吾辈的博客原文地址: https://blog.rxliuli.com/p/c3...
吾辈已经写了一个 TypeScript/JavaScript Cli 工具 liuli-cli,若有须要可使用这个 Cli 直接生成一个开箱即用 SDK 项目,而后就能够直接开始写本身的代码,不须要太过关心下面的内容了 -- 由于,它们都已然集成了。
若是咱们想要写一个 JavaScript SDK
,那么就不太可能将全部的代码都写到同一个 js 文件中。固然了,想作的话的确能够作到,但随着 JavaScript SDK
内容的增长,一个 js 文件容易形成开发冲突,以及测试上的困难,这也是现代前端基本上都依赖于打包工具的缘由。前端
现今最流行的打包工具是 webpack,然而事实上对于单纯的打包 JavaScript SDK 而言 webpack 显得有些过重了。webpack 终究是用来整合多种类型的资源而产生的(ReactJS/VueJS/Babel/TypeScript/Stylus
),对于纯 JavaScript 库而言其实并无必要使用如此 强大 的工具。而 rollup 就显得小巧精致,少量配置就能马上打包了。node
该记录的代码被吾辈放到了 GitHub,有须要的话能够看下。
开始以前,咱们必需要对如下内容有所了解jquery
// src/wait.js /** * 等待指定的时间/等待指定表达式成立 * @param {Number|Function} param 等待时间/等待条件 * @returns {Promise} Promise 对象 */ 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 // src/fetchTimeout.js /** * 为 fetch 请求添加超时选项 * 注:超时选项并不是真正意义上的超时即取消请求,请求依旧正常执行完成,但会提早返回 reject 结果 * @param {Promise} fetchPromise fetch 请求的 Promise * @param {Number} timeout 超时时间 * @returns {Promise} 若是超时就提早返回 reject, 不然正常返回 fetch 结果 */ function fetchTimeout(fetchPromise, timeout) { var abortFn = null //这是一个能够被 reject 的 Promise var abortPromise = new Promise(function(resolve, reject) { abortFn = function() { reject('abort promise') } }) // 有一个 Promise 完成就马上结束 var abortablePromise = Promise.race([fetchPromise, abortPromise]) setTimeout(function() { abortFn() }, timeout) return abortablePromise } export default fetchTimeout // src/main.js import wait from './wait' import fetchTimeout from './fetchTimeout' /** * 限制并发请求数量的 fetch 封装 */ class FetchLimiting { constructor({ timeout = 10000, limit = 10 }) { this.timeout = timeout this.limit = limit this.execCount = 0 // 等待队列 this.waitArr = [] } /** * 执行一个请求 * 若是到达最大并发限制时就进行等待 * 注:该方法的请求顺序是无序的,与代码里的顺序无关 * @param {RequestInfo} url 请求 url 信息 * @param {RequestInit} init 请求的其余可选项 * @returns {Promise} 若是超时就提早返回 reject, 不然正常返回 fetch 结果 */ 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
webpack
npm i rollup -D
在根目录建立一个 rollup.config.js
配置文件git
export default { // 入口文件 input: 'src/main.js', output: { // 打包名称 name: 'bundlea', // 打包的文件 file: 'dist/bundle.js', // 打包的格式,umd 支持 commonjs/amd/life 三种方式 format: 'umd', }, }
添加一个 npm script
github
"scripts": { "build": "rollup -c" }
而后运行 npm run build
测试打包,能够看到 dist 目录下已经有 bundle.js
文件了web
好了,到此为止咱们已经简单使用 rollup 打包 js 了,下面的内容都是可选项,若是须要能够分节选读。
然而,咱们虽然已经将 main.js 打包了,然而实际上咱们的代码没有发生什么变化。即:本来是 ES6 的代码仍然会是 ES6,而若是咱们想要尽量地支持更多的浏览器,目前而言仍是须要兼容到 ES5 才行。npm
因此,咱们须要 babel
,它可以帮咱们把 ES6 的代码编译成 ES5。json
附:babel 被称为现代前端的 jquery。
首先,安装 babel 须要的包promise
npm i -D rollup-plugin-babel @babel/core @babel/plugin-external-helpers @babel/preset-env
在 rollup.config.js
中添加 plugins
import babel from 'rollup-plugin-babel' export default { plugins: [ // 引入 babel 插件 babel({ exclude: 'node_modules/**', }), ], }
添加 babel 的配置文件 .babelrc
{ "presets": [ [ "@babel/preset-env", { "modules": false } ] ], "plugins": ["@babel/plugin-external-helpers"] }
再从新运行 npm run build
,能够看到 bundle.js
中的代码已经被编译成 ES5 了。
那么,生产中的代码还须要作什么呢?是的,压缩,减少 js 代码的体积是必要的。接下来,咱们还须要使用 uglify
压缩咱们打包后的 bundle.js
代码。
首先仍然是安装 uglify
相关的包
npm i -D rollup-plugin-uglify
而后在 rollup.config.js
中引入插件就行了
// 注意,这里引入须要使用 { uglify } 而非 uglify,由于 uglify 导出自身时使用的是 exports.uglify import { uglify } from 'rollup-plugin-uglify' export default { plugins: [ // js 压缩插件,须要在最后引入 uglify(), ], }
若是咱们想要须要多人协做统一代码风格,那么可使用 ESLint 来强制规范。
首先,全局安装 eslint
npm i eslint -g
而后使用 eslint cli
初始化
eslint --init
下面的三项问题选择
Use a popular style guide
Standard (https://github.com/standard/standard)
JavaScript
y
而后,咱们发现项目根目录下多出了 .eslintrc.js
,这是 eslit 的配置文件。然而,咱们须要对其稍微修改一下,否则若是咱们的代码中出现了浏览器中的对象,例如 document
,eslint 就会傻傻的认为那是个错误!
修改后的 .eslintrc.js
配置
module.exports = { extends: 'standard', // 添加了运行环境设定,设置 browser 为 true env: { browser: true, }, }
当咱们查看打包后的 bundle.js
时发现 eslint 给咱们报了一堆错误,因此咱们须要排除掉 dist 文件夹
添加 .eslintignore
文件
dist
添加 rollup-plugin-eslint
插件,在打包以前进行格式校验
npm i -D rollup-plugin-eslint
而后引入它
import { eslint } from 'rollup-plugin-eslint' export default { plugins: [ // 引入 eslint 插件 eslint(), ], }
这个时候,当你运行 npm run build
的时候,eslint 可能提示你一堆代码格式错误,难道咱们还要一个个的去修复么?不,eslint 早已考虑到了这一点,咱们能够添加一个 npm 脚本用于全局修复格式错误。
"scripts": { "lint": "eslint --fix src" }
而后运行 npm run lint
,eslint 会尽量修复格式错误,若是不能修复,会在控制台打印异常文件的路径,而后咱们手动修复就好啦
其实很简单,只要在 rollup.config.js
启用一个配置就行了
export default { output: { // 启用代码映射,便于调试之用 sourcemap: true, }, }
首先移除掉根目录下的 rollup.config.js
配置文件,而后建立 build 目录并添加下面四个文件
// build/util.js import path from 'path' /** * 根据相对路径计算真是的路径 * 从当前类的文件夹开始计算,这里是 /build * @param {String} relaPath 相对路径 * @returns {String} 绝对路径 */ export function calcPath(relaPath) { return path.resolve(__dirname, relaPath) }
// build/rollup.config.dev.js 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`), // 打包的格式,umd 支持 commonjs/amd/life 三种方式 format: 'umd', // 启用代码映射,便于调试之用 sourcemap: true, }, plugins: [ // 引入 eslint 插件,必须在 babel 以前引入,由于 babel 编译以后的代码未必符合 eslint 规范,eslint 仅针对咱们 [本来] 的代码 eslint(), ], }
// build/rollup.config.prod.js import babel from 'rollup-plugin-babel' // 注意,这里引入须要使用 { uglify } 而非 uglify,由于 uglify 导出自身时使用的是 exports.uglify 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`), // 打包的格式,umd 支持 commonjs/amd/life 三种方式 format: 'umd', }, plugins: [ // 引入 eslint 插件,必须在 babel 以前引入,由于 babel 编译以后的代码未必符合 eslint 规范,eslint 仅针对咱们 [本来] 的代码 eslint(), // 引入 babel 插件 babel({ exclude: calcPath('../node_modules/**'), }), // js 压缩插件,须要在最后引入 uglify(), ], }, ]
// build/rollup.config.js import dev from './rollup.config.dev' import prod from './rollup.config.prod' // 若是当前环境时 production,则使用 prod 配置,不然使用 dev 配置 export default process.env.NODE_ENV === 'production' ? prod : dev
修改 npm 脚本
"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 的内容就先到这里了,有须要的话后续吾辈还会继续更新的!