您现在的位置是:网站首页> 编程资料编程资料

webpack4升级到webpack5的实战经验总结_javascript技巧_

2023-05-24 347人已围观

简介 webpack4升级到webpack5的实战经验总结_javascript技巧_

前言

最近接手了公司内部webpack相关的依赖包,于是打算优化一波。考虑到webpack5已经正式发布近两年,跟webpack相关的依赖包应该适配的差不多了,于是打算先把webpack4升级到webpack5,然后基于webpack5再进行优化。

升级前用的是 "webpack": "^4.42.1" ,升级后用的是 "webpack": "^5.72.1"

笔者采用的升级webpack的方法是先一键升级所有的依赖包,然后一个一个地去解决运行过程中的报错。

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

yarn global add npm-check-updates 

然后在项目中执行 ncu -u ,这样项目的package.json会把所有的依赖包都更新到最新版本,然后执行 yarn 。升级完就可以开启漫长的debug之旅了。

terser-webpack-plugin语法报错

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? }

原来的配置:

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

从报错来看,terser-webpack-plugin的配置属性发生了改变,现在已经没有 cache 这个选项了。

terser-webpack-plugin是用来压缩JavaScript代码的。不过webpack5已经自带了terser-webpack-plugin,如果说你用的是webpack5或者更高版本,同时还希望自定义配置,那么还是需要安装terser-webpack-plugin。

webpack4的时候可以通过terser-webpack-plugin的cache属性开启文件缓存。现在webpack5自身提供了持久化缓存机制,它能够将首次打包的结果缓存到硬盘中,等下次打包的时候就可以跳过一系类的耗时的操作,复用第一次的打包结果。可以通过以下配置开启持久化缓存:

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

缓存默认保存路径是 node_modules/.cache/webpack。这里要注意每当我们修改了webpack配置,记得更新cache的version,否则可能会出现因为重用了缓存导致配置没生效的问题。

综上,最后代码修改如下:

 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语法报错

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 是在单独的进程上运行 TypeScript 类型检查器的 Webpack 插件。当文件发生改动需要重新转译和类型检查时,fork-ts-checker-webpack-plugin会开辟一个单独的进程去执行类型检查的任务,这样就不会影响 webpack 重新编译的速度。

原来的配置:

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 升级到 7.2.11 ,这个plugin的API已经发生了改变。改成:

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

diagnosticOptions选项用来设置哪些TypeScript语法需要检查。

IgnorePlugin报错

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的作用是忽略第三包指定目录,让这些指定目录不要被打包进去。比如moment包的locale文件夹包括了各国语言的目录,如果把所有语言都打包进去就会影响打包效率。

原来的配置:

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

从报错来看,该plugin的语法发生了改变。改成:

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

devtool报错

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.

大概的意思是说:检查devtool的匹配,webpack5要求的匹配更严格。

原来的配置:

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

改成:

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

webpack-dev-server publicPath报错

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" 升级到了 "^4.9.0"

publicPath用来设置项目跑在本地时,打包生成的文件所在的位置。

原来的配置:

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

改成:

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

webpack-dev-server contentBase报错

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用来设置项目跑在本地时,不由webpack打包生成的文件的位置。

原来的配置:

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

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

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

webpack-dev-server disableHostCheck报错

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? }

原来的配置:

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 会包含 nodejs 核心模块的 polyfill,这样的话,比如安装了一个crypto模块,那么就可以直接使用,因为 node 的polyfill会自动启动。现在,webpack5 移除了 nodejs 的 polyfill,无法再直接使用类似crypto的模块了。

如果你想要使用类似crypto的 nodejs 核心模块,有两种方法:

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

module.exports = { ... resolve: { fallback: { "crypto": require.resolve("cry
                
                

-六神源码网