原文地址:https://vuejsdevelopers.com/2017/07/31/vue-component-publish-npm/
当你开发出一款NB累累的 Vue 组件,并希望其他开发者在的项目中使用它。你将怎么分享组件给他们使用呢?
在这篇伟德伟诺官网中我将告诉你如何准备你的组件,打包并发布到 NPM。我将使用一个示例项目演示以下内容:
项目案例: Vue Clock
我创建了这个简单的时钟组件,我会把它发布到 NPM 上。也许它不是你见过的最酷的组件,但它足以演示。
这是组件文件。这里没有什么特别的东西,但是请注意,我正在引入 moment
库用于格式化时间。
从你的包中排除依赖关系很重要,稍后我们会看到。
Clock.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div></div>
</template>
<script>
import moment from 'moment';
export default {
data() {
return {
time: Date.now()
}
},
computed: {
display() {
return moment(this.time).format("HH:mm:ss");
}
},
created() {
setInterval(() => {
this.time = Date.now();
}, 1000);
}
}
</script>
关键工具: Webpack
我为将组件发布到 NPM 上所做的大部分准备工作都是由 Webpack 完成的。 下面示例代码是本文中将要添加的基本 Webpack 配置。 如果您以前使用过Vue和Webpack,可以忽略没什么特别的地方:
webpack.config.js
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
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: path.resolve(__dirname + '/src/Clock.vue'),
output: {
path: path.resolve(__dirname + '/dist/'),
filename: 'vue-clock.js'
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
include: __dirname,
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.css$/,
loader: 'style!less!css'
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin( {
minimize : true,
sourceMap : false,
mangle: true,
compress: {
warnings: false
}
})
]
};
Externals
externals 配置选项可以配置,从 Webpack 打包的代码中排除某个特定的依赖。 我不希望我的组件中包含依赖关系,因为那会使打包出来的代码变得臃肿,并可能导致用户环境中的版本冲突。 用户必须自己安装依赖项。
在这个例子中,我的包依赖于 moment
库。 为了确保它不会被打包,在 WebPACK 配置中我将指定 moment 为一个 external
(外部引用):
webpack.config.js
1
2
3
4
5
6
7
module.exports = {
...
externals: {
moment: 'moment'
},
...
}
环境搭建
在Vue.js中,用户可能通过两种途经使用组件。 首先是,浏览器引入:
1
<script type="text/javascript" src="vue-clock.js"></script>
其次,基于Node.js的开发环境,例如:
1
import VueClock from 'vue-clock';
理想情况下,我希望用户能够在任意一个环境中使用 Vue Clock。 不幸的是,这些环境需要将代码以不同方式打包,这意味着我必须设置两个不同的构建配置。
为此,我将创建两个单独的Webpack配置。 这比听起来更容易,因为配置几乎相同。 首先,我将创建一个常见的配置对象,然后使用 webpack-merge
将其包含在两个环境配置中:
webpack.config.js
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
const webpack = require('webpack');
const merge = require('webpack-merge');
const path = require('path');
var commonConfig = {
output: {
path: path.resolve(__dirname + '/dist/'),
},
module: {
loaders: [ ... ]
},
externals: { ... },
plugins: [ ... ]
};
module.exports = [
// Config 1: For browser environment
merge(commonConfig, {
}),
// Config 2: For Node-based development environments
merge(commonConfig, {
})
];
常见的配置与之前完全一样(我简写了大部分内容以节省空间),除了我已经删除的 entry
和 output.filename
选项。 我将在单独的构建配置中单独配置它们。
用于浏览器环境的打包
浏览器不能像 Node 那样,可以从另一个 JavaScript 模块文件引入。但是它们可以使用像AMD这样的脚本加载器,为了最大限度地简化,我让组件脚本作为一个全局变量,这样可以更简单地添加。
另外,我不希望用户必须想很多才能弄清楚如何使用组件。我会这样做的,当用户引入脚本时,组件可以很容易地注册为全局组件。Vue的插件系统将有助于实现这个功能。
我的目标是这个简单的设置:
index.html
1
2
3
4
5
6
7
8
9
<body>
<div id="app">
<vue-clock></vue-clock>
</div>
<script type="text/javascript" src="vue-clock.js"></script>
<script type="text/javascript">
Vue.use(VueClock);
</script>
</body>
Plugin
首先,我将创建一个插件包装器,以方便安装组件:
plugin.js
1
2
3
4
5
6
7
import Clock from './Clock.vue';
module.exports = {
install: function (Vue, options) {
Vue.component('vue-clock', Clock);
}
};
该插件全局注册组件,因此用户可以在其应用程序的任何位置调用 clock 组件。
webpack配置
现在,我使用plugin.js
路径作为浏览器构建的入口点。我会输出一个名为 vue-clock.min.js
的文件,这对用户来说是最明显的。
1
2
3
4
5
6
7
8
9
module.exports = [
merge(config, {
entry: path.resolve(__dirname + '/src/plugin.js'),
output: {
filename: 'vue-clock.min.js',
}
}),
...
];
以库的形式导出
Webpack 可以以各种不同的方式导出你的脚本,例如:作为一个对象,作为一个全局变量,遵循AMD或CommonJS规范的模块。您可以使用 libraryTarget
选项指定。
对于浏览器打包方式,我将使用 window
导出方式。 我也可以使用 UMD
来获得更多的灵活性,但是由于我已经创建了两个打包方式,所以我只是将这个打包方式限制在浏览器中。
我还将库名称指定为 VueClock
。 这意味着当浏览器引入包时,它将挂载在全局上 window.VueClock
。
1
2
3
4
5
output: {
filename: 'vue-clock.min.js',
libraryTarget: 'window',
library: 'VueClock'
}
Node 环境打包
为了允许用户在 Node 开发环境中使用组件,我将使用 UMD 方式打包输出提供给 Node 环境使用。 UMD是一种灵活的模块类型,可以在各种不同的脚本加载器和环境中使用代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module.exports = [
...
merge(config, {
entry: path.resolve(__dirname + '/src/Clock.vue'),
output: {
filename: 'vue-clock.js',
libraryTarget: 'umd',
// These options are useful if the user wants to load the module with AMD
library: 'vue-clock',
umdNamedDefine: true
}
})
];
注意,在Node 环境中使用单个文件组件作为入口,不需要使用插件包装器。这样可以更灵活的引入:
1
2
3
4
5
6
7
import VueClock from 'vue-clock';
new Vue({
components: {
VueClock
}
});
package.json
在发布到NPM之前,我将设置我的 package.json 文件。 有关每个选项的详细说明,请访问 npmjs.com。
package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"name": "vue-clock-simple",
"version": "1.0.0",
"description": "A Vue.js component that displays a clock.",
"main": "dist/vue-clock.js",
"scripts": {
"build": "rimraf ./dist && webpack --config ./webpack.config.js"
},
"author": "Anthony Gore",
"license": "MIT",
"dependencies": {
"moment": "^2.18.1"
},
"repository": { ... },
"devDependencies": { ... }
}
我省略了这个文件的大部分,但重点要注意的是:
- 主脚本文件即
"main": "dist/vue-clock.js"
。 这指向 Node bundle 文件,确保模块加载器知道文件的准确路径,即
1
import VueClock from 'vue-clock' // this resolves to dist/vue-clock.js
- 依赖关系,由于我从包中排除了所有依赖关系,用户必须自行安装依赖才能使用该包。
发布到 NPM
现在我的组件设置正确,可以在NPM上发布。 我不会重复的在这里说明,因为它们在npmjs.com上很好地介绍。
结果如下:
https://github.com/anthonygore/vue-clock-simple/blob/master/webpack.config.js
https://vuejsdevelopers.com/2017/07/31/vue-component-publish-npm/