webpack4.0打包優化策略(二)

打包優化策略

區分開發和生產環境

一般咱們在開發網頁時須要區分構建環境css

  • 開發環境(development) 開發過程當中方便開發調試的環境
  • 生產環境(production) 發佈到線上使用的運行環境

經過npm命令區分

經過cross-env模塊設置環境變量html

cross-env 跨平臺地設置及使用環境變量,而沒必要擔憂爲平臺正確設置或使用環境變量。vue

npm i cross-env -D
複製代碼

Usage

npm scripts中:node

{
    "scripts": {
        "build": "cross-env NODE_ENV=production webpack --mode production",
        "dev": "cross-env NODE_ENV=development webpack-dev-server --mode development",
    }
}
複製代碼

執行npm命令切換環境react

npm run build // 生產環境 process.env.NODE_ENV === 'production'
npm run dev // 開發環境 process.env.NODE_ENV === 'development'
複製代碼

接下來咱們就能夠在webpack.config.js 經過process.env.NODE_ENV來得知當前環境標識webpack

代碼中區分環境

定義環境常量

webpack4之前都是經過DefinePlugin來定義NODE_ENV環境變量,以決定library中應該引用哪些內容。git

NODE_ENV是一個由Node.js暴露給執行腳本的環境變量。一般用於決定在開發環境與生產環境下,服務工具、構建腳本和客戶端library的行爲。github

在webpack.config.js 中添加DefinePlugin插件web

const webpack = require('webpack');

plugins: [
    new webpack.DefinePlugn({
       'process.env': {
           'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
       }
    })
]
複製代碼

在main.js中經過判斷process.env.NODE_ENV常量 來執行相應邏輯vue-cli

mode模式配置

在webpack4 增長了mode模式配置 在瀏覽器環境下指定了 process.env.NODE_ENV 的值,默認是development,但node環境中仍是須要cross-env來設置。 mode 是 webpack 4 中新增長的參數選項,其有兩個可選值:production 和 development。mode 不可缺省,須要二選一:

production 模式:
  • 1.生產環境默認開啓了不少代碼優化(minify,splite等)
  • 2.開發時開啓注視和驗證,而且自動加上了eval devtool
  • 3.生產環境不支持watching,開發環境優化了從新打包的速度
  • 4.默認開啓了Scope hoisting和Tree-shaking(原ModuleConcatenationPlugin)
  • 5.自動設置process.env.NODE_ENV到不一樣環境,也就是不須要DefinePlugin來作這個了
  • 6.若是你給mode設置爲none,全部默認配置都去掉了
  • 7.若是不加這個配置webpack會出現提醒,因此仍是加上吧

development 模式:

  • 1.主要優化了增量構建速度和開發體驗

  • 2.process.env.NODE_ENV 的值不須要再定義,默認是 development

  • 3.開發模式下支持註釋和提示,而且支持 eval 下的 source maps

const NODE_ENV = process.env.NODE_ENV;
if (NODE_ENV === 'development') { // 開發環境下執行下面代碼
    console.log('development', NODE_ENV);
} else { // 生產環境則執行如下環境
    console.log('production', NODE_ENV);
}

複製代碼

DefinePlugn

DefinePlugin 容許建立一個在編譯時能夠配置的全局常量。這可能會對開發模式和發佈模式的構建容許不一樣的行爲很是有用。

webpack配置中區分環境

在項目目錄中添加webpack配置文件

  • webpack.base.config.js 保存webpack基礎通用的配置的文件
  • webpack.dev.config.js 保存webpack開發環境配置的文件
  • webpack.prod.config.js 保存webpack生成環境配置的文件
  • webpack.config.js webpack執行配置文件 保存相應環境的配置和webpack基礎配置文件合併後的配置

基礎配置 webpack.base.config.js

webpack一些loader配置

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const HappyPack = require('happypack');
const os = require('os'); // 系統操做函數
const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length}); // 指定線程池個數

function resolve(dir) {
    return path.join(__dirname, dir);
}

module.exports = {
    entry: {
        app: './src/main.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                // use: 'babel-loader?cacheDirectory'
                use: 'happypack/loader?id=babel', // 緩存loader執行結果
                exclude: /node_modules/, // 排除不要加載的文件夾
                include: path.resolve(__dirname, 'src') // 指定須要加載的文件夾
            }
        ],
        noParse: function(content) { // content 從入口開始解析的模塊路徑
            return /no-parser/.test(content); // 返回true則忽略對no-parser.js的解析
        }
    },
    resolve: {
        modules: [ // 優化模塊查找路徑
            resolve('src'),
            resolve('node_modules') // 指定node_modules所在位置 當你import第三方模塊式 直接從這個路徑下搜尋
        ],
        alias: {
            funs$: resolve('src/util/funs.js')
        },
        extensions: ['.js', '.vue']
    },
    plugins: [
        new webpack.DefinePlugin({ // 定義環境變量
            "process.env": JSON.stringify(process.env.NODE_ENV)
        }),
        new HappyPack({
            id: 'babel',
            loaders: ['babel-loader?cacheDirectory'],
            threadPool: happyThreadPool,
            verbose: true
        }),
        new HtmlWebpackPlugin({
            template: resolve('index.html'),
            title: 'hello webpack!'
        })
    ]
}
複製代碼

