首页
技术分享
实用工具 发布文章 新浪微博 Github

原文地址:https://vuejsdevelopers.com/2017/07/31/vue-component-publish-npm/

当你开发出一款NB累累的 Vue 组件,并希望其他开发者在的项目中使用它。你将怎么分享组件给他们使用呢?

在这篇文章中我将告诉你如何准备你的组件,打包并发布到 NPM。我将使用一个示例项目演示以下内容:

  • 确保包中不包含任何依赖项
  • 使用 Webpack 分别构建应用于浏览器和Node环境中的代码
  • 创建一个应用于浏览器的插件
  • 配置 package.json
  • 发布到 NPM

项目案例: Vue Clock

我创建了这个简单的时钟组件,我会把它发布到 NPM 上。也许它不是你见过的最酷的组件,但它足以演示。

enter image description here

这是组件文件。这里没有什么特别的东西,但是请注意,我正在引入 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, {

})
];

常见的配置与之前完全一样(我简写了大部分内容以节省空间),除了我已经删除的 entryoutput.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": { ... }
}

我省略了这个文件的大部分,但重点要注意的是:

  1. 主脚本文件即 "main": "dist/vue-clock.js"。 这指向 Node bundle 文件,确保模块加载器知道文件的准确路径,即
1
import VueClock from 'vue-clock' // this resolves to dist/vue-clock.js
  1. 依赖关系,由于我从包中排除了所有依赖关系,用户必须自行安装依赖才能使用该包。

发布到 NPM

现在我的组件设置正确,可以在NPM上发布。 我不会重复的在这里说明,因为它们在npmjs.com上很好地介绍。

结果如下:

enter image description here

https://github.com/anthonygore/vue-clock-simple/blob/master/webpack.config.js
https://vuejsdevelopers.com/2017/07/31/vue-component-publish-npm/