webpack常見配置信息


1. devtool代碼調試

1. 生產模式下

source-map: 生成一個map文件,直接定位到源碼的行列

✅可以使用該模式,用於測試服務器

cheap-source-map: 只能定位到行,且只能定位到babel轉碼后的代碼

cheap-module-source-map: 只能定位到行,但是可以定位到源碼

2. 開發模式下

eval: 定位到編譯后的代碼

cheap-eval-source-map:  定位到babel轉碼后的行

cheap-module-eval-source-map: 定位到源碼的行

eval-source-map: 定位到源碼的行列

✅推薦使用該方法

line-*模式慢,不考慮

2. 第三方庫的應用

1. webpack.ProvidePlugin

對於類似lodash的各模塊頻繁使用的情況, 為了避免每次都手動引入,可以使用該插件實現全部模塊的自動引入該文件。只是優化了重復引入的問題,打包體積和直接引入相同。

    new webpack.ProvidePlugin({
      _: 'lodash'
    }),

相當於在每個模塊都默認執行了引入,用戶可以直接使用。

import _ from 'lodash';

❎該方法不是全局變量

2. expose-loader

該方法可以避免重復引入高頻使用的庫。而且可以將其作為全局變量。對於debugging很方便。 在控制台就可以直接使用。

在入口文件使用:

// 必須是require
require('expose-loader?_!lodash');
// !前是全局變量名稱;!后是庫名

然后可以直接使用window._訪問。

3. externals

當已經從CDN等外部引入第三方庫時,如果代碼中又手動引入了同樣的庫,該配置可以讓webpack不打包配置中的第三方庫。

 externals: {
    lodash: '_' // :前的key是庫的名稱;后面是全局變量的名稱
  }

想要起作用,必須要在html中引入CDN

<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

如上,即使在模塊中手動引入,webpack也不會將其打入包內

import _ from 'lodash'; //會忽略引入的lodash庫

const a = _.join(['a', 'b'], '~'); 

4. html-webpack-externals-plugin

3中,需要在html文件中引入CDN文件。如果不想手動引入,直接配置生成,可以使用該插件。

⚠️該插件必須在html-webpack-plugin插件實例化之后再進行實例化

new HtmlWebpackPlugin({
}),
new HtmlWebpackExternalsPlugin({
  externals: [
    {
      module: 'lodash',
      global: '_',
      entry: 'https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js'
    }
  ]
}),

3. 打包后的代碼添加注釋說明

new webpack.BannerPlugin('Lyra'),

4. 拷貝靜態文件(txt/doc等)

    new CopyWebpackPlugin([{
      from: path.join(__dirname, './src/assets'),
      to: path.join(__dirname, './dist/assets')
    }]),

5. devServer實現proxy代理,和模擬服務器

