前言:本文基於weboack4.x,主要涉及webpack4 基本概念、基本配置和實際項目打包優化。關於概念方面參考官網,經常使用配置來自於網絡資源,在文末有相關參考連接,實踐部分基於本身的項目進行優化配置。javascript
定義編譯打包入口文件。類型:字符串(單入口)、對象(多入口)css
entry: './src/index.js' // 等同於 entry: { main: './src/index.js' }
一、filename:[name]
: 對應着entry中對象的key[id]
: 內部的chumk id[hash]
: 每次打包編譯的惟一hash,改動會影響整個項目的打包,緩存失效[chunkhash]
:對應着每一個入口文件計算而來的hash,惟一,文件之間互不影響[contenthash]
: contenthash = (moduleId + content) 生成的hash。同一文件中,修改某個module影響其餘module。例如,js代碼中引入css文件,修改js文件形成css文件的hash改變 html
二、path: 是配置輸出文件存放在本地的目錄,字符串類型,是絕對路徑puclicPath: 對構建出的資源進行異步加載(圖片,文件) 時候的路徑前綴, 能夠看做靜態文件託管在cdn
三、chunkFilename: 決定了非入口(non-entry) chunk 文件的名稱,如按需加載、異步加載vue
參考:從零搭建webpack4 之output輸出java
rules 數組,包含多個處理文件的 loader 配置react
test:類型正則、字符串、數組。匹配文件
use:類型字符串、對象、數組【loader字符串或對象】。對選中的文件應用loader。webpack
對象中包含:loader、options:loader的具體配置參數、enforce: 改變該loader的執行的順序【pre/post】
include: 指定須要處理的文件。類型:通常爲路徑、能夠是數組類型。
exclude:排除不須要處理的文件。類型:通常爲路徑、能夠是數組類型。
noParse: 排除對沒有采用模塊化的文件解析和處理,相似:jQuery。 類型:RegExp, [RegExp], function其中一個。
parser:能夠更細粒度的配置哪些模塊語法【AMD、CommonJS、ES6等】是否須要解析git
Plugin 是用來擴展Webpack 功能的,經過在構建流程裏注入鉤子實現,它爲Webpack 帶
來了很大的靈活性。主要在打包的某個階段執行該插件,對文件進行處理,相似於鉤子函數github
觸發treeshking條件:
1.須要代碼是es module規範的而且使用解構賦值的方式引入,
2.開啓optimization.usedExports:true
來標記使用和未使用的模塊,web
webpack4的mode設置爲production,默認開啓optimization.usedExports和使用代碼壓縮
注:
一、tree shaking 不能做用於有反作用side-effect的代碼
若是全部代碼沒有反作用,在package.json 中添加
sideEffects: false
若是存在反作用代碼/模塊,
sideEffects: [ ".src/some-side-effectful-file.js", "*.css" ]
"side effect(反作用)" 的定義是,在導入時會執行特殊行爲的代碼,而不是僅僅暴露一個 export 或多個 export。舉例說明,例如 polyfill,它影響全局做用域,而且一般不提供 export。
二、不要意外地將 ES 模塊編譯成 CommonJS 模塊。若是你使用 Babel 的時候,採用了 babel-preset-env 或者 babel-preset-es2015,請檢查這些預置的設置。默認狀況下,它們會將 ES 的導入和導出轉換爲 CommonJS 的 require 和 module.exports,能夠經過設置.babelrc中 { modules: false } 選項來禁用它
devServer: { proxy: { '/api': { target: 'http://localhost:3000', pathRewrite: {'^/api' : ''} }, context: ['/api', '/online'], //匹配多個路徑,同時代理到同一個站點 target: 'http://localhost:3000' }, hot: true, hotOnly: true }
把代碼分離到不一樣的 bundle 中,能夠按需加載或並行加載這些文件
實現方式:
一、入口配置:entry 入口使用多個入口文件 =》 存在重複引用的模塊
二、抽取公有代碼:使用 SplitChunksPlugin 抽取公有代碼,取代CommonsChunkplugin
webpack.config.js 配置: ``` optimizition: { splitChunks: { chunks: 'all' } } ```
三、動態加載 :動態加載一些代碼 =》 ECMAScript 提案 的 import() 語法
方式1 + 方式2 須要配合使用,才能達到代碼抽離的效果
prefetch(預取):未來某些導航下可能須要的資源
preload(預加載):當前導航下可能須要資源
import(/* webpackPrefetch: true */ 'LoginModel');
/ webpackPrefetch: true /:把主加載流程加載完畢,在空閒時在加載其餘,等再點擊其餘時,只須要從緩存中讀取便可,性能更好。推薦使用,提升代碼利用率。把一些交互後才能用到的代碼寫到異步組件裏,經過懶加載的形式,去把這塊的代碼邏輯加載進來,性能提高,頁面訪問速度更快。
/ webpackPreload: true /: 和主加載流程一塊兒並行加載。
import() 異步加載加載的模塊,開啓代碼分割後,會被單獨打包在一個文件中
路由懶加載
const Login = () => import('./components/login')
模塊異步加載
import(/* webpackChunkName: "vendor"*/ './page/vendor.js').then(({default: _}) => {// todo})
mini-css-extract-plugin 用於提取公共css,取代 webpack 3 的 extract-text-webpack-plugin
注:通常適用於生產環境,在開發環境會致使HMR功能缺失;在開發環境,使用style-loader
使用方式:
const MiniCssExtractPlugin=require('mini-css-extract-plugin') const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 代碼壓縮 // modules 中 // css,scss,sass,less { test:/\.(sa|sc|c)ss$/, use: [ process.env.NODE_ENV === 'development' ? 'style-loader': MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ] } optimization: { minimizer: [new OptimizeCssAssetsPlugin({})] }, //plugins中 new MiniCssExtractPlugin({ filename: "[name].css" })
防止第三方包屢次編譯打包。 第一次打包時,把第三方模塊單獨打包生成一個文件 vendors.dll.js,以後在打包時就能夠直接從 vendors.dll.js 中引入以前打包好的第三方模塊
實現過程:
一、編寫一個用於生成動態連接庫的配置文件
二、運行生成動態連接庫和對應的.mainfest.json映射文件
三、在webpack.config.js中使用動態連接庫。這樣第二次編譯打包會從json文件中找相應的模塊
webpack.dll.config.js
module.exports = { entry: { react: ['react'] //react模塊打包到一個動態鏈接庫 }, output: { path: path.resolve(__dirname, 'dist'), filename: '[name].dll.js', //輸出動態鏈接庫的文件名稱 library: '_dll_[name]' //全局變量名稱 }, plugins: [ new webpack.DllPlugin({ name: '_dll_[name]', //和output.library中一致,值就是輸出的manifest.json中的 name值 path: path.join(__dirname, 'dist', '[name].manifest.json') }) ] }
webpack.config.js
plugins: [ new webpack.DllReferencePlugin({ manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')), }) ],
提升webpack的構建(打包/build)速度
webpack 做爲模塊化打包工具, 經常使用來對項目進行打包進行本地調試和發佈到線上,因此不管是本身在項目配置使用webpack仍是使用開發框架的腳手架進行開發,都須要區分開發和生產環境。在webpack4 的配置項中添加了 mode
屬性,能夠用來區分二者模式。
下面是開發和生產模式下一些默認配置和區別:
development 模式下,默認開啓了NamedChunksPlugin 和NamedModulesPlugin方便調試,提供了更完整的錯誤信息,更快的從新編譯的速度。
production 模式下,因爲提供了splitChunks和minimize,代碼就會自動分割、壓縮、優化,同時 webpack 也會自動幫你 Scope hoisting 和 Tree-shaking
使用 webpack-bundle-analyzer, 可直觀的看出打包後每一個模塊所佔比例和大小
使用方法:
2.在 package.json -> script 中添加啓動命令
"analyz": "cross-env NODE_ENV=prodution npm_config_report=true npm run build"
3.在 webpack.pro.conf.js -> plugin 添加如下代碼,能夠改變啓動時的端口等配置
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
new BundleAnalyzerPlugin({analyzerPort: 8089})
關於使用方法詳細可參考:webpack實踐-webpack-bundle-analyzer使用
import xxxx from '@componets/xxx' => const xxx = () => require('@componets/xxx')
對於一些相似antd、element-ui、eCharts等庫,能夠按需引入,沒有必要全局引入,具體方法見官方文檔
對於loadash等API依賴工具,結合lodash-webpack-plugin和babel-plugin-lodash,實現按需引入,把須要的API一次性引入,並掛載在全局上
// 從lodash 中統一引入你須要的方法 import _ from 'lodash' export default { cloneDeep: _.cloneDeep, debounce: _.debounce, throttle: _.throttle, size: _.size, pick: _.pick, isEmpty: _.isEmpty } // 注入到全局 import _ from '@helper/lodash.js' Vue.prototype.$_ = _ // vue 組件內運用 this.$_.debounce()
對於相似Jquery等大而使用較少的庫,能夠在index.html使用cdn引入;若是顧慮到可能形成外部攻擊等問題,能夠下載成爲本地資源,再引入
一、縮小文件搜索範圍或者指定特定的文件夾位置
二、排除不須要進行處理的文件
......
不使用默認的 UglifyJs,使用並行壓縮工具 webpack-parallel-uglify-plugin
......
具體參考:webpack 打包優化之速度篇
我是在我以前開發一大型項目使用webpack進行項目優化
注:此項目使用的webpack版本爲2.x,不是最新版本4.x,因爲項目比較複雜,升級帶來的潛在問題可能比較多,時間精力有限,暫時未升級
項目技術和庫:vue全家桶 + vue-cli + webpack + jQuery + element-UI + eCharts ...
按照上文中的經常使用配置,就打包速度和體積進行了優化,從而致使頁面加載速度獲得必定提高
圖片上傳失敗,顯示不出來 【手動捂臉】
因爲本文參考了許多相關文章,並加以本身的理解和實戰,若有不妥之處,請多包涵並指出,謝謝
參考:
webpack實踐——webpack-bundle-analyzer 的使用
從基礎到實戰 手摸手帶你掌握新版Webpack4.0詳解 教你看文檔
webpack 4.0 基礎到實戰配置github
webpack 官方文檔
關於webpack的面試題總結