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

 更新时间:2020年03月30日 11:15:50   作者:漠然1992丶  
这篇文章主要介绍了详解Webpack抽离第三方类库以及common解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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

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

单页面构建:

常规配置

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')
)

我们看下构建输出结果

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

  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'
  },

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

可以明显的看到,采用这种用法之后会有一个问题就是,我们在脚本里面就不能在引用第三方类库了,不然打包进去,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'
    })

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

同样也达到了我们的目的

方案三

方案三采用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(),
  ],

}

打包效果

问题很明显,速度慢,体积过大,这里还有个问题就是,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就可以了),提供第三方类库。

我们看下打包效果

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

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

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

代码同样引用dll

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

构建效果

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

最终配置文件

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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 细说JS数组遍历的一些细节及实现

    细说JS数组遍历的一些细节及实现

    本文主要介绍了细说JS数组遍历的一些细节及实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • js强制把网址设为默认首页

    js强制把网址设为默认首页

    有时候你会发现设首页为失效,那么来一个js强制设置首页的代码,不过为了绿色上网,尽量不要强迫你的用户意志,弄不好网站用户体验会降低。感兴趣的小伙伴可以参考一下
    2015-09-09
  • JavaScript对象原型链原理详解

    JavaScript对象原型链原理详解

    这篇文章主要介绍了JavaScript对象原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • JavaScript引用类型RegExp基本用法详解

    JavaScript引用类型RegExp基本用法详解

    这篇文章主要介绍了JavaScript引用类型RegExp基本用法,结合实例形式较为详细的分析了引用类型RegExp正则表达式相关函数使用技巧与操作注意事项,需要的朋友可以参考下
    2018-08-08
  • 微信小程序视频弹幕发送功能的实现

    微信小程序视频弹幕发送功能的实现

    这篇文章主要介绍了微信小程序视频弹幕发送功能的实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • js实现动态添加上传文件页面

    js实现动态添加上传文件页面

    这篇文章主要为大家详细介绍了js实现动态添加上传文件页面,如何动态创建一个input标签示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-10-10
  • 详解JavaScript的定时器

    详解JavaScript的定时器

    这篇文章主要为大家介绍了JavaScript的定时器 ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11
  • JS的反射问题

    JS的反射问题

    两个等号直接比较值,但是类型不能相互转换的时候报错
    2010-04-04
  • el-form实现表单和图片手动上传和校验功能

    el-form实现表单和图片手动上传和校验功能

    在写项目时,难免遇到需要上传表单,图片等文件,且表单内容需进行验证及必填项提示,图片需要和信息一起传递且图片载入后需可预览,这篇文章给大家介绍el-form实现表单和图片手动上传和校验功能,感兴趣的朋友一起看看吧
    2024-01-01
  • JS+CSS实现TreeMenu二级树形菜单完整实例

    JS+CSS实现TreeMenu二级树形菜单完整实例

    这篇文章主要介绍了JS+CSS实现TreeMenu二级树形菜单,以完整实例形式较为详细的分析了JS二级树形菜单的节点元素操作技巧,非常简单实用,需要的朋友可以参考下
    2015-09-09

最新评论