不少前端开发者学习到一定阶段都会去封装一些自己的组件并将其开源。笔者在学习过程中发现,发布的资源包基本分为两类:
- 打包发布的资源包
- 非打包发布的资源包
那么这两种方式有何不同呢,他们的使用场景如何,具体的操作步骤又是怎么样的。本文将基于这两种发布方式,对比他们的不同,详解其步骤,并对在封装vue组件和发布npm依赖过程中所遇到的问题进行归纳和解答。相信对于更加全面的了解前端工程化和npm发布流程会有些许帮助。
本文将涉及到:
待封装的vue组件(组件)
需引用的第三方依赖(第三方依赖)
测试使用的Vue项目(项目)
为了后文不至混淆,将分别使用括弧中内容指代,请读者注意区分。
(一)打包发布
这种方式是将封装好的组件最终打包成一个js文件发布。这种方式使得发开和调试时更接近与一个前端项目。但是一旦引用图片等静态资源需通过BASE64方式打包到js,而对于字体一类较大的静态资源则根本无法被引用。
适用范围:没有或极少的依赖第三方插件、图片的组件的封装或JS方法的封装
1. 项目结构
使用webpack构建前端工程,此处注意webpack配置文件应当区分开发和打包。base.js、dev.js和build.js通过merge语句链接。
// 项目结构
module
|——src
| |——asset
| |——components // 组件包文件夹
| | |——index.js // 组件包打包入口
| | └——componentA.vue // 组件
| |——pages // 供开发时预览的页面
| |——router
| |——template // html模板
| |——tools
| |——app.vue // 供开发时预览的vue入口
| └——main.js // 供开发时预览的项目入口
|——webpack // webpack配置文件夹
| |——base.js // 通用配置
| |——dev.js // 开发用配置
| └——build.js // 打包用配置
|——package.json
└——README.md
2. 配置webpack
base.js
只放基础配置如module和通用的plugins,不要包含打包入口,和出口。
dev.js
- 需要配置预览相关的页面,因此入口应该为最外层main.js,这个入口文件挂在了配置了路由信息的app.vue。
- 因为开发环境是起本地服务,因此无需出口信息。
- 同时需要配置htmlWebpackPlugin和WebpackDevServer服务相关。
var webpack = require('webpack');
config.entry = {
app:[path.join(APP_SRC, 'main.js')],
vendors: [
'vue',
'vuex',
'vue-router',
'axios'
]
},
config.entry.app.unshift("webpack-dev-server/client?http://localhost:8088/")
config.plugins.push(new htmlWebpackPlugin({
hash: true,
minify: {
removeComments: true,
collapseWhitespace: true,
},
// favicon: path.join(APP_SRC, '/asset/images/ico.ico'),
template: path.join(APP_SRC, '/template/index.html'),
}))
var compiler = webpack(config);
var serve = new WebpackDevServer(compiler, {
quiet: false,
stats: {
colors: true
},
compress: true, //gzip压缩
publicPath: 'http://localhost:8088/',
contentBase: '../dist/', //默认情况下,webpack-dev-server会从项目的根目录提供文件,可以通过此选项设置文件的目录名
historyApiFallback: true, //当设置为true时,访问所有服务器上不存在的文件,都会被重定向到/,也就是index.html文件
}).listen(8088);
build.js
- 组件的入口为components目录下的index.js(index.js引入并导出我们需要封装的组件)。
- 出口信息应当包含引包时所使用的名字,组件名不能出现大写。
var config = require("./base.js");
module.exports = merge(config, {
entry: [path.join(APP_SRC, '/components/index.js')],
output: {
path: APP_DIST,
filename: 'index.js',
library: 'module_name', // 指定的就是你使用require时的模块名
libraryTarget: 'umd', // 指定输出格式
umdNamedDefine: true // 会对 UMD 的构建过程中的 AMD 模块进行命名。否则就使用匿名的 define
},
devtool: false,
mode: 'production',
});
3. 修改package.json
package.json中需要包含引包的入口,包名称和版本号。项目在引用组件时会根据main找到组件入口。
{
"name": "my_module",
"version": "1.0.0",
"main": "dist/index.js"
...
}
4. 组件开发
组件开发无需多说,只要执行npm run dev将所需封装的组件引入到预览页面中开发调试即可。
组件入口component/index.js需引入并导出组件,更加详细请看下一章节。
5. 打包发布
维护版本
手动修改package.json中的version或者执行npm version patch生成迭代一个版本
执行打包命令
npm run build
登陆npm。
注意这一需要登陆官方仓库,如果之前连接的是淘宝镜像需要线切换回来。下面是查看仓库源和切换仓库的命令。
npm config get registry // 查看仓库源
npm config set registry https://registry.npm.taobao.org
npm config set registry http://registry.npmjs.org
登陆npm,输入账号、密码、邮箱
npm login
发布
npm publish
(二)非打包发布
封装好的组件不经过打包,直接发布,用户在引用时不是引用一个独立的js文件,而是用过一个入口文件引用一些列的文件。这种方式因为不是在单独引用一个js所以可以完美解决第三方插件的引用、图片、字体等静态文件的引用但是对于组件项目本身而言开发时的预览调试方法则需要另寻他路。而且笔者暂时没有想到不适用测方法的,是笔者认为较为完美的封装发布方案。
1. 项目结构
因为无需打包,因此不再需要webpack配置,项目结构也更加精炼。可以将组件的入口已到根目录。
// 项目结构
module
|——src
| |——asset
| |——components // 组件包文件夹
| | |——componentA // 组件A
| | └——componentB.vue // 组件B
| └——tools
|——index.js // 组件入口
|——package.json
└——README.md
2. package.json
组件的名字、版本、入口文件这三个属性必备之外,需要注意的是dependencies中记录的第三方依赖都会在执行npm install的时候被安装。
{
"name": "my_module",
"version": "1.2.16",
"main": "index.js",
"dependencies": {
"view-design": "^4.0.2",
...
}
...
}
3. 入口文件(index.js)
引入组件
使用正确的相对路径将组件和静态文件引入到index.js
import './src/asset/css/index.less'
import ComponentA from './src/components/ComponentA.vue'
import ComponentB from './src/components/ComponentB.vue'
导出用于全局安装的对象
如果你想通过Vue.use(MyComponent)的方式使用组件,需要导出一个包含了所有组件的对象,并给这个对象定义install方法供Vue.use()方法调用。
let ModuleObj = {
ComponentA,
ComponentB
}
let MyModule = {}
MyModule.install = (Vue) => {
for (let i in ModuleObj) {
Vue.component(i, ModuleObj[i])
}
}
export default MyModule
导出多个组件支持按需加载
export {
ComponentA,
ComponentB
}
4. 组件开发
关于引用第三方依赖
以引用iview为例,在组件(components/ComponentA.vue)内部局部注册iview组件。这样相当于按需加载有助于减小最终项目打包的体积。
<script>
import { Poptip, Dropdown, DropdownMenu, DropdownItem, Icon, Input } from 'view-design';
export default {
components: {
Poptip, Dropdown, DropdownMenu, DropdownItem, Icon, Input
}
}
</script>
关于引用静态文件
使用正确的相对路径引用css、图片或字体,如果之前习惯使用webpack的alias路径别名,此时当然也是不生效的。
5. 发布
无需打包,但同样需要维护版本,直接发布
维护版本
手动修改package.json中的version或者执行npm version patch生成迭代一个版本
登陆发布
npm login
npm publish
6. 引用和开发调试
因为组件项目不再有供开发调试的特面,因此需要在引用组件的项目中对组件进行调试,安装组件之后,在node_module中找到组件的所在的文件夹,进入修改即可完成调试。最后将调试好的组件文件夹拷贝出来,除package.json单独维护,发布即可。
两种引用方式:
// 全局安装
import MyModule from 'my_module'
Vue.use(MyModule)
// 按需加载
import { ComponentA, ComponentB } from 'my_module'
Vue.component('ComponentA', ComponentA)
Vue.component('ComponentB', ComponentB)
电脑刺绣绣花厂 http://www.szhdn.com 广州品牌设计公司https://www.houdianzi.com
(三)总结
打包发布 | 非打包发布 | |
---|---|---|
webpack | 需要配置 | 无需配置 |
发布 | 发布前需要打包 | 发布前无需打包 |
引用静态文件 | 较小的图片可以通过BASE64方式打包仅js文件 | 随意使用 |
引用第三方依赖 | 可以引用,但如果第三方依赖包含较多的静态文件时可能会出现引用不到的情况 | 随意引用 |
被应用的文件 | 一个打包好的js | 组件的入口文件 |
调试方法 | 在组件项目中即可调试 | 需要在引用组件的项目中的node_module中对用模块中调试 |
对比两种方式,笔者更倾向于后者,但只要理解了前端项目引用依赖的原理就会发现其实两者本质上都是一样的,读者可根据自己的需要选择一种方式进行封装。文中如有错误也希望各位不吝赐教及时指出。