如何解决Webpack抽离第三方类库以及common的问题

发布时间:2021-05-25 09:53:06 作者:小新
来源:亿速云 阅读:406

这篇文章主要介绍如何解决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')
)

我们看下构建输出结果

如何解决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的问题”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. 「小程序JAVA实战」 小程序抽离公用方法进行模块化(12)
  2. 如何在Vue中抽离接口配置文件

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

webpack common

上一篇:计算机网络中网站内部链接优化建设的要点有哪些

下一篇:redux处理异步action的示例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》