本文最后更新于:2020年12月25日 上午
吾辈已经写了一个 TypeScript/JavaScript Cli 工具 liuli-cli,如有需要可以使用这个 Cli 直接生成一个开箱即用 SDK 项目,然后就可以直接开始写自己的代码,不需要太过关心下面的内容了 – 因为,它们都已然集成了。
场景
为什么要使用打包工具
如果我们想要写一个 JavaScript SDK
,那么就不太可能将所有的代码都写到同一个 js 文件中。当然了,想做的话的确可以做到,但随着 JavaScript SDK
内容的增加,一个 js 文件容易造成开发冲突,以及测试上的困难,这也是现代前端基本上都依赖于打包工具的原因。
为什么打包工具是 rollup
现今最流行的打包工具是 webpack,然而事实上对于单纯的打包 JavaScript SDK 而言 webpack 显得有些太重了。webpack 终究是用来整合多种类型的资源而产生的(ReactJS/VueJS/Babel/TypeScript/Stylus
),对于纯 JavaScript 库而言其实并没有必要使用如此 强大 的工具。而 rollup 就显得小巧精致,少许配置就能立刻打包了。
步骤
该记录的代码被吾辈放到了 GitHub,有需要的话可以看下。
前置要求
开始之前,我们必须要对以下内容有所了解
需要打包的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
function wait(param) { return new Promise((resolve) => { if (typeof param === 'number') { setTimeout(resolve, param) } else if (typeof param === 'function') { var timer = setInterval(() => { if (param()) { clearInterval(timer) resolve() } }, 100) } else { resolve() } }) }
export default wait
function fetchTimeout(fetchPromise, timeout) { var abortFn = null var abortPromise = new Promise(function (resolve, reject) { abortFn = function () { reject('abort promise') } }) var abortablePromise = Promise.race([fetchPromise, abortPromise]) setTimeout(function () { abortFn() }, timeout) return abortablePromise }
export default fetchTimeout
import wait from './wait' import fetchTimeout from './fetchTimeout'
class FetchLimiting { constructor({ timeout = 10000, limit = 10 }) { this.timeout = timeout this.limit = limit this.execCount = 0 this.waitArr = [] }
async _fetch(url, init) { const _innerFetch = async () => { console.log( `执行 execCount: ${this.execCount}, waitArr length: ${ this.waitArr.length }, index: ${JSON.stringify(this.waitArr[0])}`, ) this.execCount++ const args = this.waitArr.shift(0) try { return await fetchTimeout(fetch(...args), this.timeout) } finally { this.execCount-- } } this.waitArr.push(arguments) await wait(() => this.execCount < this.limit) return _innerFetch() } }
export default FetchLimiting
|
使用 rollup 直接打包
安装 rollup
在根目录创建一个 rollup.config.js
配置文件
1 2 3 4 5 6 7 8 9 10 11 12
| export default { input: 'src/main.js', output: { name: 'bundlea', file: 'dist/bundle.js', format: 'umd', }, }
|
添加一个 npm script
1 2 3
| "scripts": { "build": "rollup -c" }
|
然后运行 npm run build
测试打包,可以看到 dist 目录下已经有 bundle.js
文件了
好了,到此为止我们已经简单使用 rollup 打包 js 了,下面的内容都是可选项,如果需要可以分节选读。
使用 babel 转换 ES5
然而,我们虽然已经将 main.js 打包了,然而实际上我们的代码没有发生什么变化。即:原本是 ES6 的代码仍然会是 ES6,而如果我们想要尽可能地支持更多的浏览器,目前而言还是需要兼容到 ES5 才行。
所以,我们需要 babel
,它能够帮我们把 ES6 的代码编译成 ES5。
附:babel 被称为现代前端的 jquery。
首先,安装 babel 需要的包
1
| npm i -D rollup-plugin-babel @babel/core @babel/plugin-external-helpers @babel/preset-env
|
在 rollup.config.js
中添加 plugins
1 2 3 4 5 6 7 8 9 10
| import babel from 'rollup-plugin-babel'
export default { plugins: [ babel({ exclude: 'node_modules/**', }), ], }
|
添加 babel 的配置文件 .babelrc
1 2 3 4 5 6 7 8 9 10 11
| { "presets": [ [ "@babel/preset-env", { "modules": false } ] ], "plugins": ["@babel/plugin-external-helpers"] }
|
再重新运行 npm run build
,可以看到 bundle.js
中的代码已经被编译成 ES5 了。
使用 uglify 压缩生产环境代码
那么,生产中的代码还需要做什么呢?是的,压缩,减小 js 代码的体积是必要的。接下来,我们还需要使用 uglify
压缩我们打包后的 bundle.js
代码。
首先仍然是安装 uglify
相关的包
1
| npm i -D rollup-plugin-uglify
|
然后在 rollup.config.js
中引入插件就好了
1 2 3 4 5 6 7 8 9
| import { uglify } from 'rollup-plugin-uglify'
export default { plugins: [ uglify(), ], }
|
使用 ESLint 检查代码
如果我们想要需要多人协作统一代码风格,那么可以使用 ESLint 来强制规范。
首先,全局安装 eslint
然后使用 eslint cli
初始化
下面的三项问题选择
- How would you like to configure ESLint? (Use arrow keys)
Use a popular style guide
- Which style guide do you want to follow? (Use arrow keys)
Standard (https://github.com/standard/standard)
- What format do you want your config file to be in? (Use arrow keys)
JavaScript
- Would you like to install them now with npm?
y
然后,我们发现项目根目录下多出了 .eslintrc.js
,这是 eslit 的配置文件。然而,我们需要对其稍微修改一下,不然如果我们的代码中出现了浏览器中的对象,例如 document
,eslint 就会傻傻的认为那是个错误!
修改后的 .eslintrc.js
配置
1 2 3 4 5 6 7
| module.exports = { extends: 'standard', env: { browser: true, }, }
|
当我们查看打包后的 bundle.js
时发现 eslint 给我们报了一堆错误,所以我们需要排除掉 dist 文件夹
添加 .eslintignore
文件
添加 rollup-plugin-eslint
插件,在打包之前进行格式校验
1
| npm i -D rollup-plugin-eslint
|
然后引入它
1 2 3 4 5 6 7 8
| import { eslint } from 'rollup-plugin-eslint'
export default { plugins: [ eslint(), ], }
|
这个时候,当你运行 npm run build
的时候,eslint 可能提示你一堆代码格式错误,难道我们还要一个个的去修复么?不,eslint 早已考虑到了这一点,我们可以添加一个 npm 脚本用于全局修复格式错误。
1 2 3
| "scripts": { "lint": "eslint --fix src" }
|
然后运行 npm run lint
,eslint 会尽可能修复格式错误,如果不能修复,会在控制台打印异常文件的路径,然后我们手动修复就好啦
其他 rollup 配置
添加代码映射文件
其实很简单,只要在 rollup.config.js
启用一个配置就好了
1 2 3 4 5 6
| export default { output: { sourcemap: true, }, }
|
多环境打包
首先移除掉根目录下的 rollup.config.js
配置文件,然后创建 build 目录并添加下面四个文件
1 2 3 4 5 6 7 8 9 10 11 12
| import path from 'path'
export function calcPath(relaPath) { return path.resolve(__dirname, relaPath) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import { eslint } from 'rollup-plugin-eslint' import { calcPath } from './util' import { name } from '../package.json'
export default { input: calcPath('../src/main.js'), output: { name, file: calcPath(`../dist/${name}.js`), format: 'umd', sourcemap: true, }, plugins: [ eslint(), ], }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import babel from 'rollup-plugin-babel'
import { uglify } from 'rollup-plugin-uglify' import { eslint } from 'rollup-plugin-eslint' import { calcPath } from './util' import dev from './rollup.config.dev' import { name } from '../package.json'
export default [ dev, { input: calcPath('../src/main.js'), output: { name, file: calcPath(`../dist/${name}.min.js`), format: 'umd', }, plugins: [ eslint(), babel({ exclude: calcPath('../node_modules/**'), }), uglify(), ], }, ]
|
1 2 3 4 5 6
| import dev from './rollup.config.dev' import prod from './rollup.config.prod'
export default process.env.NODE_ENV === 'production' ? prod : dev
|
修改 npm 脚本
1 2 3 4 5
| "scripts": { "build:dev": "rollup -c build/rollup.config.js --environment NODE_ENV:development", "build:prod": "rollup -c build/rollup.config.js --environment NODE_ENV:production", "build": "npm run build:dev && npm run build:prod", }
|
那么,关于使用 rollup 打包 JavaScript 的内容就先到这里了,有需要的话后续吾辈还会继续更新的!