亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

webpack4升級(jí)到webpack5的實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)

 更新時(shí)間:2022年08月15日 09:47:52   作者:凡沸  
有些老項(xiàng)目的包長(zhǎng)時(shí)間沒(méi)有更新,導(dǎo)致項(xiàng)目中有些性能問(wèn)題,在項(xiàng)目迭代中考慮升級(jí)包,下面這篇文章主要給大家介紹了關(guān)于webpack4升級(jí)到webpack5的實(shí)戰(zhàn)經(jīng)驗(yàn),需要的朋友可以參考下

前言

最近接手了公司內(nèi)部webpack相關(guān)的依賴包,于是打算優(yōu)化一波。考慮到webpack5已經(jīng)正式發(fā)布近兩年,跟webpack相關(guān)的依賴包應(yīng)該適配的差不多了,于是打算先把webpack4升級(jí)到webpack5,然后基于webpack5再進(jìn)行優(yōu)化。

升級(jí)前用的是 "webpack": "^4.42.1" ,升級(jí)后用的是 "webpack": "^5.72.1" 。

筆者采用的升級(jí)webpack的方法是先一鍵升級(jí)所有的依賴包,然后一個(gè)一個(gè)地去解決運(yùn)行過(guò)程中的報(bào)錯(cuò)。

首先,全局安裝npm-check-updates:

yarn global add npm-check-updates

然后在項(xiàng)目中執(zhí)行 ncu -u ,這樣項(xiàng)目的package.json會(huì)把所有的依賴包都更新到最新版本,然后執(zhí)行 yarn 。升級(jí)完就可以開啟漫長(zhǎng)的debug之旅了。

terser-webpack-plugin語(yǔ)法報(bào)錯(cuò)

Invalid options object. Terser Plugin has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'cache'. These properties are valid:
   object { test?, include?, exclude?, terserOptions?, extractComments?, parallel?, minify? }

原來(lái)的配置:

minimizer: [
	new TerserPlugin({
		cache: true,
		parallel: true,
		terserOptions: {
			mangle: false, // Note `mangle.properties` is `false` by default.
		},
	}),
]

從報(bào)錯(cuò)來(lái)看,terser-webpack-plugin的配置屬性發(fā)生了改變,現(xiàn)在已經(jīng)沒(méi)有 cache 這個(gè)選項(xiàng)了。

terser-webpack-plugin是用來(lái)壓縮JavaScript代碼的。不過(guò)webpack5已經(jīng)自帶了terser-webpack-plugin,如果說(shuō)你用的是webpack5或者更高版本,同時(shí)還希望自定義配置,那么還是需要安裝terser-webpack-plugin。

webpack4的時(shí)候可以通過(guò)terser-webpack-plugin的cache屬性開啟文件緩存?,F(xiàn)在webpack5自身提供了持久化緩存機(jī)制,它能夠?qū)⑹状未虬慕Y(jié)果緩存到硬盤中,等下次打包的時(shí)候就可以跳過(guò)一系類的耗時(shí)的操作,復(fù)用第一次的打包結(jié)果??梢酝ㄟ^(guò)以下配置開啟持久化緩存:

cache: {
 type: 'filesystem',
 version: 'yourVersion'
}

緩存默認(rèn)保存路徑是 node_modules/.cache/webpack。這里要注意每當(dāng)我們修改了webpack配置,記得更新cache的version,否則可能會(huì)出現(xiàn)因?yàn)橹赜昧司彺鎸?dǎo)致配置沒(méi)生效的問(wèn)題。

綜上,最后代碼修改如下:

  cache: {
    type: 'filesystem',
    version: '3.8.1',
  },
  optimization: {
    ...
    minimizer: [
      new TerserPlugin({
        parallel: true,
        terserOptions: {
          mangle: false, // Note `mangle.properties` is `false` by default.
        },
      }),
    ],
    ...
  }

fork-ts-checker-webpack-plugin語(yǔ)法報(bào)錯(cuò)

Invalid configuration object. ForkTsCheckerWebpackPlugin has been initialized using a configuration object that does not match the API schema.
 - configuration has an unknown property 'reportFiles'. These properties are valid:
   object { async?, typescript?, formatter?, issue?, logger?, devServer? }

fork-ts-checker-webpack-plugin 是在單獨(dú)的進(jìn)程上運(yùn)行 TypeScript 類型檢查器的 Webpack 插件。當(dāng)文件發(fā)生改動(dòng)需要重新轉(zhuǎn)譯和類型檢查時(shí),fork-ts-checker-webpack-plugin會(huì)開辟一個(gè)單獨(dú)的進(jìn)程去執(zhí)行類型檢查的任務(wù),這樣就不會(huì)影響 webpack 重新編譯的速度。

