Angular6+Webpack4开发环境构建:组件参数无法全部解析
我正尝试使用Angular 6与Webpack 4搭建Webpack开发环境,编译成功后出现了「Can't resolve all parameters for Component」错误。以下是相关配置文件及代码:
相关配置文件与代码
webpack.config.common
var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/app/main.ts', resolve: { extensions: ['.js', '.ts'] }, module: { rules: [ { test: /\.html$/, loaders: ['html-loader'] }, { test: /\.css$/, loaders: ['raw-loader'] }, { test: /\.(jpe?g|png|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/, loader: ['url-loader?limit=100000'] } ], exprContextCritical: false }, plugins: [ new HtmlWebpackPlugin({ template: 'src/index.html' }) ] };
webpack.config.dev
var path = require('path'); var webpackMerge = require('webpack-merge'); var commonConfig = require('./webpack.config.common'); module.exports = webpackMerge(commonConfig, { devtool: 'cheap-module-eval-source-map', output: { path: path.resolve(__dirname, 'dist'), publicPath: '/', filename: 'bundle.js', chunkFilename: '[id].chunk.js' }, mode: 'development', module: { rules: [ { test: /\.ts$/, use: [ { loader: 'awesome-typescript-loader', options: { transpileOnly: true } }, { loader: 'angular2-template-loader' }, { loader: 'angular-router-loader' } ] } ] }, devServer: { historyApiFallback: true, stats: 'minimal' } });
tsconfig.json
{ "compilerOptions": { "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "lib": ["es5", "dom"] } }
MainComponent
import { User } from '../models/user.model'; import { Component, OnInit, ChangeDetectionStrategy, NgZone } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { UserService } from '../user.service'; import { PlatformLocation } from '@angular/common'; import { ConnectionService } from '../app/connection.service'; import { AlertMessageDialogComponent } from '../alertMessageDialog/alertmessagedialog.component'; import { MainService } from './main.service'; @Component({ selector: 'main', templateUrl: './main.component.html', styleUrls: ['./main.component.css'] }) export class MainComponent implements OnInit { private userClaims: User; ngOnInit(): void { // this.getUserDetailstoMain(); this.userService.getUserClaims().subscribe((data: any) => { this.userClaims = data; let NameArray = this.userClaims['User']['FullName'].split(' ', 2); this.globalItems.UserFirstName = NameArray[0]; this.globalItems.UserLastName = NameArray[1]; this.globalItems.UserPhoto = this.userClaims['User']['UserPhoto']; }); } constructor( private userService: UserService, private location: PlatformLocation, private router: Router, private connectionService: ConnectionService, private globalItems: MainService, private zone: NgZone ) {} logOut(event) { sessionStorage.clear(); this.zone.runOutsideAngular(() => { location.reload(); }); } }
package.json 脚本部分
{ "name": "cloud-crp", "version": "0.0.0", "license": "MIT", "main": "index.js", "angular-cli": {}, "scripts": { "ng": "ng", "start": "ng serve", "test": "ng test", "build": "webpack-dev-server --inline --progress --port 8080 --config webpack.config.dev.js", "build:prod": "del-cli dist && ngc -p tsconfig.aot.json && ngc -p tsconfig.aot.json && webpack --config webpack.config.prod.js --progress --profile --bail && del-cli 'src/app/**/*.js' 'src/app/**/*.ngfactory.ts' 'src/app/**/*.js.map' 'src/app/**/*.shim.ts' 'src/app/**/*.ngsummary.json' 'src/app/**/*.ngstyle.ts' 'dist/app' 'src/polyfills.ngsummary.json'", "clean": "del-cli dist && ngc -p tsconfig.aot.json && ngc -p tsconfig.aot.json && del-cli 'src/app/**/*.js' 'src/app/**/*.ngfactory.ts' 'src/app/**/*.js.map' 'src/app/**/*.shim.ts' 'src/app/**/*.ngsummary.json' 'src/app/**/*.ngstyle.ts' 'dist/app' 'src/polyfills.ngsummary.json'" } }
错误原因分析与解决方案
这个错误说白了就是Angular的依赖注入系统找不到组件构造函数里参数的对应依赖,核心问题出在元数据缺失或者Webpack配置没正确处理装饰器相关的元数据上。结合你的配置,我帮你梳理出几个关键问题和解决办法:
1. awesome-typescript-loader 的 transpileOnly: true 把元数据搞丢了
你给 awesome-typescript-loader 加了 transpileOnly: true,这个选项会让TypeScript只做代码转译,跳过类型检查和装饰器元数据的生成——而Angular的依赖注入恰恰需要这些元数据才能知道该注入什么服务。
解决办法:
要么直接删掉 transpileOnly: true 选项,要是你需要热重载的话,可以配合 @angularclass/hmr-loader 使用。修改 webpack.config.dev 里的TS loader配置:
{ test: /\.ts$/, use: [ { loader: 'awesome-typescript-loader' }, // 移除 transpileOnly 配置 { loader: 'angular2-template-loader' }, { loader: 'angular-router-loader' } ] }
2. 缺了 reflect-metadata 这个关键polyfill
Angular 6依赖 reflect-metadata 来处理装饰器的元数据,你大概率没在项目里引入它。
解决办法:
- 先装依赖:
npm install reflect-metadata --save - 然后在
src/main.ts的最开头加上:
import 'reflect-metadata';
3. 检查服务有没有在模块里注册
得确保 MainService、UserService、ConnectionService 这些服务都在对应的NgModule里声明成 providers 了。比如在根模块或者 MainComponent 所属的模块里:
import { NgModule } from '@angular/core'; import { MainComponent } from './main.component'; import { MainService } from './main.service'; import { UserService } from '../user.service'; import { ConnectionService } from '../app/connection.service'; @NgModule({ declarations: [MainComponent], providers: [MainService, UserService, ConnectionService] // 把服务加到这里 }) export class MainModule {}
4. 给 tsconfig.json 加个小优化
你的 tsconfig.json 已经开了 emitDecoratorMetadata 和 experimentalDecorators,这部分是对的,不过可以加个 skipLibCheck: true 避免第三方库的类型检查报错:
{ "compilerOptions": { "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "lib": ["es5", "dom"], "skipLibCheck": true } }
按照上面的步骤改完之后,重新跑 npm run build,应该就能解决这个参数解析错误啦!
内容的提问来源于stack exchange,提问作者saahaalaa

