值得了解的webpack高級技能

只要這幾步,webpack速成不是事兒一文中, 筆者簡單介紹了webpack的常見用法。能知足最基本的開發需求。在這篇文章中,再來談談一些較高級的應用。css

1. 配置不一樣環境的構建腳本

以前構建都是經過 npx webpack ... 這樣的方式執行構建命令。可能你會以爲這樣的方式不夠高效。甚至在某些特定的狀況下還須要設置 Node 的環境變量。根據環境變量值的不一樣,設置構建 --mode 的不一樣。html

scripts 配置的入口在 package.json 中,另外再介紹下。經過執行 npm i 默認安裝package.json中所有依賴。vue

"scripts": {
    "build": "webpack",
    "dev": "webpack-dev-server"
  },
複製代碼

cross-env 設置node環境變量的插件 npm i cross-env -Dnode

  • 開發環境構建: npm run dev

經過圖中能夠看到,npm run dev 至關於 npx webpack-dev-serverreact

  • 生產環境構建: npm run build

1.1 設置node環境變量

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

先安裝插件cross-envjquery

npm i cross-env -Dwebpack

執行 npm run dev, 先設置環境變量 NODE_ENV=devlelopment, 而後執行 webpack 命令。web

爲何要設置環境變量呢? 設置環境變量後,能夠在打包構建時執行相應環境變量下的腳本。npm

在webpack.config.js中 process.env.NODE_ENV 拿到環境變量值。作你想作的事情。哈哈哈~

  • 經過 webpack 自帶的插件定義全局變量 _DEV_ ,相似於全局變量 window
//應用: 在項目 src/index.js 文件中代碼裏區分開發或者是生產環境
 if(__DEV__){
     alert('開發環境')
 }else{
     alert('生產環境')
 }
複製代碼
  • 根據環境不一樣,來設置某些插件是否可用

在webpack.config.js文件中,設置變量 let isDev = process.env.NODE_ENV === 'development',而後定義插件的disable屬性的值json

plugins: [
        new ExtractTextWebpackPlugin({
            filename: 'css/index.css',
            disable: isDev
        }),
    ],
複製代碼

1.2 構建 DLL 動態連接庫

.dll 爲後綴的文件稱爲動態連接庫,在一個動態連接庫中能夠包含給其餘模塊調用的函數和數據

  • 基礎模塊獨立出來打包到單獨的動態鏈接庫裏
  • 當須要導入的模塊在動態鏈接庫裏的時候,模塊不能再次被打包,而是去動態鏈接庫裏獲取 dll-plugin
  • 提升構建效率

react, react-dom 爲例

  • 建立 webpack.config.react.js
let path = require('path');
let webpack = require('webpack');

module.exports  = {
    entry: {
        vendor: ['react', 'react-dom']
    },
    output: {
        filename: '[name].js',
        path: path.join(__dirname, 'dist'),
        libraryTarget: "var",  //構建後輸出js文件所屬規範, 若是 設置爲 commonjs, 則輸出文件符合 commonjs規範
        library: '_dll_[name]', //構建後輸出js庫的名字
      
    },
    mode: 'development',
    plugins: [
        new webpack.DllPlugin({
            name: '_dll_[name]',
            path: path.join(__dirname, 'dist', '[name].manifest.json')
        })
    ],
};
複製代碼
  • 設置構建命令
"scripts": {
    "build": "webpack",
    "dev": "webpack-dev-server",
    "react": "wepack --config webpack.config.react.js"
  },
複製代碼
  • 執行 npm run react

  • 輸出的 vendor.js

1.3 使用動態連接庫

在webpack.config.js中配置插件

plugins: [
    new webpack.DllReferencePlugin({
        manifest: path.resolve(__dirname, 'dist', 'vendor.manifest.json')
    })
]
複製代碼
  • react編譯須要安裝以下loader

npm i babel-core babel-loader babel-preset-env babel-preset-react babel-preset-stage-0 -D

  • 配置相關rules
module: {
        rules: [
            {
                test: /\.jsx?/,
                use: 'babel-loader',
                exclude:/node_modules/,
                include:/src/
            },
        ]
    },