開發配置webpack.dev.config.js

開發時的輸入輸出以及開發調試配置 如 devServer devtool 配置

const webpack = require('webpack');

module.exports = {
    plugins: [
       new webpack.DefinePlugin({
           'process.env': {
               'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
           }
       })
    ],
    devServer: {
        contentBase: resolve('dist'),
        compress: true,
        port: 9000
    }
};
複製代碼

生成環境webpack.prod.config.js

生成環境 進行壓縮 代碼分離等代碼優化 線上配置

const webpack = require('webpack');
const path = require('path');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlIncludeAssetsPlugin = require('html-webpack-include-assets-plugin');

module.exports = {
    plugins: [
        new webpack.DllReferencePlugin({
            manifest: require(path.join(__dirname, 'dll', 'react.manifest.json'))
        }),
        new ParallelUglifyPlugin({
            workerCount: 4, // 開啓幾個子進程去併發的執行壓縮,默認是當前電腦的cpu數量減1
            uglifyJS: {
                output: {
                    beautify: false, // 不須要格式化
                    comments: false // 保留註釋
                },
                compress: {
                    warnings: false, // Uglifyjs 刪除沒有代碼時,不輸出警告
                    // drop_console: true, // 刪除全部console語句
                    collapse_vars: true,
                    reduce_vars: true
                }
            }
        }),
        new HtmlWebpackPlugin({
            template: path.join(__dirname, 'index.html')
        }),
        new HtmlIncludeAssetsPlugin({
            assets: ['/dll/react.dll.js'],
            append: false
        })
    ]
};
複製代碼

webpack.config.js 配置合併

藉助webpack-merge 將base配置和相應環境配置 合併到'webpack.config.js'

npm i webpack-merge -D
複製代碼

webpack.config.js

const base = require('./webpack.base.config');
const merge = require('webpack-merge');

let config;
if (process.env.NODE_ENV === 'production') {
    config = require('./webpack.prod.config');
} else {
    config = require('./webpack.dev.config');
}

module.exports = merge(base, config);
複製代碼

運行生產配置

npm run build
複製代碼

運行開發配置

npm run dev
複製代碼

實時從新加載(live reloading) 和 模塊熱替換(HMR)

webpack-dev-server 爲你提供了一個簡單的 web 服務器,而且可以實時從新加載(live reloading)。

讓咱們設置如下:

npm i webpack-dev-server -D
複製代碼

配置webpack.dev.config.js

devServer: {
    contentBase: path.join(__dirname, 'dist'), // 將 dist 目錄下的文件,做爲可訪問文件。
    compress: true, // 開啓Gzip壓縮
    port: 9000, // 端口號
    inline: true // 在打包後文件裏注入一個websocket客戶端
}
複製代碼

npm scripts

{
    "scripts": {
        "dev": "cross-env NODE_ENV=development webpack-dev-server --mode development"
    }
}
複製代碼

啓動server

npm run dev
複製代碼

瀏覽器訪問localhost:9000 當修改代碼ctrl+s 將自動刷新瀏覽器

啓用HMR

模塊熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它容許在運行時更新各類模塊,而無需進行徹底刷新。

配置webpack.dev.config.js

devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 9000,
    inline: true,
    hot: true // 開啓HMR
}
複製代碼

注意 此外咱們還需添加NamedModulesPlugin 和 HotModuleReplacementPlugin 插件

webpack.dev.config.js

{
    plugins: [
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin()
    ]
}
複製代碼

其餘代碼和框架開啓熱替換

1.React Hot Loader(實時調整 react 組件)

Install

npm install react-hot-loader
複製代碼

Getting started

1.1 Add react-hot-loader/babel to your .babelrc:

// .babelrc

{
    "plugins": ["react-hot-loader/babel"]
}
複製代碼

1.2 Mark your root component as hot-exported:

// App.js
import React from 'react'
import { hot } from 'react-hot-loader'

const App = () => <div>Hello World!</div>

export default hot(module)(App)
複製代碼

2.Vue loader

vue-cli 已經集成 只需用vue-cli腳手架開發便可

HMR修改樣式表

藉助於style-loader的幫助,CSS的模塊熱替換其實是至關簡單的。

安裝以下loader:

npm i style-loader css-loader -D
複製代碼

HMR參考配置

相關文章
相關標籤/搜索