原來(lái)的配置:

plugins: [
  new ForkTsCheckerWebpackPlugin({
      memoryLimit: 4096,
      tsconfig: PATH.appDirectory + '/tsconfig.json',
      checkSyntacticErrors: true,
      reportFiles: [`${PATH.appSrc}/**/*.{ts,tsx}`],
    }),
]

fork-ts-checker-webpack-plugin從 4.1.3 升級(jí)到 7.2.11 ,這個(gè)plugin的API已經(jīng)發(fā)生了改變。改成:

plugins: [
  new ForkTsCheckerWebpackPlugin({
      typescript: {
        memoryLimit: 4096,
        configFile: PATH.appDirectory + '/tsconfig.json',
        diagnosticOptions: { syntactic: false, semantic: false, declaration: false, global: false }
      },
    }),
]

diagnosticOptions選項(xiàng)用來(lái)設(shè)置哪些TypeScript語(yǔ)法需要檢查。

IgnorePlugin報(bào)錯(cuò)

Invalid options object. Ignore Plugin has been initialized using an options object that does not match the API schema.
 - options should be one of these:
   object { resourceRegExp, contextRegExp? } | object { checkResource }
   Details:
    * options misses the property 'resourceRegExp'. Should be:
      RegExp
      -> A RegExp to test the request against.
    * options misses the property 'checkResource'. Should be:
      function
      -> A filter function for resource and context.

IgnorePlugin的作用是忽略第三包指定目錄,讓這些指定目錄不要被打包進(jìn)去。比如moment包的locale文件夾包括了各國(guó)語(yǔ)言的目錄,如果把所有語(yǔ)言都打包進(jìn)去就會(huì)影響打包效率。

原來(lái)的配置:

new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)

從報(bào)錯(cuò)來(lái)看,該plugin的語(yǔ)法發(fā)生了改變。改成:

new webpack.IgnorePlugin({
  resourceRegExp: /^\.\/locale$/,
  contextRegExp: /moment/,
})

devtool報(bào)錯(cuò)

Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
 - configuration.devtool should match pattern "^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$".
   BREAKING CHANGE since webpack 5: The devtool option is more strict.
   Please strictly follow the order of the keywords in the pattern.

大概的意思是說(shuō):檢查devtool的匹配,webpack5要求的匹配更嚴(yán)格。

原來(lái)的配置:

devtool: isEnvDevelopment ? 'cheap-module-eval-source-map' : false,

改成:

devtool: isEnvDevelopment ? 'eval-cheap-module-source-map' : false,

webpack-dev-server publicPath報(bào)錯(cuò)

Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'publicPath'. These properties are valid:
   object { allowedHosts?, bonjour?, client?, compress?, devMiddleware?, headers?, historyApiFallback?, host?, hot?, http2?, https?, ipc?, liveReload?, magicHtml?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, port?, proxy?, setupExitSignals?, static?, watchFiles?, webSocketServer? }

這次webpack-dev-server從 "^3.11.2" 升級(jí)到了 "^4.9.0"。

publicPath用來(lái)設(shè)置項(xiàng)目跑在本地時(shí),打包生成的文件所在的位置。

原來(lái)的配置:

devServer: {
    ...
    publicPath: appConfig.publicPath,
    ...
},

改成:

devServer: {
    ...
    devMiddleware: {
      publicPath: appConfig.publicPath,
    },
    ...
  },

webpack-dev-server contentBase報(bào)錯(cuò)

Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'contentBase'. These properties are valid:
   object { allowedHosts?, bonjour?, client?, compress?, devMiddleware?, headers?, historyApiFallback?, host?, hot?, http2?, https?, ipc?, liveReload?, magicHtml?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, port?, proxy?, setupExitSignals?, static?, watchFiles?, webSocketServer? }

contentBase用來(lái)設(shè)置項(xiàng)目跑在本地時(shí),不由webpack打包生成的文件的位置。

原來(lái)的配置:

devServer: {
    ...
    contentBase: PATH.appDirectory,
    ...
  },

devServer的v4中contentBase遷移到了static下,并且static的默認(rèn)值是path.resolve(process.cwd(), 'public') 。改成:

devServer: {
    ...
    static: [
      {
        directory: PATH.appDirectory,
      },
    ],
    ...
  },

webpack-dev-server disableHostCheck報(bào)錯(cuò)

Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'disableHostCheck'. These properties are valid:
   object { allowedHosts?, bonjour?, client?, compress?, devMiddleware?, headers?, historyApiFallback?, host?, hot?, http2?, https?, ipc?, liveReload?, magicHtml?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, port?, proxy?, setupExitSignals?, static?, watchFiles?, webSocketServer? }

