详解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 相关文章推荐
jquery、js调用iframe父窗口与子窗口元素的方法整理
Jul 31 Javascript
AngularJS 使用$sce控制代码安全检查
Jan 05 Javascript
解读Bootstrap v4 sass设计
May 29 Javascript
纯前端JavaScript实现Excel IO案例分享
Aug 26 Javascript
javascript过滤数组重复元素的实现方法
May 03 Javascript
简单谈谈axios中的get,post方法
Jun 25 Javascript
详解微信小程序Page中data数据操作和函数调用
Sep 27 Javascript
Vue.js 使用v-cloak后仍显示变量的解决方法
Nov 19 Javascript
使用mpvue搭建一个初始小程序及项目配置方法
Dec 03 Javascript
大转盘抽奖小程序版 转盘抽奖网页版
Apr 16 Javascript
vue实现表单录入小案例
Sep 27 Javascript
AJAX检测用户名是否存在的方法
Mar 24 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
分割GBK中文遭遇乱码的解决方法
2013/08/09 PHP
PHP函数preg_match_all正则表达式的基本使用详细解析
2013/08/31 PHP
那些年我们错过的魔术方法(Magic Methods)
2014/01/14 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
ThinkPHP5+Layui实现图片上传加预览功能
2018/08/17 PHP
PHP检查URL包含特定字符串实例方法
2019/02/11 PHP
PHP连接SQL server数据库测试脚本运行实例
2020/08/24 PHP
Js 时间函数getYear()的使用问题探讨
2013/04/01 Javascript
nodejs实现遍历文件夹并统计文件大小
2015/05/28 NodeJs
Highcharts使用简例及异步动态读取数据
2015/12/30 Javascript
浅析Bootstrip的select控件绑定数据的问题
2016/05/10 Javascript
bootstrap日历插件datetimepicker使用方法
2016/12/14 Javascript
Windows下快速搭建NodeJS本地服务器的步骤
2017/08/09 NodeJs
JQuery用$.ajax或$.getJSON跨域获取JSON数据的实现代码
2017/09/23 jQuery
vue使用jsonp抓取qq音乐数据的方法
2018/06/21 Javascript
详解puppeteer使用代理
2018/12/27 Javascript
使用p5.js实现动态GIF图片临摹重现
2019/10/23 Javascript
vue+AI智能机器人回复功能实现
2020/07/16 Javascript
jQuery实现穿梭框效果
2021/01/19 jQuery
[01:17:12]职来职往完美电竞专场
2014/09/18 DOTA
[02:17]快乐加倍!DOTA2食人魔魔法师至宝+迎霜节活动上线
2019/12/22 DOTA
Python实现PS滤镜Fish lens图像扭曲效果示例
2018/01/29 Python
python实现多线程行情抓取工具的方法
2018/02/28 Python
tensorflow实现简单的卷积网络
2018/05/24 Python
tensorflow实现训练变量checkpoint的保存与读取
2020/02/10 Python
Django ValuesQuerySet转json方式
2020/03/16 Python
东南亚排名第一的服务市场:kaodim
2019/03/28 全球购物
网络方面基础面试题
2012/11/16 面试题
海量信息软件测试笔试题
2015/08/08 面试题
美术指导求职信
2014/03/17 职场文书
奥巴马英文演讲稿
2014/05/15 职场文书
安全责任书怎么写
2014/07/28 职场文书
幼儿教师师德师风演讲稿
2014/08/22 职场文书
消费者理赔投诉书
2015/07/02 职场文书
2016年优秀共产党员先进事迹材料
2016/02/29 职场文书
python中sys模块的介绍与实例
2021/04/17 Python