vuecli3创建的组件库工程实现按需引入

工程地址

  1. 创建一个vuecli3项目:
    vue create demo-vuecli3-ui
    
    手动选择特性,我这里只要Babel以及Css-Professor;
    然后选择Sass/SCSS,开发者按照自己的喜好来选择css预处理语言;
  2. 启动检查是否正常,npm run serve
    [外链图片转存失败(img-4l6U1F2X-1566802198122)(AE419B7078334401AEAF03CBD849727C)]
    没问题,一切正常;
  3. 这里组件库的名字为:demo-vuecli3-ui,现在开始写组件,这里只写两个组件:
    • pl-button
    • pl-input

      除了这两个组件之外,还需要有一个体积比较大的组件,不然到时候测试按需引入的时候,很难观察到只引入部分组件(比如只引入button)所带来的打包体积优化效果。这里这个体积比较大的组件,使用element-ui来替代,把element-ui当做一个组件看待;
  4. 安装element-ui
    npm i element-ui -D
    
    这里为什么要-D-D--save-dev的缩写,-S--save的缩写,--save会将依赖添加到package.jsondependency列表中,如果是--save-dev,会将依赖添加到devDependency列表中。将组件打包,然后发布到npm仓库之后,用户可以通过npm i demo-vuecli2-ui --save安装依赖,这时候,用户安装的时候也会去下载element-ui,这个可以通过观察node_modules/demo-vuecli2-ui目录验证,这个目录下面也会有一个node_modules文件夹,其中就是demo-vuecli2-ui的dependency列表。实际上用户是不需要再次安装下载element-ui的,所以这里是-D
  5. 编写组件,根目录下创建components文件夹,目录结构:
    - components
        - button
            - index.js
            - pl-button.vue
        - ele
            - index.js
        - input
            - index.js
            - pl-input.vue
        - index.js
    
    文件内容:
    /*components/button/index.js*/
    import Button from './pl-button'
    Button.install = (Vue) => Vue.component(Button.name, Button);
    export default Button
    
    /*components/button/pl-button.vue*/
    <template>
      <div class="pl-button">
        pl-button
      </div>
    </template>
    
    <script>
      export default {
        name: "pl-button"
      }
    </script>
    
    <style lang="scss">
      .pl-button {
        background-color: maroon;
        color: white;
      }
    </style>
    
    /*components/ele/index.js*/
    import ELE from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    export default {
      install(Vue) {
        Vue.use(ELE)
      },
    }
    
    /*components/input/index.js*/
    import Input from './pl-input'
    Input.install = (Vue) => Vue.component(Input.name, Input)
    export default Input
    
    /*components/input/pl-input.vue*/
    <template>
      <div class="pl-input">
        pl-input
      </div>
    </template>
    
    <script>
      export default {
        name: "pl-input"
      }
    </script>
    
    <style lang="scss">
      .pl-input {
        background-color: #42b983;
        color: white;
      }
    </style>
    
    
    这个是总的打包入口
    /*components/index.js*/
    import Button from './button'
    import Input from './input'
    import Ele from './ele'
    
    export default {
      install(Vue) {
        Vue.use(Button)
        Vue.use(Input)
        Vue.use(Ele)
      },
    }
    
    

    这样用户在全引入组件库`demo-vuecli2-ui`,因为element-ui的存在,打包的体积会非常大,而用户在按需引入button以及input的时候,因为没有element-ui,打包的体积会大大缩小;
  6. 修改main.js,全引入demo-vuecli3-ui,用来调试组件。
    import Vue from 'vue'
    import App from './App.vue'
    
    import DVU3 from 'demo-vuecli3-ui'
    Vue.use(DVU3)
    
    Vue.config.productionTip = false
    
    new Vue({
        render: h => h(App),
    }).$mount('#app')
    
  7. 修改App.vue,展示组件:
    <template>
      <div id="app">
        <img alt="Vue logo" src="./assets/logo.png">
        <pl-input/>
        <pl-button/>
        <el-button>hello world</el-button>
        <el-input/>
      </div>
    </template>
    
    <script>
    export default {
      name: 'app',
    }
    </script>
    
    <style lang="scss">
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
  8. 创建目录,build,创建文件build/utils.js:
    const fs = require('fs')
    const path = require('path')
    const join = path.join
    const resolve = (dir) => path.join(__dirname, '../', dir)
    
    module.exports = {
        resolve,
        getComponentEntries(path) {
            let files = fs.readdirSync(resolve(path));
            const componentEntries = files.reduce((ret, item) => {
                const itemPath = join(path, item)
                const isDir = fs.statSync(itemPath).isDirectory();
                if (isDir) {
                    ret[item] = resolve(join(itemPath, 'index.js'))
                } else {
                    const [name] = item.split('.')
                    ret[name] = resolve(`${itemPath}`)
                }
                return ret
            }, {})
            console.dir(componentEntries)
            return componentEntries
        },
    }
    
  9. 创建文件build/config.pub.js,这个是本地调试以及打包组件都需要的配置信息:
    const utils = require('./utils')
    
    module.exports = {
        resolve: {
            extensions: ['.js', '.vue', '.json'],
            alias: {
                'src': utils.resolve('src'),
                'components': utils.resolve('components'),
                'demo-vuecli3-ui': utils.resolve('components/index.js'),
            }
        },
    }
    
  10. 创建文件build/config.dev.js,这个是本地调试的时候加载的配置文件:
    const pub = require('./config.pub')
    
    module.exports = {
        pages: {
            index: {
                // page 的入口
                entry: 'src/main.js',
                // 模板来源
                template: 'public/index.html',
                // 在 dist/index.html 的输出
                filename: 'index.html',
                // 当使用 title 选项时,
                // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
                title: 'pl-app document',
                // 在这个页面中包含的块,默认情况下会包含
                // 提取出来的通用 chunk 和 vendor chunk。
                chunks: ['chunk-vendors', 'chunk-common', 'index']
            },
        },
        configureWebpack: {
            resolve: pub.resolve
        },
    }
    
  11. 创建文件build/config.build.js,这个是打包组件的时候,加载的配置文件:
    const {resolve, getComponentEntries} = require('./utils')
    const pub = require('./config.pub')
    
    module.exports = {
        outputDir: resolve('lib'),
        configureWebpack: {
            entry: {
                ...getComponentEntries('components'),
            },
            output: {
                filename: '[name]/index.js',
                libraryTarget: 'commonjs2',
                libraryExport: 'default',
                library: 'demo-vuecli3-ui',
            },
            resolve: pub.resolve,
        },
        css: {
            sourceMap: true,
            extract: {
                filename: '[name]/style.css'
            }
        },
        chainWebpack: config => {
            config.optimization.delete('splitChunks')
            config.plugins.delete('copy')
            config.plugins.delete('preload')
            config.plugins.delete('prefetch')
            config.plugins.delete('html')
            config.plugins.delete('hmr')
            config.entryPoints.delete('app')
    
            config.module
                .rule('fonts')
                .use('url-loader')
                .tap(option => {
                    option.fallback.options.name = 'static/fonts/[name].[hash:8].[ext]'
                    return option
                })
        }
    }
    
    这里面主要讲chainWebpack中做了什么事情:
    • 删除splitChunks,在打包组件的时候,并不希望抽离每个组件的公共js出来,而是每个独立打包,于是删除这个配置;
    • 删除copy:不要复制public文件到打包目录;
    • 删除preload以及prefetch,因为删除了html插件,所以这两个也没用;
    • 删除html,只打包组件,不生成html页面;
    • 删除hmr,删除hot-module-reload;
    • 删除自动加上的入口:app
    • 下面的配置fonts这个rule,打包字体的时候,输出到打包目录的static/fonts目录下;
  12. 本地调试启动,检查效果:npm run serve
    [外链图片转存失败(img-t61MQgGy-1566802198124)(956D822BB84148F083572A1CE57918AB)]
  13. 打包:npm run build,打包结果:
    [外链图片转存失败(img-hR6dC7h9-1566802198124)(AC1C44C5182F436A96A99FB9C011FE66)]
    [外链图片转存失败(img-uQ4B0k0v-1566802198124)(5E50901B0BEF4C77AB1DE1A110202F1F)]
  14. 修改package.json
    • 修改版本号version为0.0.1
    • 删除private:true
    • 添加"main":“lib/index/index.js”
    • 添加"files":[“lib”]
  15. 发布到npm,npm publish
    [外链图片转存失败(img-nGiuHGOF-1566802198125)(DA6502EEBAD44BF5989F31A7D1F08009)]
    看到这个+ demo-vuecli3-ui就表示发布成功。
  16. 使用上一篇创建的测试工程test-load-on-demand测试demo-vuecli3-ui的按需引入功能是否完成。安装demo-vuecli3-ui:
    npm i demo-vuecli3-ui -S
    
  17. src/main.js中全引入demo-vuecli3-ui:
    import Vue from 'vue'
    import App from './App.vue'
    
    import DVU3 from 'demo-vuecli3-ui'
    import 'demo-vuecli3-ui/lib/index/style.css'
    
    Vue.use(DVU3)
    
    Vue.config.productionTip = false
    new Vue({
        render: h => h(App),
    }).$mount('#app')
    
  18. 本地调试启动,检查效果:
    [外链图片转存失败(img-LAjfSiTn-1566802198126)(77B2A3F4782E47A08897A6B52E410D3F)]
    可以看到,app.js大概有4.1m
  19. 打包页面,检查效果:
    [外链图片转存失败(img-UeX3ls3K-1566802198126)(1C0567A02EE14579AFA138B6489E6E90)]
    可以看到,chunk-vendor有800多k
  20. 配置按需引入,安装插件:babel-plugin-import
    npm i babel-plugin-import -D
    
  21. 配置.babelrc文件:
    {
      "presets": ["@vue/app", ["@babel/preset-env", { "modules": false }]],
      "plugins": [
        [
          "import",
          {
            "libraryName": "demo-vuecli3-ui",
            "style": true
          }
        ]
      ]
    }
    
  22. 配置src/main.js,按需引入Button以及Input组件:
    import Vue from 'vue'
    import App from './App.vue'
    
    import {Button, Input} from 'demo-vuecli3-ui'
    Vue.use(Button)
    Vue.use(Input)
    
    
    Vue.config.productionTip = false
    new Vue({
        render: h => h(App),
    }).$mount('#app')
    
  23. 本地调试启动,检查效果:
    [外链图片转存失败(img-Qnv9oal6-1566802198126)(ECD66CE652B242DF9AC1C6E1B80DE0F0)]
    可以看到,app.js的大小变为1.8m
  24. 打包页面,检查效果:
    [外链图片转存失败(img-roQjGWCh-1566802198127)(18ECDFAD2F4446979AAFA685A965B4EC)]
    可以看到,chunk-vendor变成了123k,体积大大缩小了;
  • 至此,vuecli3工程组件库按需引入说明已经结束
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值