原來(lái)的配置:

devServer: {
    ...
    disableHostCheck: true,
    ...
  },

改成:

devServer: {
    ...
    allowedHosts: "all",
    ...
  },

移除 node.js polyfill

Module not found: Error: Can't resolve 'crypto' in '/xxx/node_modules/crypto-js'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
    - add a fallback 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }'
    - install 'crypto-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
    resolve.fallback: { "crypto": false }

webpack5 以前,webpack 會(huì)包含 nodejs 核心模塊的 polyfill,這樣的話,比如安裝了一個(gè)crypto模塊,那么就可以直接使用,因?yàn)?node 的polyfill會(huì)自動(dòng)啟動(dòng)?,F(xiàn)在,webpack5 移除了 nodejs 的 polyfill,無(wú)法再直接使用類似crypto的模塊了。

如果你想要使用類似crypto的 nodejs 核心模塊,有兩種方法:

1.在 webpack 配置文件的resolve中配置fallback

module.exports = {
    ...
    resolve: {
        fallback:  {
            "crypto": require.resolve("crypto-browserify"), // 如果不需要,那么就直接改為 false 就可以了
        }
    }
}

2.如果覺(jué)得上面的方法很麻煩,那么可以使用node-polyfill-webpack-plugin:

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')

{
  ...
  plugins: [
    ...
    new NodePolyfillPlugin(),
    ...
  ]
}

導(dǎo)入json文件語(yǔ)法改變

export 'orderLimit'.'group_ids'.'includes' (imported as 'orderLimit') was not found in '../../../custom.config.json' (possible exports: 0, 1, 2)

原來(lái):

// custom.config.json
{
  "orderLimit": {
    "group_ids": ["xxx"],
    "desc": ["xxx"]
  }
}

// 原來(lái)引用文件方式
import { orderLimit } from '../../../custom.config.json'

改成:

import orderLimit from '../../../custom.config.json'

打包報(bào)錯(cuò)unknown option ‘-p’

[webpack-cli] Error: Unknown option '-p'

原本的打包命令文件:

shellExec(
  'webpack -p --color --config ' + require.resolve('../config/webpack.config'),
)

改成如下:

shellExec(
  'webpack --mode production --color --config ' + require.resolve('../config/webpack.config'),
)

node版本過(guò)低

eslint@8.15.0: The engine "node" is incompatible with this module. Expected version "^12.22.0 || ^14.17.0 || >=16.0.0". Got "14.15.4"

項(xiàng)目跑CI的時(shí)候報(bào)錯(cuò)說(shuō)CI的node鏡像版本偏低了?,F(xiàn)在eslint要求的node版本是16以上,但是公司node版本是14。于是找負(fù)責(zé)運(yùn)維的同事升級(jí)了node版本。

圖片編譯問(wèn)題

原來(lái)的配置:

          {
            test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
            loader: require.resolve('url-loader'),
            options: {
              limit: 10000,
              name: 'media/image/[name].[hash:8].[ext]',
            },
          },

之前處理圖片用的是url-loader。如果圖片比較小那么會(huì)被編譯成base64的格式,然后和項(xiàng)目代碼打包在一起;如果是比較大的圖片則會(huì)放在build/media/image文件夾下。然而升級(jí)到webpack5以后出現(xiàn)了下面的情況:

圖片除了按要求放在build/media/image文件夾下,竟然還多存了一份直接放在了build文件夾下。而且項(xiàng)目代碼中圖片的引用路徑指向了這些放錯(cuò)位置的圖片,但是這些圖片的格式是錯(cuò)誤的,根本顯示不了圖像。

在網(wǎng)上查了一下,上面的現(xiàn)象是因?yàn)閣ebpack5已經(jīng)自帶了圖片解析功能,再使用url-loader的話會(huì)出現(xiàn)圖片重復(fù)打包的問(wèn)題?,F(xiàn)在有兩種解決方案:

1.繼續(xù)使用使用url-loader。

2.改用webpack5自身來(lái)解析圖片

          {
            test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
            type: 'asset',
            parser: {
              dataUrlCondition: {
                maxSize: 10000,
              },
            },
            generator: {
              filename: 'media/image/[name].[hash:8].[ext]',
            },
          },

看了一下npm,url-loader已經(jīng)兩年沒(méi)有更新了。穩(wěn)妥起見,還是webpack自帶的圖片解析吧。

打包文件命名問(wèn)題

webpack4的時(shí)候,代碼編譯后的文件夾命名是按順序自增的數(shù)字id:

