详解Webpack抽离第三方类库以及common解决方案


Posted in Javascript onMarch 30, 2020

前端构建场景有两种,一种是单页面构建,另一种是多入口构建多页面应用程序(我视野比较小,目前就知道这两种),下面我们针对这两种场景总结了几种抽离第三方类库以及公共文件的解决方案。

如果有哪些地方优化不周到,请指点一二,另外求关注求星星,么么哒

单页面构建:

常规配置

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  mode: "development",
  entry: {
    app: './app.js'
  },
  output: {
    path: path.resolve(__dirname, './build/'),
    filename: "bundle-[chunkhash:8].js"
  },
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
        },
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ],
        exclude: /node_modules/
      },
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',  // translates CSS into CommonJS
          'less-loader',   // compiles Less to CSS
        ],
        exclude: /node_modules/
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        use: [{
          loader: 'file-loader',
          options: {
            limit: 1024,
          }
        }],
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].[chunkhash:8].css",
      chunkFilename: "[id].[chunkhash:8].css"
    }),
    new HtmlWebpackPlugin({
      title: 'webpack',
      template: './index.html',
      chunks: ['app']
    }),
    new CleanWebpackPlugin()
  ],
}

在脚本种我们常规写法是这样的

require('./main-less.less');
require('./main-css.css');
const ReactDOM = require('react-dom');
const React = require('react');
import Main from './main.js';
// /**
// * 引入 scope hisiting test
// */
// import B from './ScopeHisitingTest/b';
ReactDOM.render(
  <Main />,
  document.getElementById('app')
)

我们看下构建输出结果

详解Webpack抽离第三方类库以及common解决方案

现在我们看到这个应该思考三个问题

1.脚本部分,难道每个页面都要写一边import React&ReactDOM 吗

2.构建体积能不能再缩小一点

3.构建速度能不能在快一点

以上三个问题都会在开发过程中耽误开发效率,我们开始处理这三个问题

方案1

html全局引用第三方类库,比如React,因为React源码中将React挂在到了window上,这么做解决了什么呢,脚本里面我们不用在每一个页面中引用第三方类库了,我们看下代码

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>
  <div id='app'></div>
  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</body>

</html>

好了解决了脚本部分不用每个页面都需要import一次了

构建体积怎么减小呢

这里我们可以借助webpack插件,下面我们上代码

externals: {
    'react': 'react',
    'react-dom': 'react-dom'
  },

我们将两个第三方类库打包的时候不依赖进去就可以啦,我们看下打包效果

详解Webpack抽离第三方类库以及common解决方案

可以明显的看到,采用这种用法之后会有一个问题就是,我们在脚本里面就不能在引用第三方类库了,不然打包进去,external会找不到这个第三方导致报错,直接用就好了,我们毕竟要解决的就是这个问题嘛。

以上就是第一种解决方案。

第二种

第二种方式采用将第三方类库打包到指定的dll中,通过webpack构建应用时引用

涉及两个Plugin,分别是DllReferencePlugin,DllPlugin

首先创建一个专门针对dll的webpack配置文件

const webpack = require('webpack');
const path = require('path');

module.exports = {
  entry: {
    react: [
      'react',
      'react-dom'
    ]
  },
  output: {
    filename: '[name].dll.js',
    path: path.resolve(__dirname, './distDll/dll/'),
    library: '[name]_dll_[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]_dll_[hash]',
      context: __dirname,
      path: path.join(__dirname, 'distDll/dll', '[name].manifest.json')
    })
  ]
}

然后执行这个webpack,生成dll以及描述模块运行依赖的manifest.json,我们应用的webpack需要引用这个dll

new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('./distDll/dll/react.manifest.json')
    }),

到这里就结束了吗,并不是,我们执行下webpack会发现,React找不到了,我们首先考虑到什么,难道是external的问题吗,你会发现跟它一点关系没有,难道我们每次写还要导入第三方类库吗,解决方案

ProvidePlugin

new webpack.ProvidePlugin({
      'React': 'react',
      'ReactDOM': 'react-dom'
    })

这样就解决了这个问题,我们看下构建效果

详解Webpack抽离第三方类库以及common解决方案

同样也达到了我们的目的

方案三

方案三采用optimization分离,其实与多页面分离第三方与common部分的用法是一样的,我们就跟多页面一起具体了。

多页面解决方案

基本配置