複製代碼
  • 在項目根目錄下建立 .babelrc文件
{
    "presets": [
        "env",
        "stage-0",
        "react"
    ]
}
複製代碼

  • 執行構建命令 npm run build, 控制檯打印:
[./node_modules/react-dom/index.js] delegated ./node_modules/react-dom/index.js from dll-reference _dll_vendor 42 bytes {index} [built]
[./node_modules/react/index.js] delegated ./node_modules/react/index.js from dll-reference _dll_vendor 42 bytes {index} [built]
複製代碼

由此能夠看出項目構建時是使用的預先構建好的react庫文件,從控制檯打印的構建耗時也明顯不一樣。

2. 抽離公共代碼(庫文件或組件)

  • 建立src/a.js, src/x.js 文件
  • 在src/index.js 和 src/x.js文件中都import a.js文件
  • 在src/index.js 和 src/x.js文件中都引入 react庫文件

index.js

import './index.css';
// if(module.hot){
//    console.log('熱更新');
// }
import React, { Component } from 'react'
import { render } from 'react-dom'
import a from './a.js'

render(<h1>hello zfpx</h1>, window.app)
複製代碼

x.js

import React, { Component } from 'react'
import { render } from 'react-dom'

import a from './a.js'
複製代碼

a.js

module.exports = {
    a: 'a.js'
}
複製代碼

在webpack.config.js中配置:

optimization: {
        splitChunks: {
            cacheGroups: {
                commons: { //提供公共組件, 只要超出0字節就生產新的包
                    chunks: 'initial',
                    //miniChunks: 2,
                    //maxInitalRequest: 5,
                    name: 'commons',
                    minSize: 0 
                },
                vendor: {// 抽離第三插件
                    test: /node_modules/,
                    chunks: 'initial',
                    name: 'vender',
                    priority: 10,
                    enforce: true
                }
            }
        }
    },
複製代碼

執行構建腳本 npm run build, 控制檯打印:

若是註釋相關構建信息:

從兩者控制檯信息中能夠看出,構建後的index.js 和 x.js文件體積大小和 dist目錄中輸出的文件數量是不同的。

3. 設置全局變量

在index.js中引入 jquery.js後,在a.js文件中想不引入jquery.js直接使用jquery對象

webpack.config.js中配置

module: {
    rules: [
        {
        test: /jquery/,
        use:[{
            loader:'expose-loader',
            options:'$'
        }]
        },
    ]
}
複製代碼

或者使用webpack提供的內置插件

// 提供全局變量插件
        new webpack.ProvidePlugin({
            $:'jquery'
        }),
複製代碼

兩者的區別是神馬呢

  • 使用插件時:
1. $不會定義到window上
2. 只要是用到jquery(或者 $)的地方,當前bundle.js都會把jquery打包進去
複製代碼

webpack.config.js 相關配置爲:

entry: {
        index: './src/index.js',
        x: './src/x.js'
    },
 output: {
    filename: '[name].[hash].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    library: '_dll_[name]'
},
...
pugins: [
 new HtmlWebpackPlugin({
            template: 'src/index.html',
            hash: true
        }),
]
複製代碼

index.js

console.log($)
複製代碼

x.js

console.log($);
複製代碼

從構建的日誌中能夠看出,index.js構建後的文件大小和x.js構建的文件大小一致

  • 使用 expose-loader
1.導入一次,就會暴露出來
2.$會定義到在window上
複製代碼

index.js

import $ from 'jquery'
console.log('index.js');
console.log($);
複製代碼

x.js

console.log('x.js');
console.log($);
console.log(window.$);
複製代碼

構建日誌:

瀏覽器打印日誌:

從構建的日誌中能夠看出,index.js構建後的文件大小和x.js構建的文件大小不一致 從瀏覽器打印日誌能夠看出,x.js在沒有直接import jquery時,也能夠拿到jquery對象

4. 小結

webpack還有不少其餘適用的功能,好比在使用vue時,經常會根據路由加載相應的組件js也就是咱們所說的 按需加載。能夠用到webpack代碼分離中的 動態導入和懶加載(dynamic imports),優化代碼加載,提高性能。

相關文章
相關標籤/搜索