美文网首页前端必备性能优化
使用npm打造自己的vue组件库

使用npm打造自己的vue组件库

作者: 景元合 | 来源:发表于2019-11-27 10:30 被阅读0次

    背景说明

    最近公司要将项目用的组件整合成一个npm库,像使用mint-ui一样引用,于是借这个机会学习了一下,实现按需引用自己的vue组件库。
    参考链接:https://segmentfault.com/a/1190000015884948#articleHeader1

    目标

    可以像mint-ui一样按需引用组件,方便团队统一管理组件。

    难点

    webpack的入口、出口配置,以及组件的按需加载

    原理

    利用 babel-plugin-component 插件,来实现按需加载。该插件需要的是 这样一个文件结构


    image.png

    实现过程

    • vue-cli 搭建基础项目。

    vue init webpack adms-plugin
    

    因为公司组件依赖mint-ui,因此还需要install mint-ui以及使用iconfont。

    npm i mint-ui --save
    
    image.png

    项目是用vue-cli搭建的项目:
    1、build中是webpack相关配置
    2、example目录是开发时调试用
    3、src目录中components中是各个功能模块,各功能模块的入口中同element一样,对组件进行扩展,增加install方法,将组件进行全局注册,index.js是入口,其中引入所有功能模块,同时导出模块和install方法,将所有模块进行注册。
    4、lib中是最终打包的目标目录,记录将要打包的功能模块名称和路径
    5、增加components.json文件

    {
        "Datepopup":"./src/components/Datepopup",
        "index":"./src/index"
    }
    

    index文件为所有文件入口,可用于全局引用。

    • webpack相关配置更改

    规划中,需要将各个模块打包至lib,一个功能模块为一个.js文件,并且在theme目录中存在一个同名的.css文件,这样使用时借助babel-plugin-component插件就可实现按需引入。还需要一个总的index.js包含所有的功能模块,和一个index.css包含所有的样式。
    这里采用多入口(entry)配置,实现各个功能模块分别打包成一个.js文件,并使用extract-text-webpack-plugin将样式进行抽离后,按入口chunk进行打包为对应的.css文件。
    npm run build进行将各个模块打包为各自的.js文件,样式文件也同时抽离处理为同名的.css
    下面是webpeck相关具体修改:
    E:\npm\adms-plugin\config\index.js


    image.png

    assetsRoot路径改为lib

    • 下面详细介绍webpack.prod.conf

    E:\npm\adms-plugin\build\webpack.prod.conf.js

    '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 ExtractTextPlugin = require('extract-text-webpack-plugin')
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
    const env = require('../config/prod.env')
    // 整理入口
    const components = require('../components.json')
    const entrys = {}
    Object.keys(components).forEach(item => {
      entrys[item] = components[item]
    })
    const webpackConfig = merge(baseWebpackConfig, {
      entry: entrys,
      module: {
        rules: utils.styleLoaders({
          sourceMap: config.build.productionSourceMap,
          extract: true,
          usePostCSS: true
        })
      },
      devtool: config.build.productionSourceMap ? config.build.devtool : false,
      output: {
        path: config.build.assetsRoot,
        filename: '[name].js',
        library: 'VueDropUpload',
        libraryTarget: 'umd'
      },
      externals: {
        vue: {
          root: 'Vue',
          commonjs: 'vue',
          commonjs2: 'vue',
          amd: 'vue'
        }
      },
      plugins: [
        new webpack.DefinePlugin({
          'process.env': env
        }),
        new UglifyJsPlugin({
          uglifyOptions: {
            compress: {
              warnings: false
            }
          },
          sourceMap: config.build.productionSourceMap,
          parallel: true
        }),
        // extract css into its own file
        new ExtractTextPlugin({
          filename: '/theme/[name].css'
        })
      ]
    })
    
    if (config.build.productionGzip) {
      const CompressionWebpackPlugin = require('compression-webpack-plugin')
    
      webpackConfig.plugins.push(
        new CompressionWebpackPlugin({
          asset: '[path].gz[query]',
          algorithm: 'gzip',
          test: new RegExp(
            '\\.(' +
            config.build.productionGzipExtensions.join('|') +
            ')$'
          ),
          threshold: 10240,
          minRatio: 0.8
        })
      )
    }
    
    if (config.build.bundleAnalyzerReport) {
      const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
      webpackConfig.plugins.push(new BundleAnalyzerPlugin())
    }
    
    module.exports = webpackConfig
    

    1、删除HtmlWebpackPlugin相关配置,这里只需打包为js文件和css文件,不涉及html
    2、引入components.json,根据配置的模块及路径配置入口entrys,配置完后,将入口写入entry配置
    3、ExtractTextPlugin插件是进行css抽离的,这里不用处理
    4、ouput中,出口.js文件的名称不能写死
    5、在plugins插件配置处,ExtractTextPlugin相关配置,filename不能写死,需要根据chunk名称自动生成对应名称。这里设置为'/theme/[name].css'指定目录lib/theme存放
    到此,webpack配置就差不多完成了。
    npm run build打包完成后的目录结构:


    image.png
    • 配置package.json

    E:\npm\adms-plugin\package.json


    image.png

    private设置项目为公开,main设置项目入口地址

    打包发布

    npm login //登录npm 
    npm publish //发布包 
    

    截止到目前为止,vue组件成功发布到npm。
    此处需要将 将淘宝镜像 还原。否则 发布、安装 都出问题。

    // 查询当前配置的镜像 npm get registry //https://registry.npmjs.org/ 
    // 设置成淘宝镜像 npm config set registry http://registry.npm.taobao.org/
    // 换成原来的 npm config set registry https://registry.npmjs.org/
    

    另外,每次发布 需要 修改 package.json 里的 version。
    还需要注意是否包名(package.json 里的 name)冲突,npm 平台已存在的话 不让上传。

    引入使用

    接下来大家就可以开心的使用自己的npm库了,

    import {Datepopup} from 'adms-plugin'
    Vue.use(Datepopup)
    

    这里需要使用babel-plugin-component插件,并且配置

    npm i babel-plugin-component -D
    

    E:\npm\hello-world\demo.babelrc文件

    "plugins": ["transform-vue-jsx", "transform-runtime",[
        "component",{
          "libraryName": "adms-plugin",
          "styleLibrary": {
            "name": "theme",
            "base":true
          }
        }
      ]],
    

    其中libraryName为自己的库名,name为样式文件,base为是否使用引用base.css文件。

    遇到的难点

    • 多个组件引用base.css文件
      使用babel-plugin-component会引用base.css,难点主要是 base.css 文件的生成,由于 webpack 无法单独生成css文件(要依赖js)。这里 我新建了一个 base.js 文件,也作为了一个 webpack 的入口文件
      因此我新建了一个base.js
    import './assets/css/base.css'
    import './assets/font/iconfont.css'
    

    并且修改components.json文件:

    {
        "Datepopup":"./src/components/Datepopup",
        "index":"./src/index",
        "base":"./src/base"
    }
    

    这样就可以生成base.css,同时依赖的iconfont也加载了进来

    • 打包时需要注意名称命名需要使用kebab-case (短横线分隔命名)格式,例如:button-model,在components.json配置中,需要使用短横线分隔命名。

    总结

    构建vue项目库难点主要创建webpack入口,以及base.css文件的引入,同时使用时候记得配合babel-plugin-component插件按需加载,希望这篇文章能帮助有需要的同学们。

    相关文章

      网友评论

        本文标题:使用npm打造自己的vue组件库

        本文链接:https://www.haomeiwen.com/subject/rontwctx.html