const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    app1: './app1.js',
    app2: './app2.js'
  },
  output: {
    path: path.resolve(__dirname, './build/'),
    filename: "[name]-[chunkhash].js"
  },
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
          },
          'less-loader',

        ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          'cache-loader',
          {
            loader: 'babel-loader',
          }
        ],
        exclude: /node_modules/
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash:5].css',
    }),
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'index1',
      template: './index1.html',
      filename: 'index1.html',
      chunks: ['app1', 'common'],
      // hash: true
    }),
    new HtmlWebpackPlugin({
      title: 'index2',
      template: './index2.html',
      filename: 'index2.html',
      chunks: ['app2', 'common'],
      // hash: true
    }),
    new webpack.HashedModuleIdsPlugin(),
  ],

}

打包效果

详解Webpack抽离第三方类库以及common解决方案

问题很明显,速度慢,体积过大,这里还有个问题就是,app1的与app2引用共同的文件导致的体积过大,也就是我们要解决的如何提取common部分的问题,这里我们就不讨论脚本import 第三方的问题了,上面有解决方案了。

提取common部分

optimization: {
    runtimeChunk: {
      "name": "manifest"
    },
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        default: false,
        vendors: false,
        common: {
          test: /\.(s*)js$/,
          chunks: 'all',
          minChunks: 2,
          minSize: 0,
          name: 'common',
          enforce: true,
          priority: -11
        },
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendors",
          priority: -10,
          chunks: 'all',
          reuseExistingChunk: true,
          enforce: true
        },
        style: {
          name: 'style',
          test: /\.less$/,
          chunks: 'all',
          enforce: true
        }
      }
    },
    runtimeChunk:{
      name:'manifest'
    }
  },

这里我们要做的是,提供commonjs,合并css(提取common部分也是可以的,毕竟页面也不可能用全部的css,做法与提取commonjs是一样的,配置minChunks最小为2就可以了),提供第三方类库。

我们看下打包效果

详解Webpack抽离第三方类库以及common解决方案

速度提升了,同时生成了common文件以及提三方文件集合verndors文件,嗯,目前解决了我们要解决的问题,上面单页面场景同样适用,浏览器缓存这个一般不会变得vendors,也达到了提升效率问题,

但是有没有想过一个问题,就是每一次webpack构建过程,是不是都要打一次这个包呢,浪费时间了吧,于是我们采用什么方式呢,没错~采用DllPlugin与DllReferencePlugin来提取一次第三方,

剩下common部分每一次构建都去重新打一次。

代码同样引用dll

new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('./distDll/dll/react.manifest.json')
    })

构建效果

详解Webpack抽离第三方类库以及common解决方案

效果就是大幅度提升构建速度。

最终配置文件

const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: {
    app1: './app1.js',
    app2: './app2.js'
  },
  output: {
    path: path.resolve(__dirname, './build/'),
    filename: "[name]-[chunkhash].js"
  },
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            // options: {
            //   sourceMap: true,
            //   modules: true,
            //   localIdentName: '[name]---[local]---[hash:base64:5]'
            // }
          },
          'less-loader',

        ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          'cache-loader',
          {
            loader: 'babel-loader',
            options: {
              // cacheDirectory: path.join(__dirname,'./build/', 'babel_cache')
              // happyPackMode: true,
              // transpileOnly: true
            }
          }
        ],
        exclude: /node_modules/
      }
    ]
  },
  optimization: {
    runtimeChunk: {
      "name": "manifest"
    },
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        default: false,
        vendors: false,
        common: {
          test: /\.(s*)js$/,
          chunks: 'all',
          minChunks: 2,
          minSize: 0,
          name: 'common',
          enforce: true,
          priority: -11
        },
        // vendors: {
        //   test: /[\\/]node_modules[\\/]/,
        //   name: "vendors",
        //   priority: -10,
        //   chunks: 'all',
        //   reuseExistingChunk: true,
        //   enforce: true
        // },
        style: {
          name: 'style',
          test: /\.less$/,
          chunks: 'all',
          enforce: true
        }
      }
    },
    runtimeChunk:{
      name:'manifest'
    }
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash:5].css',
    }),
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'index1',
      template: './index1.html',
      filename: 'index1.html',
      chunks: ['app1', 'common'],
      // hash: true
    }),
    new HtmlWebpackPlugin({
      title: 'index2',
      template: './index2.html',
      filename: 'index2.html',
      chunks: ['app2', 'common'],
      // hash: true
    }),
    new webpack.HashedModuleIdsPlugin(),
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('./distDll/dll/react.manifest.json')
    })
  ],
}

