Zhili's blog Zhili's blog
首页
关于
GitHub (opens new window)

Zhili

转型中的前端老兵
首页
关于
GitHub (opens new window)
  • webpack 区分环境使用CDN以及HtmlWebpackPlugin插件的编写

  • 前端
zhili
2018-12-14

webpack 区分环境使用CDN以及HtmlWebpackPlugin插件的编写

webpack 区分环境使用CDN以及HtmlWebpackPlugin插件的编写

最近项目由1.0版开发到了1.1版,内容越来越多,引入的库也越来越多,每次打包的时候webpack都会提示,包的大小太大什么的,影响性能,作为一个有追求的前端当然不会放任不管,于是,Google一番,引入cdn,在index.html中写入

 <script src="https://unpkg.com/vue@2.5.21/dist/vue.min.js"></script>
 <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.min.js"></script>
 <script src="https://unpkg.com/element-ui@2.4.11/lib/index.js"></script>
1
2
3

在webpack.base.conf.js中添加要忽略的包

 externals: {
    vue: 'Vue',
    vuex: 'Vuex',
    'element-ui': 'ELEMENT'
  }
1
2
3
4
5

一切都看起来很不错,but,当我背着电脑回家,打开项目,npm run dev,输入localhost:8080,页面出不来,额,忘了没有联网。。。但是,没有网就不能开发吗,显然不能,于是注释掉上面这些代码,页面终于出来了,这么注释来注释去,不够优雅,我只想在生产环境下使用CDN,在开发环境下还是想用本地的,有了问题我们来解决

# 区分环境使用CDN

HtmlWebpackPlugin插件是我们开发时基本上必用的一个webpack插件,网上的介绍也很多,它主要是完成对index.html的js,css等资源的注入,同时它也能定义一些变量,template即我们的模板文件如果没有使用loader的时候,默认以ejs格式处理,这样,我们就可以在index.html方便的处理了

  • 首先,去掉index.html中我们添加的CDN引用

  • 去掉webpack.base.conf.js中的externals配置,将其放到webpack.prod.conf.js中

  • 在webpack.prod.conf.js中的HtmlWebpackPlugin中添加一个变量cdn,最终修改为如下所示:

    new HtmlWebpackPlugin({
          filename: config.build.index,
          template: 'index.html',
          inject: true,
          cdn:[
            'https://unpkg.com/vue@2.5.21/dist/vue.min.js',
            'https://unpkg.com/vuex@3.0.1/dist/vuex.min.js',
            'https://unpkg.com/element-ui@2.4.11/lib/index.js'
          ],
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true
          },
          chunksSortMode: 'dependency'
        })
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  • 将index.html中添加如下内容:

    <% if(htmlWebpackPlugin.options.cdn){ %> <% for(var i in htmlWebpackPlugin.options.cdn){ %>
        <script src="<%= htmlWebpackPlugin.options.cdn[i] %>"></script>
        <% } %> <% } %>
    
    1
    2
    3

    使用ejs语法将定义在HtmlWebpackPlugin中的cdn写入,这样就解决了只在生产环境使用CDN,在开发环境下使用本地的。但是,作为一个完美主义者,修改HtmlWebpackPlugin插件的配置以及在index.html中写入一串类似js的代码总觉得不够优雅,难道不能直接在HtmlWebpackPlugin注入的阶段插入CDN吗,于是一顿操作,最终发现HtmlWebpackPlugin提供了事件接口,我们可以在它的基础上开发自己的插件,bingo,那么就来开发一个吧。

    # HtmlWebpackPlugin插件的编写

    HtmlWebpackPlugin插件在3.x和4.x版本上的写法是不一样的,我们的开发环境使用的webpack3.x的,因此下面我基于3.x进行开发。

    HtmlWebpackPlugin提供了5个异步事件和1个同步事件,这些在官方GitHub和其他网友的博客中都有写到,我就不再叙述了,我主要使用了html-webpack-plugin-before-html-processing事件,在HTML处理之前将js注入进去,官网给了开发插件的例子:

    function MyPlugin(options) {
      // Configure your plugin with options...
    }
    
    MyPlugin.prototype.apply = function(compiler) {
      // ...
      compiler.plugin('compilation', function(compilation) {
        console.log('The compiler is starting a new compilation...');
    
        compilation.plugin('html-webpack-plugin-before-html-processing', function(htmlPluginData, callback) {
          htmlPluginData.html += 'The magic footer';
          callback(null, htmlPluginData);
        });
      });
    
    };
    
    module.exports = MyPlugin;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    htmlPluginData我们打印出来一看,属性一目了然:

    {
        html:''//HTML模板内容,
        assets:{
            chunks:[],//入口文件的内容
            js:[],//要插入的js文件的路径  ---就是我们要找的
            css:[],//要插入的css文件的路径
            manifest:''
        },
        ....
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    assets.js就是我们要找的,编写插件其实只要一句话

    htmlPluginData.assets.js = this.options.js.concat(htmlPluginData.assets.js)
    
    1

    so easy,下面是插件的完整代码:

    class InjectCDN {
      constructor (options) {
        const defaultOpt = {
          js: []
        }
        this.options = Object.assign(defaultOpt, options)
      }
    
      // 处理方法
      apply (compiler) {
        // webpack3.x
        compiler.plugin('compilation', compilation => {
          compilation.plugin(
            'html-webpack-plugin-before-html-processing',
            (htmlPluginData, callback) => {
              // 将js添加进去
              htmlPluginData.assets.js = this.options.js.concat(htmlPluginData.assets.js)
              if (callback) {
                return callback(null, htmlPluginData)
              } else {
                return Promise.resolve(htmlPluginData)
              }
            }
          )
        })
      }
    }
    module.exports = InjectCDN
    
    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

    在webpack.prod.conf.js中这样使用:

    new HtmlWebpackPlugin({}),
    new InjectCDN({
          js: [
            'https://unpkg.com/vue@2.5.21/dist/vue.min.js',
            'https://unpkg.com/vuex@3.0.1/dist/vuex.min.js',
            'https://unpkg.com/element-ui@2.4.11/lib/index.js'
          ]
    })
    
    1
    2
    3
    4
    5
    6
    7
    8

    new InjectCDN需要放到new HtmlWebpackPlugin后面。

    这样,就完成了在发布的时候使用cdn,在开发的时候使用本地文件。同时,这个插件也可以实现不同环境下不同CDN的切换,方便调试和发布。

编辑 (opens new window)
#webpack#plugin#CI
上次更新: 2022/03/17, 06:32:20
最近更新
01
可视化表单搭建系统的开发与思考
03-09
02
使用node反向代理接口改造旧项目
11-17
03
面试总结39题
10-11
更多文章>
Theme by Vdoing | Copyright © 2022-2023 zhili | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式