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抽取等問題。

求個關注~謝謝,麼麼噠~

相關文章
相關標籤/搜索