私は、webpack、angular 4 でうまく機能し、最近 angular 5 に移動した大規模なプロジェクトと、改善された webpack 構成を持っています。「開発」ビルドは問題なくロードされます。
しかし、「プロダクション」ビルドはロードされ、「@NgModule アノテーションを追加してください」というメッセージが表示されて終了します。
そこで、mangle をオフにして、どのコンポーネントが問題を引き起こしているかを確認しました。そして、 import: [ ... ] @NgModule の array セクションの先頭にリストされているものはすべてリストされていることがわかりました。これはなぜですか?この素敵なエラーの原因は何ですか?
インポートの最初にリストされている最初のモジュールが常に見つからないのはなぜですか?
以下にリストされているバージョンでは、エラーは次のとおりです。
Uncaught Error: Unexpected value 'FormsModule' imported by the module 'AppModule'. Please add a @NgModule annotation.
以下は、いくつかの光を当てることを願っているプロジェクトのセクションです。
@NgModule({
bootstrap: [ AppComponent ],
declarations: COMPONENTS,
imports: [ // import Angular's modules
FormsModule,
ReactiveFormsModule,
HttpModule,
BrowserModule,
RouterModule.forRoot(ROUTES, { useHash: true, preloadingStrategy: PreloadAllModules }),
BsDropdownModule.forRoot(),
AlertModule.forRoot(),
DatepickerModule.forRoot(),
TooltipModule.forRoot(),
ModalModule.forRoot(),
LocalStorageModule.withConfig({
prefix: 'tracker',
storageType: 'localStorage'
}),
A2Edatetimepicker,
DndModule.forRoot(),
NgPipesModule,
ColorPickerModule
],
providers: [ // expose our Services and Providers into Angular's dependency injection
ENV_PROVIDERS,
APP_PROVIDERS,
{
provide: AuthHttp,
useFactory: (http: Http, localStorage: LocalStorageService) => {
let conf: AuthConfig;
conf = new AuthConfig({
tokenName: 'token',
tokenGetter: (() => {
const t = localStorage.get<any>('id_token');
// console.log(t);
return t;
}),
globalHeaders: [{'Content-Type': 'application/json'}],
});
return new AuthHttp(conf, http);
},
deps: [Http, LocalStorageService]
},
{
provide: SocketService,
useFactory: (broadcast: BroadCaster,
authHttp: AuthHttp) => {
return new SocketService(broadcast, authHttp);
},
deps: [BroadCaster, AuthHttp]
},
{
provide: ImportUserData,
useFactory: (authHttp: AuthHttp,
localStorage: LocalStorageService) => {
return new ImportUserData(authHttp, localStorage);
},
deps: [AuthHttp, LocalStorageService]
},
{
provide: AuthService,
useFactory: (http: Http,
authHttp: AuthHttp,
localStorage: LocalStorageService) => {
const as = new AuthService(http, authHttp, localStorage);
return as;
},
deps: [Http, AuthHttp, LocalStorageService]
},
{
provide: UserCondition,
useFactory: (authHttp: AuthHttp,
broadcast: BroadCaster,
localStorage: LocalStorageService,
sanitizer: DomSanitizer,
zone: NgZone) => {
return new UserCondition(authHttp, broadcast, localStorage, sanitizer, zone);
},
deps: [AuthHttp, BroadCaster, LocalStorageService, DomSanitizer, NgZone]
},
{
provide: ProfileComponent,
useFactory: (userCondtion: UserCondition,
sanitizer: DomSanitizer,
auth: AuthService) => {
return new ProfileComponent(userCondtion, sanitizer, auth);
},
deps: [UserCondition, DomSanitizer, AuthService]
},
{
provide: LogoutWarningComponent,
useFactory: (userCondtion: UserCondition,
broadcaster: BroadCaster,
versionS: Version,
auth: AuthService) => {
return new LogoutWarningComponent(userCondtion, broadcaster, versionS, auth);
},
deps: [UserCondition, BroadCaster, Version, AuthService]
},
]
})
export class AppModule implements OnDestroy {
private mVersion: string;
...
...
}
この問題を更新します。
数日後、私はかなりの進歩を遂げました。
また、この種の問題に遭遇した他の人を助けるかもしれないいくつかのことを学びました.
- webpack ビルドの製品版のほぼすべてのプラグインをコメント アウトします。
- 名前マングルをオフにします。
これを行った後、問題はプロジェクトの構成セクションの「プロダクション」設定から発生していることを知りました: angular-starter. 問題が表面化した場所は、「build-utils.js」ファイルでした。
const ts = require('typescript');
const path = require('path');
const fs = require('fs');
const helpers = require('./helpers');
const DEFAULT_METADATA = {
title: 'Tracker',
baseUrl: '/',
isDevServer: helpers.isWebpackDevServer(),
HMR: helpers.hasProcessFlag('hot'),
AOT: process.env.BUILD_AOT || helpers.hasNpmFlag('aot'),
E2E: !!process.env.BUILD_E2E,
WATCH: helpers.hasProcessFlag('watch'),
tsConfigPath: 'tsconfig.webpack.json',
/**
* This suffix is added to the environment.ts file, if not set the default environment file is loaded (development)
* To disable environment files set this to null
*/
envFileSuffix: ''
};
function supportES2015(tsConfigPath) {
if (!supportES2015.hasOwnProperty('supportES2015')) {
const tsTarget = readTsConfig(tsConfigPath).options.target;
supportES2015['supportES2015'] = tsTarget !== ts.ScriptTarget.ES3 && tsTarget !== ts.ScriptTarget.ES5;
}
return supportES2015['supportES2015'];
}
function readTsConfig(tsConfigPath) {
const configResult = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
return ts.parseJsonConfigFileContent(configResult.config, ts.sys,
path.dirname(tsConfigPath), undefined, tsConfigPath);
}
function getEnvFile(suffix) {
if (suffix && suffix[0] !== '.') {
suffix = '.' + suffix;
}
if (suffix === null) {
return;
}
let fileName = helpers.root(`src/environments/environment${suffix}.ts`);
if (fs.existsSync(fileName)) {
return fileName;
} else if (fs.existsSync(fileName = helpers.root('src/environments/environment.ts'))) {
console.warn(`Could not find environment file with suffix ${suffix}, loading default environment file`);
return fileName;
} else {
throw new Error('Environment file not found.')
}
}
/**
* Read the tsconfig to determine if we should prefer ES2015 modules.
* Load rxjs path aliases.
* https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#build-and-treeshaking
* @param supportES2015 Set to true when the output of typescript is >= ES6
*/
function rxjsAlias(supportES2015) {
try {
const rxjsPathMappingImport = supportES2015 ? 'rxjs/_esm2015/path-mapping' : 'rxjs/_esm5/path-mapping';
const rxPaths = require(rxjsPathMappingImport);
return rxPaths(helpers.root('node_modules'));
} catch (e) {
return {};
}
}
function ngcWebpackSetup(prod, metadata) {
if (!metadata) {
metadata = DEFAULT_METADATA;
}
// TURNED OFF THE buildOptimizer here:
// const buildOptimizer = prod;
const buildOptimizer = false;
const sourceMap = true; // TODO: apply based on tsconfig value?
const ngcWebpackPluginOptions = {
skipCodeGeneration: !metadata.AOT,
sourceMap
};
const environment = getEnvFile(metadata.envFileSuffix);
// console.log('environment:', environment);
if (environment) {
ngcWebpackPluginOptions.hostReplacementPaths = {
[helpers.root('src/environments/environment.ts')]: environment
}
}
if (!prod && metadata.WATCH) {
// Force commonjs module format for TS on dev watch builds.
ngcWebpackPluginOptions.compilerOptions = {
module: 'commonjs'
};
}
const buildOptimizerLoader = {
loader: '@angular-devkit/build-optimizer/webpack-loader',
options: {
sourceMap
}
};
const loaders = [
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: metadata.AOT && buildOptimizer ? [ buildOptimizerLoader, '@ngtools/webpack' ] : [ '@ngtools/webpack' ]
},
...buildOptimizer
? [ { test: /\.js$/, use: [ buildOptimizerLoader ] } ]
: []
];
console.log('loaders:', loaders);
// console.log('ngcWebpackPluginOptions:', ngcWebpackPluginOptions);
return {
loaders,
plugin: ngcWebpackPluginOptions
};
}
exports.DEFAULT_METADATA = DEFAULT_METADATA;
exports.supportES2015 = supportES2015;
exports.readTsConfig = readTsConfig;
exports.getEnvFile = getEnvFile;
exports.rxjsAlias = rxjsAlias;
exports.ngcWebpackSetup = ngcWebpackSetup;
ここで、上記の ngcWebpackSetup() 関数内で「buildOptimizer」を false に設定する必要がありました。欠点は、最小化されたコードが 3.59 MB から 4.04 MB に増えたことです。しかし、コードが読み込まれ、ブラウザで正しく実行されるようになりました!
ここで問題が何であるかを学び、報告し、「angular-starter」プロジェクトに修正を投稿することを願っています。