Angular 13项目用Webpack 5打包遇阻,求解决方案
Angular 13 + Webpack 5 打包问题解决方案
核心问题说明
升级Angular 6到Angular 13(搭配Webpack 5)时,出现错误:可注入对象'PlatformLocation'需通过JIT编译器编译,但'@angular/compiler'不可用。这是因为Angular 13默认启用AOT编译,若代码中存在触发JIT编译的场景(如动态创建组件、未正确配置AOT的依赖),但编译器未被正确引入或打包时就会触发该错误。
1. Webpack配置中异步加载Loader的实现方式
Webpack支持通过异步引入的方式加载loader,以下是两种适配方案:
方式一:ES Modules动态import()
修改webpack.config.js中的loader配置,以@ngtools/webpack为例:
{ test: /\.[jt]sx?$/, exclude: /node_modules/, use: [ async () => (await import('babel-loader')).default, async () => { const ngTools = await import('@ngtools/webpack'); return { loader: ngTools.AngularWebpackPlugin.loader, options: { directTemplateLoading: false } }; }, async () => (await import('@angular-devkit/build-optimizer/webpack-loader')).default ] }
方式二:CommonJS动态加载(兼容现有配置)
如果保持webpack.config.js为CommonJS格式,可使用回调式动态加载:
{ test: /\.[jt]sx?$/, exclude: /node_modules/, use: [ (loaderContext, callback) => { require.ensure([], (require) => { callback(null, require('babel-loader')); }); }, (loaderContext, callback) => { require.ensure([], (require) => { const ngTools = require('@ngtools/webpack'); callback(null, { loader: ngTools.AngularWebpackPlugin.loader, options: { directTemplateLoading: false } }); }); } ] }
2. Babel LinkerPlugin适配ES Modules与Node.js 14.20的解决方案
Node.js 14.20对ES Modules的支持存在部分限制,搭配Babel LinkerPlugin时需注意以下几点:
步骤1:配置Babel模块转换
安装@babel/plugin-transform-modules-commonjs,并在Babel配置中添加:
{ "plugins": ["@babel/plugin-transform-modules-commonjs"] }
步骤2:ES Modules格式webpack配置(改为.mjs后缀)
将webpack.config.js重命名为webpack.config.mjs,正确引入LinkerPlugin:
import { LinkerPlugin } from '@angular/compiler-cli/linker/babel'; export default async () => { const config = { // ... 现有配置 module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: [LinkerPlugin] } } } ] } }; // ... 环境判断逻辑 return config; };
步骤3:Node.js运行兼容配置
在package.json的scripts中添加ES Modules兼容参数:
"start": "node --experimental-specifier-resolution=node webpack-dev-server --open --config webpack.config.mjs --progress --port 8080"
3. PlatformLocation错误补充修复
针对核心报错,还需调整以下配置:
- 在webpack entry中显式引入@angular/compiler:
entry: { 'polyfills': './src/polyfills.ts', 'app': './src/main.ts', 'compiler': '@angular/compiler' } - 修改tsconfig.json的module配置为
esnext,提升ES Modules兼容性:"compilerOptions": { "module": "esnext", // ... 其他配置 }
相关配置文件
package.json
{"name":"my-webpack-project","version":"1.0.0","scripts":{"path":"webpack-dev-server --version","path2":"webpack --version","ng":"ng","start":"webpack-dev-server --open --config webpack.config.js --progress --port 8080","build":"webpack --mode=production --node-env=production","watch":"webpack --watch","test":"ng test","build:dev":"webpack --mode=development","build:prod":"webpack --mode=production --node-env=production","serve":"webpack serve"},"private":true,"dependencies":{"@angular-devkit/build-optimizer":"^0.1302.1","@angular/animations":"~13.4.0","@angular/common":"~13.4.0","@angular/compiler":"~13.4.0","@angular/core":"~13.4.0","@angular/forms":"~13.4.0","@angular/platform-browser":"~13.4.0","@angular/platform-browser-dynamic":"~13.4.0","@angular/router":"~13.4.0","@ngtools/webpack":"^13.3.11","@types/ws":"8.5.4","html-loader":"^4.2.0","rxjs":"~7.5.0","tsimportlib":"^0.0.5","tslib":"^2.3.0","zone.js":"~0.11.4"},"devDependencies":{"@angular-devkit/build-angular":"~13.3.11","@angular/cli":"~13.3.11","@angular/compiler-cli":"~13.4.0","@babel/core":"^7.22.9","@babel/preset-env":"^7.22.9","@types/jasmine":"~3.10.0","@types/node":"^12.11.1","@webpack-cli/generators":"^3.0.7","babel-loader":"^9.1.3","css-loader":"^6.8.1","html-webpack-plugin":"^5.5.3","jasmine-core":"~4.0.0","karma":"~6.3.0","karma-chrome-launcher":"~3.1.0","karma-coverage":"~2.1.0","karma-jasmine":"~4.0.0","karma-jasmine-html-reporter":"~1.7.0","prettier":"^3.0.0","sass":"^1.63.6","sass-loader":"^13.3.2","style-loader":"^2.0.0","ts-loader":"^9.4.4","typescript":"4.4.4","webpack":"5.76.1","webpack-cli":"^5.1.4","webpack-dev-server":"^4.15.1"},"description":"My webpack project"}
tsconfig.json
{"compileOnSave":false,"compilationMode":"partial","compilerOptions":{"resolveJsonModule":false,"baseUrl":"./","outDir":"./dist/out-tsc","importHelpers":true,"sourceMap":true,"allowSyntheticDefaultImports":true,"noImplicitAny":true,"module":"es6","target":"es5","allowJs":true,"moduleResolution":"node","experimentalDecorators":true,"lib":["es2018","dom"]},"files":["src/main.ts","src/polyfills.ts"]}
webpack.config.js
// Generated using webpack-cli https://github.com/webpack/webpack-cli const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ngToolsWebpack = require('@ngtools/webpack'); const dynamicImport = require('tsimportlib'); const isProduction = process.env.NODE_ENV == 'production'; const config = { entry: { 'polyfills': './src/polyfills.ts', 'app': './src/main.ts', }, output: { path: path.resolve(__dirname, 'dist'), filename: "[name].js" }, devtool: "source-map", devServer: { open: true, host: 'localhost', historyApiFallback: true }, plugins: [ new ngToolsWebpack.AngularWebpackPlugin({ tsConfigPath: './tsconfig.json' // entryModule: helpers.root('src/app/app.module#AppModule'), // sourceMap: false, }), new HtmlWebpackPlugin({ template: './src/index.html', inject: 'body' }), // Add your plugins here // Learn more about plugins from https://webpack.js.org/configuration/plugins/ ], module: { rules: [ { test: /\.html$/, use: 'html-loader' }, { test: /\.css$/i, use: ['style-loader', 'css-loader'], }, { test: /\.s[ac]ss$/i, use: ['style-loader', 'css-loader', 'sass-loader'], }, { test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i, type: 'asset', }, { // Regular rule for all non-library files test: /\.[jt]sx?$/, exclude: /node_modules/, use: [ {loader: 'babel-loader'}, // Optional { loader: '@ngtools/webpack', // Required options: { directTemplateLoading: false, // See https://www.npmjs.com/package/@ngtools/webpack } }, {loader: '@angular-devkit/build-optimizer/webpack-loader'}, // Optional ] }, // Add your rules for custom modules here // Learn more about loaders from https://webpack.js.org/loaders/ ], }, resolve: { extensions: ['.tsx', '.ts', '.jsx', '.js', '...'], }, }; module.exports = () => { if (isProduction) { config.mode = 'production'; } else { config.mode = 'development'; } return config; };
内容的提问来源于stack exchange,提问作者iamcootis
相关产品推荐
相关产品推荐

