前言
文章用来纪录我如何从零开始,通过 webpack4 发布一个 vue 的 npm 包,同时使用的是 es6 语法。涉及到的知识点包括:
- webpack4
- npm 包的发布
- babel 配置
- vue 配置
准备工作
了解相关知识
首先需要了解相关基础知识,由简单到难,依次列举如下:
- 如何发布一个 npm 包,需要准备些什么?
- webpack 简单的打包配置需要哪些
- 如何配置 babel 的 es6 支持
- 如何配置 vue 的支持
- 如何配置 vue 的 @、@src 等引用
- 包内的 vue 的组件该如何编写
- 如何优化打包的体积
发包前的准备
创建账号
发布 npm 包首先需要一个 npm 账号。npm 添加账号的方法:
1 | npm adduser |
创建待发布的包
创建包的方法也十分简单,此处用 yarn 来创建一个 npm 包
1 | # 首先进入对应文件夹,然后 |
规范化 package.json
内容
当然,要发布一个比较规范的包,仅默认的一些配置还是不够的,package.json
的详细配置可见「中文文档」,总结过后,我们可以配置这么一些字段:
name
: 项目名称version
: 当前包的版本keywords
: 关键词,方便搜索description
: 项目描述repository
: 项目地址author
: 作者contributors
: 项目开发人员files
: 项目包括的文件scripts
: webpack 打包会用到style
: 项目样式所存放的地址license
: 许可证(一般 MIT 即可)
安装时常用的有此三种依赖:
- dependencies: 必须依赖的包,会在用户安装此包时,将该部分的包一并装上,会更新版本(如果版本过低)
- peerDependencies: 会在用户安装此包时,如果该模块内的包没有或者用户安装的对应包版本过低,会用 warning 提示用户安装(不会自动安装)
- devDependencies: 开发时会用到的包,打包至项目的或者 webpack 配置需要的等等,不会帮用户安装或者给予提示
它们依次对应的指令是:
1 | # dependencies |
初始化包的配置
两种安装方式
1 | # 全局安装 |
在先前创建的项目内新建一个 webpack.config.js
文件,并写入以下基础内容
1 | const path = require('path'); |
注:webpack4 版本这两个是分开的,都得装
配置 webpack
出入口文件配置
1 | // 在 module.exports 文件内添加 entry 和 output 两字段 |
1 | // 例子 |
loader 配置
vue-loader
由于项目是关于 vue 的,因此可参考「vue-loader 官网」,跟着对应内容配置即可,解析 vue 的 loader 配置
1 | // rules 部分 |
es6 支持
首先在 webpack
配置文件的 rules
部分(vue-loader
配置的部分)添加 js
的语法转译
1 | // ... |
然后在项目内添加 .babelrc
文件,并在内部添加 es
支持
1 | { |
此处使用的是最新版本的 babel 配置,官网有详细的讲解
需要安装的一些依赖:
1 | // devDependencies 部分 |
注意: babel-core 默认安装的是 6.x 版本,装 7 版本的命令是:
yarn add babel-core@^7.0.0-bridge.0 -D
css 样式支持
由于 vue 项目中用的较多的是 less 或者是 sass,因此打包时需要对样式进行转译,此时需要样式相关的 loader。webpack 的配置例子如下:
1 | // rules 部分 |
这里注意到最顶部配置的不是 style-loader/vue-style-loader
,当我们使用的是开发环境即:"mode": "development"
时,使用 style-loader/vue-style-loader
,当使用生产环境即:"mode": "production"
时,我们使用此处的配置,以达到最小化压缩
其余资源支持
参考官方文档总结的配置如下:
1 | { |
url-loader 转为 base64 格式,对于小文件类型用这种方法处理更优,但是大文件最好还是用 file-loader 处理,因此对此 loader 设定一个限制,大于阈值 8K 的自动用 file-loader 处理
optimization 配置
此部分是最后对文件进行压缩优化一下体积,webpack4 中生产环节相对较好的 devtool
模式是 cheap-module-source-map
,但是压缩出的文件内会包含 source-map
,如果想将其去掉需要额外的一些配置。webpack 配置例子:
1 | optimization: { |
此处使用的是 UglifyJsPlugin 压缩 js 代码,删除 map 部分的内容, OptimizeCssAssetsPlugin 则是压缩 CSS 部分的内容,具体配置可参考对应的 npm 插件文档
注:css 部分有推荐配合使用
cssnano
,因为本项目 css 内容就 2 属性,因此不做过多的配置了,有需要的可查阅相关知识配置即可
附带的配置
- clean-webpack-plugin: 放在 plugins 的最后面,可每次自动清除对应的生成文件
- webpack-bundle-analyzer: 对压缩的文件的依赖树的可视化分析,方便分析是否有多余依赖
vue 的配置
发布一个 vue 组件时需要为组件添加 install 方法,每个组件的文件目录树大致为
1 | fileName |
这是一个组件的文件结构,其中的 component
就是我们的 vue 组件,index.js
为向外侧暴露该组件的一个入口文件,其内容基本格式一致,例如:
1 | import myComponent from './src/component'; |
整体的配置可以参考 elementUI 的组件写法,原理一样,本质是如何添加 install 方法
开发时的一些疑问
关于 devtool
的选用
开发环境推荐: cheap-module-eval-source-map
生产环境推荐:cheap-module-source-map
理由:
- 大部分情况我们调试并不关心列信息,而且就算 sourcemap 没有列,有些浏览器引擎(例如 v8) 也会给出列信息,所以我们使用 cheap 模式可以大幅提高 souremap 生成的效率
- 使用 module 可支持 babel 这种预编译工具(在 webpack 里做为 loader 使用)
- 使用 eval 方式可大幅提高持续构建效率,参考 webapck devtool 速度对比列表,这对经常需要边改边调的前端开发而言非常重要
- 直接将 sourceMap 放入打包后的文件,会明显增大文件的大小,不利于静态文件的快速加载;而外联 .map 时,.map 文件只会在 F12 开启时进行下载( sourceMap 主要服务于调试),故推荐使用外联 .map 的形式
升级 babel 的问题
依照官方文档的介绍,安装了 @babel/core
等插件,并更新了 .babelrc
的配置,但是 build 的时候报错表示 babel-core 版本过低(直接 yarn add babel-core
装的是 6.x 版本),需要 7.0.0.0 版本,因此需要更新 babel-core
1 | yarn add babel-core@^7.0.0-bridge.0 -D |
本地调试包
一般通过 yarn link
来调试编写的包,但是除此之外还有另外一个方法,通过相对路径来安装对应的包
1 | "target-file": "file:<relative-path>" |
但是缺点是,每次更新后都需要删除后重新安装此包,或者将包升级一下版本,然后再次安装才能调试,比较麻烦。
最好的配置方法还是通过 yarn link
来调试。
按需引入比解构引入打包的体积要大?
分析了一下打包后的代码,就用以下的例子来解释
1 | // 按需 |
通过 webpack-bundle-analyzer 分析打包后的内容,发现前者有 lodash 的模块,后者没有,后者没有的原因时在压缩的代码内有 require('lodash')
即,我们需要配置 package.json
的 lodash
的 dependencies
依赖,需要引用此包的项目有对 lodash
的依赖,也就是说,解构获取的 debouce
不会将对应的内容连同代码一起打包,而是需要用户安装对应的包的依赖,因此体积相对会变小。
为什么要用 library?
使用 umd 是为了兼容 commonjs 和 amd 的方式,一般发包用 umd 可保证不会出啥问题,兼容性也很棒,而使用 umd 则需要配置 library。
path 和 publicPath
一般我们配置好 path 其实就能万事大吉了,那 publicPath 究竟有什么用呢?其实简单理解, path 至当前的项目的根目录(本地),publicPath 指的是服务器的根目录(服务器),比如:将资源放在 CDN 上时,把 publicPath 设置为 CDN 的值就行了。
参考文档
- webpack devtool 配置对比
- webpack 文档
- webpack 配置详情文档
- webpack externals 详解
- webpack 配置 publicPath 的理解
- babel 文档
- babel-bridge
- vue-loader