说在前面
最近一直在忙自己的毕业设计,在做的过程中,有的地方要用到缓存.我采用了 localStorage 和 sessionStorage 的方式进行的缓存,并完整地实现了自己想要的功能.但是我突然想到前端的" 模块化开发",这块完全可以独立出来,将其封装为一个统一的 API,想要使用的时候就引入使用,于是我将其封装为了一个将 localStorage 和 sessionStorage 统一在一起的功能函数:xieyezi-storage.js
.我存放在自己的电脑里面,以便我自己以后使用,但是我突然想到了程序员的"开源精神"😹,好吧其实是想到,每次我们需要安装一个包的时候,我们都是采用npm install xxx
的方式进行引入,然后在使用的时候,就通过import xxx from xxx
这样的方式进行使用.于是我也想要将我的功能函数封装为一个 npm 包,并且发布到npm👆 上面去,那也算是为我们开源作出了一定的贡献.
说得简单,动手困难
世界上很多事情都是说起来容易,做起来比较难,并且,万事开头难.我发现我自己缺乏这方面的很多知识,于是我开始了边学边写的模式. 在前期的考察中,我看了许多的 npm 包的源码,他们都有差不多类似的目录结构,于是我依葫芦画瓢,构建了如下的目录结构:
.
├── ./dist
└── ./src
└── ./src/index.js
我执行了一下 npm 的初始化工程命令:
npm init -y
目录变成了这样:
.
├── ./dist
├── ./package.json
└── ./src
└── ./src/index.js
原来初始化包都会有一个 package.json,这个文件包含了这个包 的入口及其信息 在 src 目录下面存放功能代码index.js
,dist 目录下面则存放打包后的文件xieyezi-storage.js
一切都已经准备就绪,我开始寻找一个打包工具.
webpack
在众多的打包工具中,我第一个想到的打包工具就是 webpack,于是先安装(在根目录):
npm i webpack webpack-cli --save-dev
然后靠着自己对 webpack 的浅薄知识,含泪写下了配置文件(webpack.config.js):
const path = require("path")
module.exports = {
entry: "./src/index.js",
output: {
filename: "xieyezi-storage.js",
publicPath: "/dist/",
path: path.resolve(__dirname, "dist")
}
}
于是打包之后,生成了xieyezi-storage.js
的文件,于是我将此文件复制到我的项目目录里面进行引入使用:
import storage from "common/js/xieyezi-storage"
结果是我成功地引入了文件并进行了使用.但是我这是 ES6 规范,并不能支持 commonJS 模式,说到这个,有如下标准:
- amd – 异步模块定义,用于像 RequireJS 这样的模块加载器
- cjs – CommonJS,适用于 Node 和 Browserify/Webpack 例如
require('xieyezi-storage')
- es – 将软件包保存为 ES 模块文件 例如
import storage from 'xieyezi-storage'
. - iife – 一个自动执行的功能,适合作为
<script>
标签.(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小.) - umd – 通用模块定义,以 amd,cjs 和 iife 为一体,umd 是 amd 和 CommonJS 的糅合,umd 先判断是否支持 Node.js 的模块(exports)是否存在,存在则使用 Node.js 模块模式.
所以我打包的文件无法通过 commonJS 方式来引入.
libraryTarget
libraryTarget 就是问题的关键,通过设置该属性,这是可以控制 library 如何以不同方式暴露的选项.
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'xieyezi-storage.js',
publicPath: '/dist/',
libraryTarget: 'umd'
path: path.resolve(__dirname, 'dist')
}
};
这样子,我们打包的文件就会支持各种规范了.这样子我以为就算完了,但是事实并非如此.我看了一下,打包之后的文件大小居然有 2k.这么大??
rollup
在前面的考察中,我在选择打包工具的时候,我看见了 Vue 框架和 React 用的是什么打包工具,结果我发现,居然他们两都不是用的 webpack,而是用的是一个叫做 rollup
的东西.于是我去查阅了 rollup 的官网:
Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序.Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6 版本中,而不是以前的特殊解决方案,如 CommonJS 和 AMD.ES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数,而你的项目不必携带其他未使用的代码.
所以说,rollup 就是专门用来打包 library 的,而 webpack 大多是用来打包应用程序的.
于是我愉快的开始了 rollup 的学习使用: 先安装:
npm install --global rollup
在项目根目录新建一个 rollup.config.js:
export default {
input: "./src/index.js",
output: {
file: "./dist/xieyezi-storage.js",
format: "umd",
name: "xieyezi-storage"
}
}
然后就是执行 rollup c
,成功打包.而且经过我的测试,能正常引入使用.我一看,才 1k😂,开心的笑了. 然后我就打算用我们的uglify
进行代码压缩:
npm i rollup-plugin-uglify -D
在 rollup.config.js 配置引入:
import { uglify } from "rollup-plugin-uglify"
export default {
input: "./src/index.js",
output: {
file: "./dist/xieyezi-storage.js",
format: "umd",
name: "xieyezi-storage"
},
plugins: [uglify()]
}
然后重新运行 rollup c
进行打包,结果直接报错
我上去就是一顿谷歌加百度,原来 uglify 插件只支持 es5 的压缩.看来我只能另寻出路.我看见了 terser
这个插件,这个插件也能对代码进行压缩,支持 es6.
npm i rollup-plugin-terser -D
在 rollup.config.js 配置引入:
import { terser } from "rollup-plugin-terser"
export default {
input: "./src/index.js",
output: {
file: "./dist/xieyezi-storage.js",
format: "umd",
name: "xieyezi-storage"
},
plugins: [terser()]
}
再次进行打包,成功打包!!!可是我们打包之后对代码只支持 es6,我们还需要用 babel
进行转义:
//package.json
"devDependencies": {
"babel-core": "^6.9.1",
"babel-loader": "^6.2.4",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-es2015-modules-umd": "^6.12.0",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-polyfill": "^6.22.0",
"babel-preset-env": "^1.5.1",
"babel-preset-es2015": "^6.9.0",
"babel-preset-stage-2": "^6.5.0",
"rollup-plugin-babel": "^3.0.7",
"rollup-plugin-terser": "^4.0.4"
}
再进行npm install
这里要注意,要使用 babel,在 rollup 里面,必须安装完它所需对依赖,不能只安装 rollup-plugin-babel
.必须安装完所有 babel 所需依赖.
完整的 rollup.config.js:
import { terser } from "rollup-plugin-terser"
import babel from "rollup-plugin-babel"
export default {
input: "./src/index.js",
output: {
file: "./dist/xieyezi-storage.js",
format: "umd",
name: "xieyezi-storage"
},
plugins: [
babel({
exclude: "node_modules/**"
}),
terser()
]
}
在项目根目录新建.babelrc:
{
"presets": [
[
"env",
{
"modules": false
}
]
],
"plugins": [
"transform-object-assign"
]
}
执行打包,打包成功 完整的 package.json:
{
"name": "xieyezi-storage",
"version": "1.0.4",
"description": "a package that encapsulates localStorage and sessionStorage",
"main": "dist/xieyezi-storage.js",
"module": "dist/xieyezi-storage.esm.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["web", "localStorage", "sessionStorage"],
"author": "xieyezi",
"license": "ISC",
"git": {
"url": "https://github.com/xieyezi/webStorage"
},
"devDependencies": {
"babel-core": "^6.9.1",
"babel-loader": "^6.2.4",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-es2015-modules-umd": "^6.12.0",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-polyfill": "^6.22.0",
"babel-preset-env": "^1.5.1",
"babel-preset-es2015": "^6.9.0",
"babel-preset-stage-2": "^6.5.0",
"rollup-plugin-babel": "^3.0.7",
"rollup-plugin-terser": "^4.0.4"
}
}
最后的项目结构如下:
.
├── ./README.md
├── ./dist
│ ├── ./dist/xieyezi-storage.esm.js
│ └── ./dist/xieyezi-storage.js
├── ./package-lock.json
├── ./package.json
├── ./rollup.config.js
├── ./babelrc
└── ./src
└── ./src/index.js
我按照 es
和 umd
打包了两次.
将包上传至 npm
先去 npm 注册一个账号,然后进入到根目录进行登录:
$ npm login
Username: xieyezi
Password:
Email: (this IS public) 1435398529@qq.com
Logged in as xieyezi on https://registry.npmjs.org/.
注:输入密码的时候不会显示,只要最后显示 Logged in as your nickName 即可. 然后输入:
npm publish
它会提示你成功发布,并会给你发邮件. 进入到 npm 官网进行搜索我们发布的包,如果成功搜索到,则发布成功:
好了,接下来,进入到我自己的毕业设计的根目录:
npm install xieyzi-storage
在 node_moudules 里面查找 xieyezi-storage
: 成功找到,引入项目,成功地进行了引入 ✌️
总结
完成上面的这些工作,我花了前前后后差不多 5 天的时间,前期主要是在学习,后面才开始动手做.做的过程中遇到了很多 error
和 bug
,但是都是慢慢的解决了困难.我觉得最大的收获就是:很多时候,不是我们不会,只是我们不愿意主动去做而已.所以朋友吧,遇到自己不会的东西,撸起袖子就是干吧!!