這樣就存在一個(gè)問(wèn)題,如果命名排在前面的模塊被移除了,那么后面的模塊就會(huì)補(bǔ)位,這會(huì)導(dǎo)致即使后續(xù)模塊內(nèi)容沒(méi)有發(fā)生變化,但是因?yàn)槲募A名稱發(fā)生了改變,之前的緩存就會(huì)失效了。

現(xiàn)在webpack5讓開發(fā)者可以自己設(shè)置chunk和module的命名方式:

optimization: {
  chunkIds: 'named', // 'natural' | 'named' | 'size' | 'deterministic'
  moduleIds: 'named',
}
  • natural 就是webpack5以前生產(chǎn)模式下的命名方式。
  • named 是根據(jù)項(xiàng)目文件路徑生成名稱,webpack以前和現(xiàn)在的開發(fā)環(huán)境模式默認(rèn)使用這種命名方式
  • size 是根據(jù)模塊大小來(lái)生成數(shù)字。
  • deterministic 是webpack5新增的命名方式,根據(jù)文件名稱生成短hash,webpack5生產(chǎn)模式下默認(rèn)啟用。

廢棄了ModuleConcatenationPlugin

項(xiàng)目打包完在線上運(yùn)行的時(shí)候出現(xiàn)了報(bào)錯(cuò):

Uncaught TypeError: Cannot read properties of undefined (reading 'call')

錯(cuò)的是這段代碼:

function __webpack_require__(moduleId) {
		var cachedModule = __webpack_module_cache__[moduleId]
		if (void 0 !== cachedModule) return cachedModule.exports
		var module = (__webpack_module_cache__[moduleId] = {
			id: moduleId,
			loaded: !1,
			exports: {},
		})
		return (
			__webpack_modules__[moduleId].call(
				module.exports,
				module,
				module.exports,
				__webpack_require__
			),
			(module.loaded = !0),
			module.exports
		)
	}

webpack實(shí)現(xiàn)了一個(gè)加載函數(shù) __webpack_require__(moduleId) 來(lái)加載模塊。這個(gè)函數(shù)做了這些事情:

  • 根據(jù)模塊Id在緩存中找是否有這個(gè)模塊,如果有直接從緩存拿
  • 如果緩存沒(méi)有,那么先新建這個(gè)模塊的緩存,然后再返回模塊

__webpack_modules__[moduleId].call() 會(huì)報(bào)錯(cuò)八成是因?yàn)閣ebpack找不到對(duì)應(yīng)模塊,__webpack_modules__[moduleId] 的結(jié)果是 undefined 。

順著控制臺(tái)列出來(lái)的報(bào)錯(cuò)文件繼續(xù)往下看,看看是哪里使調(diào)用了 __webpack_require__(moduleId)

    "./node_modules/@babel/runtime/helpers/esm/slicedToArray.js": function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
        "use strict";
       ...
        var arrayWithHoles = __webpack_require__(null);
        var unsupportedIterableToArray = __webpack_require__(null)
          , nonIterableRest = __webpack_require__(null);
        ...
    },

破案了,顯然 __webpack_require__(null) 是有問(wèn)題的。

在網(wǎng)上搜了一下,找到了解決方案:

之前公司webapck4的配置中,在生產(chǎn)環(huán)境會(huì)啟用 new webpack.optimize.ModuleConcatenationPlugin()

plugins: [
  !isEnvDevelopment && new webpack.optimize.ModuleConcatenationPlugin()
]

看了一下webpack的開發(fā)文檔,webpack在打包的時(shí)候會(huì)將各個(gè)模塊打包成閉包,用了ModuleConcatenationPlugin之后會(huì)盡可能將模塊放到一個(gè)閉包內(nèi),這樣會(huì)提升代碼在瀏覽器中的執(zhí)行速度。這種操作還有一個(gè)專業(yè)名詞,叫 Scope Hoisting,意思就是作用域提升。

不過(guò)現(xiàn)在ModuleConcatenationPlugin已經(jīng)廢棄了,把上面的代碼刪除以后,項(xiàng)目就能正常運(yùn)行了。

升級(jí)前后對(duì)比

 第一次打包第二次打包第三次打包打包體積
webpack4325.75s106.36s105.89s56.9MB
webpack5252.91s33.23s23.86s30.7MB

沒(méi)有緩存,且不保留之前打包的文件 

有緩存,但不保留之前打包的文件 

有緩存,且保留之前打包的文件 

總結(jié)

到此這篇關(guān)于webpack4升級(jí)到webpack5實(shí)戰(zhàn)經(jīng)驗(yàn)總結(jié)的文章就介紹到這了,更多相關(guān)webpack4升級(jí)到webpack5內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論