今年三月份入职以来, 一直在做后台运营系统, 其中重复性工作有很多, 其中组件库就是一项. 尽管现阶段有很多优秀的开源组件库, 但是为了适应产品奇奇怪怪的需求, 还是要手动实现一些组件. 将其沉淀下来, 积累一些自己东西.
概述: 首先基于 vue-cli 脚手架改装一个组件库的基本构建工具, 它具备以下几点功能:
webpack3.0 升级 webpack4.0 => 更好地完成组件的开发以及打包工作;
支持 Sass => 加速组件样式开发;
支持导入 Markdown 以及 Markdown 样式自定义, 以及 code 高亮;
自动配置路由.
1. 实例
实例地址:[Fat-Ge UI library](http://fatge.xyz/blog/juejin-example-3#/)
代码地址:[UI-Library code](https://github.com/FatGe/UI-Library)
2. 安装流程
环境: win-64 位, node-v8.12.0
安装
NPM install --global vue-cli
安装 vue-cli, 之后创建一个 ui-library 的项目
vue init webpack ui-library
创建的项目的 package.JSON 中, webpack 的版本为 3.6.0
- "webpack": "^3.6.0",
- "webpack-bundle-analyzer": "^2.9.0",
- "webpack-dev-server": "^2.9.1",
- "webpack-merge": "^4.1.0"
为了升级 webpack4.1.2, 先把当前 webpack 以及其相关依赖 uninstall
安装 webpack4, 由于 webpack4 依赖 webpack-cli, 所以也需要安装
- NPM install -D webpack webpack-cli webpack-bundle-analyzer webpack-dev-server webpack-merge
- NPM install -D copy-webpack-plugin CSS-loader eslint-loader file-loader HTML-webpack-plugin url-loader friendly-errors-webpack-plugin optimize-CSS-assets-webpack-plugin uglifyjs-webpack-plugin vue-loader
手动替换 extract-text-webpack-plugin 插件 NPM uninstall -D extract-text-webpack-plugin 替换为 NPM install -D mini-CSS-extract-plugin
安装 Sass 相关依赖 NPM install -D node-Sass Sass-loader --save-dev
配置
首先配置 webpack 的 mode, 在 webpack.dev.conf.JS 以及 webpack.prod.conf.JS 中分别加上
- const devWebpackConfig = merge(baseWebpackConfig, {
- mode: 'production',
- ...
- })
- const webpackConfig = merge(baseWebpackConfig, {
- mode: 'development',
- ...
- })
配置 webpack.base.conf.JS 文件
- // 引入 VueLoaderPlugin
- const { VueLoaderPlugin } = require('vue-loader')
- // 添加至
- const devWebpackConfig = merge(baseWebpackConfig, {
- ...
- plugins: [
- new VueLoaderPlugin(),
- ...
- ]
- })
配置 webpack.prod.conf.JS 文件
需要删除
- const ExtractTextPlugin = require('extract-text-webpack-plugin')
- const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
之后配置 config 项
- const ExtractTextPlugin = require('extract-text-webpack-plugin')
- const { VueLoaderPlugin } = require('vue-loader')
- const webpackConfig = merge(baseWebpackConfig, {
- optimization: {
- splitChunks: {
- cacheGroups: {
- vendors: {
- test: /[\\/]node_modules[\\/]/,
- chunks: 'initial',
- name: 'vendors',
- },
- 'async-vendors': {
- test: /[\\/]node_modules[\\/]/,
- minChunks: 2,
- chunks: 'async',
- name: 'async-vendors'
- }
- }
- },
- runtimeChunk: { name: 'runtime' }
- },
- plugins: [
- // 添加 VueLoaderPlugin
- new VueLoaderPlugin(),
- ...
- // 引入 MiniCssExtractPlugin
- new MiniCssExtractPlugin({
- filename: utils.assetsPath('css/[name].[contenthash:7].css')
- }),
- // Compress extracted CSS. We are using this plugin so that possible
- // duplicated CSS from different components can be deduped.
- new OptimizeCSSPlugin({
- cssProcessorOptions: config.build.productionSourceMap
- ? { safe: true, map: { inline: false } }
- : { safe: true }
- }),
- // see https://github.com/ampedandwired/html-webpack-plugin
- new HtmlWebpackPlugin({
- filename: config.build.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 vendor modules does not change
- new webpack.HashedModuleIdsPlugin(),
- // copy custom static assets
- new CopyWebpackPlugin([
- {
- from: path.resolve(__dirname, '../static'),
- to: config.build.assetsSubDirectory,
- ignore: ['.*']
- }
- ])
- ]
修改 utils.JS
- exports.cssLoaders = function(options) {
- options = options || {}
- // generate loader string to be used with extract text plugin
- function generateLoaders(loader, loaderOptions) {
- let loaders = []
- if (loader) {
- loaders = [{
- loader: loader + '-loader',
- options: Object.assign({}, loaderOptions, {
- sourceMap: options.sourceMap
- })
- }]
- }
- if (options.extract) {
- let extractLoader = {
- loader: MiniCssExtractPlugin.loader,
- options: {}
- }
- return [extractLoader, 'css-loader'].concat(['postcss-loader'], loaders)
- } else {
- return ['vue-style-loader', 'css-loader'].concat(['postcss-loader'], loaders)
- }
- }
- return {
- CSS: generateLoaders(),
- postcss: generateLoaders(),
- Less: generateLoaders('less'),
- Sass: generateLoaders('sass', { indentedSyntax: true }),
- SCSS: generateLoaders('sass'),
- stylus: generateLoaders('stylus'),
- styl: generateLoaders('stylus')
- }
- }
3. 支持导入 Markdown 以及 Markdown 样式自定义
由于 vue-Markdown-loader 与 vue-loader 版本 15 有兼容性的问题, 所以利用 text-loader 将 Markdown 文档导入并生成 String, 再编译为 Markdown 文档.
首先 NPM install -D text-loader 安装 text-loader, 用来引入 *.md 文件, 再修改 webpack.base.conf.JS 文件, 添加 text-loader
- rules: [
- ...(config.dev.useEslint ? [createLintingRule()] : []),
- {
- test: /.md$/,
- loader: 'text-loader'
- },
- ...
- ]
在引入 marked 对导入的 String 进行编译
- <template>
- <div class="markdown-body" v-HTML="compiledMarkdown" v-highlight></div>
- </template>
- import Markdown from '../../README.md'
- import marked from 'marked'
- export default {
- computed: {
- markdowonText () {
- // 编译 Markdown
- return marked(Markdown)
- }
- }
- }
觉得 Markdown 的样式有些丑, 可以导入 GitHub-Markdown-CSS
NPM install -D GitHub-Markdown-CSS
对样式进行修改. 如果 Markdown 中存在着某些 code, 可以通过 highlight 进行高亮展示
- NPM install -D highlight
- import hljs from 'highlight.js'
- // 调整高亮 code 的样式
- import 'highlight.js/styles/vs2015.css'
- hljs.configure({ useBR: true })
- // 注册一个 directive 用来添加 code 高亮
- Vue.directive('highlight',function (el) {
- let blocks = el.querySelectorAll('code')
- blocks.forEach(block => {
- hljs.highlightBlock(block)
- })
- })
4. 自动配置路由
利用 require.context 解析某个目录下的文件, 将其生成 Router 的配置
- const context = require.context('@/components/', true, /demo\.vue$/)
- const componentRouters = context.keys().map(url => {
- const start = url.indexOf('/')
- const end = url.lastIndexOf('/')
- const name = url.substring(start + 1, end)
- const path = `/${name}`
- return {
- name,
- path,
- component: require(`@/components${path}/demo`).default
- }
- })
- export default new Router({
- routes: [
- {
- path: '/',
- name: 'mainPage',
- component: mainPage
- },
- ...componentRouters
- ]
- }
- )
5. 总结
搭建一个简单的 UI-library 结构, 用于开发相关组件以及打包.
来源: https://juejin.im/post/5c0b8ece5188254f9e2809fe