Fork me on GitHub

npm 如何发布自己的组件库(三)

签名两篇讲了如何规划本地项目的结构和如何发布最终的包,这一章讲一下如何编写文档和示例demo。

修改webpack.base.conf.js配置

学习elemntui的做法,主要是使用vue-markdown-loader来解析md文件,同时配置vueMarkdown参数来实现示例demo的展示。

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const MarkdownItContainer = require('markdown-it-container')
const striptags = require('./strip-tags')
const vueMarkdown = {
preprocess: (MarkdownIt, source) => {
MarkdownIt.renderer.rules.table_open = function () {
return '<table class="table">'
}
MarkdownIt.renderer.rules.fence = utils.wrapCustomClass(MarkdownIt.renderer.rules.fence)
return source
},
use: [
[MarkdownItContainer, 'demo', {
validate: params => params.trim().match(/^demo\s*(.*)$/),
render: function(tokens, idx) {
var m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
if (tokens[idx].nesting === 1) {
var desc = tokens[idx + 2].content;
const html = utils.convertHtml(striptags(tokens[idx + 1].content, 'script'))
// 移除描述,防止被添加到代码块
tokens[idx + 2].children = [];
return `<demo-block>
<div slot="desc">${html}</div>
<div slot="highlight">`;
}
return '</div></demo-block>\n';
}
}]
]
}
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: {
app: './examples/main.js'
},
...
module: {
rules: [
...
{
test: /\.md$/,
loader: 'vue-markdown-loader',
options: vueMarkdown
}
]
}
}

新建和注册demo-block组件

学习elementui,在components下面新建组件demo-block,并在全局注册,用于在md文件中使用和配合markdown进行解析。

1
Vue.component('demo-block', demoBlock)

新建docs文件夹

具体的我就不讲了,主要讲一下要点,首先是新建docs文件夹用于存放md文件,然后将对应的路由指向对应的md文件,比如/count指向/docs/count.md。

1
2
3
4
5
{
path: '/count',
name: 'count',
component: r => require.ensure([], () => r(require('../docs/count.md')))
}

这样当你执行npm run dev的时候,打开http://localhost:8080/count就可以查看count.md下面的内容了。

发布docs静态文件

这里重点讲一下如何分别打包package组件库和文档静态页面。首先,webpack.pro.conf.js已经被打包组件库占用了,那么我们的demo打包可以采取新建一个webpack.demo.conf.js文件来打包,具体内容和build有区别,但是和普通的前端开发静态资源打包没有区别。需要分别在config下面的index.js里面新建一个demo对象,然后修改build文件夹下面的build.js。

先把所有有

1
2
process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory : config.dev.assetsSubDirectory

的地方改为(暂不考虑test情况)

1
2
3
process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: process.env.NODE_ENV === 'demo' ? config.demo.assetsSubDirectory : config.dev.assetsSubDirectory

/config/index.js中demo对象为:

1
2
3
4
5
6
7
8
9
10
demo: {
env: require('./demo.env'), // demo的环境变量为demo
index: path.resolve(__dirname, '../demo/index.html'), // 输出的index.html文件所在
assetsRoot: path.resolve(__dirname, '../demo'), // 输出的文件夹
assetsSubDirectory: 'static', // 二级文件夹
assetsPublicPath: '/cdcomponents/', // 这里设置为github仓库的名字,用于gh-pages访问静态文件使用
productionSourceMap: false,
productionGzip: false,
productionGzipExtensions: ['js', 'css']
}

webpack.demo.conf.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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: config.demo.env
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.demo.productionSourceMap,
extract: true
})
},
devtool: config.demo.productionSourceMap ? '#source-map' : false,
output: {
path: config.demo.assetsRoot,
filename: path.posix.join(config.demo.assetsSubDirectory, 'js/[name].[chunkhash].js'),
chunkFilename: path.posix.join(config.demo.assetsSubDirectory, 'js/[name].[chunkhash].js')
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
// UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: path.posix.join(config.demo.assetsSubDirectory, 'css/[name].[contenthash].css')
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.demo.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// keep module.id stable when vender modules does not change
new webpack.HashedModuleIdsPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.demo.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
if (config.demo.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.demo.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.demo.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig

配置package.json

修改后将package.json的script稍作修改,使得打包更加便捷:

1
2
3
4
5
6
7
8
9
"scripts": {
"dev": "cd packages/theme-default && gulp dev && cd ../../ && node build/dev-server.js ",
"start": "npm run dev",
"build": "cross-env NODE_ENV=production node build/build.js && cp -r ./packages/theme-default/lib/* dist/",
"demo": "cross-env NODE_ENV=demo node build/build.js",
"unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit/specs"
}

其中npm run dev表示运行本地的demo,cd packages/theme-default && gulp dev是先打包了theme样式文件,这样也有利于后面打包生成环境的时候可以直接利用。

其中npm run build表示打包packages组件库,cp -r ./packages/theme-default/lib/* dist/是将刚刚打包的theme直接copy到dist文件夹下面。

其中npm run demo表示打包示例demo的静态页面,cross-env NODE_ENV=demo设置了环境变量。

发布到gh-pages

github的gh-pages可以展示项目中的静态页面,那么我们刚刚打包好了demo文件下面的静态文件就可以push到gh-pages分支了,那么如何更加便捷的push呢。

在根目录下新建bin文件夹,bin下面新建static文件

1
2
3
4
5
6
7
8
#!/bin/bash node
cd demo
git init
git add .
git commit -m "auto push"
git remote add origin https://github.com/zp1112/cdcomponents.git
git push -f --set-upstream origin master:gh-pages

执行sh ./bin/static即可实现push到gh-pages,然后网页打开https://zp1112.github.io/cdcomponents/,即可看到文档了!

-------------本文结束感谢您的阅读-------------
如果您觉得受益了,欢迎打赏鼓励。