devServer: {
    contentBase: path.join(__dirname, 'dist'),
    port: 8080,
   host: 'localhost',
compress: true, // 啟用gzip壓縮 before(app) {
// devServer本身是一個express服務器,app是其對應的app;before指的是在app.listen之前執行 app.get('/api/user', (req, res) => { res.json([{ a: 'lyra' }]); }); }, proxy: { '/api': { target: 'http://localhost3000', // 代理本地服務到目標服務器;相當於nginx,不存在跨域問題 pathRewrite: { '^/api': '' // 重寫路徑;如:/api/user -> /user } } } },

6. webpack-dev-middleware模擬實現webpack-dev-server

const express = require('express');
const WebpackDevMiddleware = require('webpack-dev-middleware');
const webpack = require('webpack');
const webpackConfig = require('./webpack.config.js');


const app = express();
// 返回一個編譯對象
const compiler = webpack(webpackConfig);
// 1.使用webpack-dev-middleware插件啟動編譯
// 2.使用該插件響應客戶端請求的打包文件
app.use(WebpackDevMiddleware(compiler, {}));

app.get('/api/user', (req, res) => {
  res.json([{ a: 'name' }]);
});

app.listen(5000);

通過命令啟動

  "scripts": {
    "node": "node devServer.js",
    "build": "webpack",
    "dev": "webpack-dev-server --open"
  },

7. 模塊解析規則resolve

1. extensions

當引入文件不寫擴展名時,根據extentsions設置的規則,進行文件查找。

module.exports = {
  ...
  resolve: {
     extensions: ['.js', '.jsx', '.json']
  }  
}

2. alias

給查找路徑定義別名,加快文件查找速度。

對於引入npm安裝的模塊時,它會按照查找規則,依次查找。對於相對路徑查找,也會按照相對路徑的規則,依次查找。

通過定義alias可以直接按照alias指定的路徑查找,避免路徑解析消耗的時間。

module.exports = {
  //...
  resolve: {
    alias: {
      Utilities: path.resolve(__dirname, 'src/utilities/'),
      Templates: path.resolve(__dirname, 'src/templates/')
    }
  }
};

引入alias之前:

import Utility from '../../utilities/utility';

引入之后

import Utility from 'Utilities/utility';

另外,別名最后加上$表示,嚴格匹配,即使用時只能是別名,其他的都不匹配。

module.exports = {
  //...
  resolve: {
    alias: {
      xyz$: path.resolve(__dirname, 'path/to/file.js')
    }
  }
};

示例:

import Test1 from 'xyz'; // 嚴格匹配,按照別名解析
import Test2 from 'xyz/file.js'; // 不嚴格匹配,按照原來的解析規則解析

3. modules

指定查找的模塊,也可以在默認規則上添加其他需要查找的模塊

module.exports = {
  //...
  resolve: {
    modules: ['node_modules', 'myloaders'] //后者是自定義的模塊
  }
};

4. mainFields

定義入口文件字段的查找順序

module.exports = {
  //...
  resolve: { //定義了先查找package.json中的browser字段...
    mainFields: ['browser', 'module', 'main']
  }
};

5. mainFiles

當解析文件夾目錄的時候,會按照該字段查找文件夾中的文件

module.exports = {
  //...
  resolve: {
    mainFiles: ['index'] //也可以修改為main.js等
  }
};

8.resolveLoaders

屬性和規則同resolve, 對應的是處理模塊的loader的查找規則。

module.exports = {
  //...
  resolveLoader: {
    modules: ['node_modules'],
    extensions: ['.js', '.json'],
    mainFields: ['loader', 'main']
  }
};

在module中按照rules使用loaders進行解析時,查找loader模塊默認按照resolveLoader中的定義規則查找。

9. 自定義全局變量webpack.DefinePlugin

該插件中對應的字符串的內容,會被當作代碼片段解析。變量對應的值如果是非字符串,要通過JSON.stringify()進行序列化。

    new webpack.DefinePlugin({
      "PRODUCTION": JSON.stringify(true),
      "AUTHOR": {
        "USER": JSON.stringify('lyra') // 字符串也需要序列化,否則按照表達式處理
      }
    }),

10. 環境變量process.env.NODE_ENV

在代碼中可以通過訪問process.env.NODE_ENV來獲取當前項目的mode值。

應用:

可以根據該值來封裝函數,實現在不同環境下的不同表現。

const oldLog = console.log;
// 覆蓋原來的日志函數
console.log = function newlog() {
  if (process.env.NODE_ENV === 'development') {
    oldLog('開發環境打印日志');
  }
};

//使用時,引入該文件
import './console';

console.log("node_env", process.env.NODE_ENV);

11. glob匹配多入口文件

glob是一個匹配文件的工具。

npm i glob

如果需要實現多個入口文件,使用多個html模版文件。我們可以將入口文件統一放入entries文件中;將模版文件統一放入templates文件夾中。且名稱一一對應。

則不在需要一個個添加html-webpack-plugin插件。可以批量操作。

const glob = require('glob');

const files = glob.sync('./src/entries/*.js'); //獲取匹配的所有文件路徑
const entries = {};
const templates = [];
files.forEach((file) => {
  const fileName = path.basename(file, '.js'); //獲取文件的名稱,不含擴展名
  entries[fileName] = file;
  templates.push(new HtmlWebpackPlugin({
    template: `./src/templates/${fileName}.html`,
    filename: `${fileName}.html`,
    // hash: true,
    chunks: [fileName], // 指定各自的chunk塊,否則所有chunk將都引入
    chunksSortMode: 'manual'
  }));
});

12. 日志優化stats

webpack編譯時打印的日志多數是無效日志,我們通過設置stats的值自定義顯示的代碼。

stats默認是"normal"。

module.exports = {
  //...
  stats: 'normal'
};

還可以是其他值,如

1. errors-only        //只打印錯誤信息
2. errors-warnings // 錯誤和警告
3. verbose            // 打印所有的信息
4. minimal            // 只打印錯誤和新的編譯
5. none                // 不打印

如果想要更清晰,可以使用friendly-errors-webpack-plugin插件(作用不大)。

module.exports = {
  // ...
  plugins: [
    new FriendlyErrorsWebpackPlugin(),
  ],
}

13. 實現ES6等新API的兼容問題polyfill

一般會推薦使用babel-polyfill,用法

import 'babel-polyfill';

但是該方法會增大打包文件的體積,而且對於不需要的瀏覽器也會打包。

為了解決這些問題,可以使用

<script src="https://polyfill.io/v3/polyfill.min.js/"></script>

該接口可以根據UserAgent返回需要的polyfills。如果是Chrome瀏覽器,將返回空內容,因為它不需要polyfills。

13. stats.json

npx webpack --profile --json > stats.json

通過名稱生成stats.json文件,里面包含打包的所有信息。主要有幾個屬性:

1. chunks

代碼塊。生成代碼的途徑:

1. 入口文件會生成對應的chunk

output: {
    filename: '[name].[contenthash].js'  //hot:true下不能contenthash
}

2. 動態導入模塊會生成對應的chunk(import())

這類代碼塊的chunk命名規則如下
import(/* webpackChunkName: "example" */'./example')

3. splitChunk會生成分割的代碼chunk(代碼塊)

optimization: {
  splitChunks: {
    cacheGroups: {
      vendors: {
        chunks: 'initial', //必須有,默認是async(import());initial是同步,不設置該值不會生成代碼塊
        name: 'vendors', //設置代碼塊名稱
        test: /node_modules/, //指定要打包的模塊
        minSize: 50*1024,  // 打包最小體積
        priority: 1
      }, 
      commons: {
        chunks: 'initial',
        name: 'commons',
        test: /src/,
        minChunks: 2, // 至少被minChunks個module引用過
        priority: 2
      }
    }
  }
}, 

2. modules

在webpack中一切皆模塊。每個js,css,image等都是模塊。

webpack本身只能識別js文件,對於任何非js文件都需要通過loader進行編譯, 最終將其編譯為js輸出。

3. assets

最后打包生成的所有文件都是assets。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM