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

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

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

单页面构建:前端

常规配置node

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()
    ],
}

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

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

 

 

 如今咱们看到这个应该思考三个问题web

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

  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抽取等问题。

求个关注~谢谢,么么哒~

相关文章
相关标签/搜索