以上就是针对webpack构建优化全部总结,涉及第三方抽取,common抽取等问题。更多相关Webpack抽离第三方类库及common内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
url 编码 js url传参中文乱码解决方案
Apr 11 Javascript
FileUpload上传图片(图片不变形)
Aug 05 Javascript
jQuery实现按钮只点击一次后就取消点击事件绑定的方法
Jun 26 Javascript
JS实现带有抽屉效果的产品类网站多级导航菜单代码
Sep 15 Javascript
前端设计师们最常用的JS代码汇总
Sep 25 Javascript
原生Javascript和jQuery做轮播图简单例子
Oct 11 Javascript
JS刷新父窗口的几种方式小结(推荐)
Nov 09 Javascript
jQuery实现经典的网页3D轮播图封装功能【附源码下载】
Feb 15 jQuery
如何在微信小程序里面退出小程序的方法
Apr 28 Javascript
解决使用layui对select append元素无效或者未及时更新的问题
Sep 18 Javascript
工作中常用js功能汇总
Nov 07 Javascript
JavaScript中的几种继承方法示例
Dec 06 Javascript
记一次react前端项目打包优化的方法
Mar 30 #Javascript
12 种使用Vue 的最佳做法
Mar 30 #Javascript
javascript实现简易数码时钟
Mar 30 #Javascript
vue计算属性+vue中class与style绑定(推荐)
Mar 30 #Javascript
Bootstrap简单实用的表单验证插件BootstrapValidator用法实例详解
Mar 29 #Javascript
JS实现滑动拼图验证功能完整示例
Mar 29 #Javascript
json_decode 索引为数字时自动排序问题解决方法
Mar 28 #Javascript
You might like
PHP 面向对象 PHP5 中的常量
2010/05/05 PHP
php 获取今日、昨日、上周、本月的起始时间戳和结束时间戳的方法
2013/09/28 PHP
利用PHP将部分内容用星号替换
2020/04/21 PHP
PHP5.5.15+Apache2.4.10+MySQL5.6.20配置方法分享
2016/05/06 PHP
thinkPHP2.1自定义标签库的导入方法详解
2016/07/20 PHP
PHP实现统计代码行数小工具
2019/09/19 PHP
javascript引导程序
2008/10/26 Javascript
测试你的JS的掌握程度的代码
2009/12/09 Javascript
Textarea与懒惰渲染实现代码
2012/01/04 Javascript
jquery动态增加删除表格行的小例子
2013/11/14 Javascript
js菜单点击显示或隐藏效果的简单实例
2014/01/13 Javascript
jQuery实现的支持IE的html滑动条
2015/03/16 Javascript
Js和JQuery获取鼠标指针坐标的实现代码分享
2015/05/25 Javascript
BootstrapTable refresh 方法使用实例简单介绍
2017/02/20 Javascript
Koa项目搭建过程详细记录
2018/04/12 Javascript
用vue2.0实现点击选中active其他选项互斥的效果
2018/04/12 Javascript
vue .sync修饰符的使用详解
2018/06/15 Javascript
jsonp跨域获取数据的基础教程
2018/07/01 Javascript
javascript实现弹出层效果
2019/12/10 Javascript
如何HttpServletRequest文件对象并储存
2020/08/14 Javascript
React实现评论的添加和删除
2020/10/20 Javascript
Python中的字典与成员运算符初步探究
2015/10/13 Python
利用Python获取操作系统信息实例
2016/09/02 Python
Python3.5 创建文件的简单实例
2018/04/26 Python
用Python写脚本,实现完全备份和增量备份的示例
2018/04/29 Python
Python装饰器知识点补充
2018/05/28 Python
python利用插值法对折线进行平滑曲线处理
2018/12/25 Python
Python调用接口合并Excel表代码实例
2020/03/31 Python
标记环介质访问控制协议
2016/03/27 面试题
大学生专科学习生活的自我评价
2013/12/07 职场文书
应用化学专业职业生涯规划书
2013/12/31 职场文书
初一体育教学反思
2014/01/29 职场文书
河童之夏观后感
2015/06/11 职场文书
2016中秋节月饼促销广告语
2016/01/28 职场文书
QT与javascript交互数据的实现
2021/05/26 Javascript
springboot+rabbitmq实现智能家居实例详解
2022/07/23 Java/Android