angular 8 降级模块的 AoT 编译
AoT compilation for angular 8 downgraded module
在我的 Angular 项目构建中,由 gulp 完成,我需要设置一个混合 angular 应用程序。
目前,我通过以下方式使用 webpack 进行操作:
gulp 运行 webpack 并将它的包注入 dist
文件夹 以前 由 gulp 生成。
我的 webpack 配置:
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: path.resolve(__dirname, './src/main/app/app.module.angular.ts'),
output: {
filename: 'webpack.bundle.js'
},
module: {
rules: [
{ test: /\.ts?$/, use: 'ts-loader', exclude: '/node_modules/' },
{ test: /\.html?$/, use: 'raw-loader' }
]
},
resolve: { extensions: ['.ts', '.js'] },
plugins: [
new htmlWebpackPlugin({
template: '.' + outputPath + 'index.html',
inject: false // <script> reference already in file
})
],
optimization: {
minimize: false
}
};
我的gulp启动webpack的任务:
gulp.task('main-webpack', (done) => {
return gulp.src(path.join(paths.src, '/**/*.ts'))
.pipe(webpackStream(require('../webpack.main.config.js'), webpack))
.on('error', (err) => {
gutil.log('WEBPACK ERROR', err);
})
.pipe(gulp.dest(gulp.paths.serve.main));
});
我的 angular 降级模块是这样定义和引导的:
@NgModule({
imports: [
BrowserModule,
CommonModule,
HttpClientModule,
TranslateModule.forRoot()
],
declarations: COMPONENTS,
entryComponents: COMPONENTS,
providers: [...]
})
export class MainAppModule {
constructor() { }
ngDoBootstrap(){} // required to start hybrid app
}
const bootstrapFn = (extraProviders: StaticProvider[]) => {
const platformRef = platformBrowserDynamic(extraProviders);
return platformRef.bootstrapModule(MainAppModule);
};
const MainAngularDowngradedModule = angular
.module(
'app.angular',
[ downgradeModule(bootstrapFn)]
);
之后,我将 'app.angular'
添加为 angularjs 应用程序根模块的依赖项,一切正常。
但我想通过使用 AoT 编译从捆绑包中删除 angular 编译器。
我尝试使用 https://www.npmjs.com/package/@ngtools/webpack
使用以下 webpack 配置:
mode: 'production',
devtool: false,
entry: path.resolve(__dirname, './src/main/app/app.module.angular.ts'),
output: { filename: 'webpack.bundle.js' },
module: {
rules: [
{ test: /\.ts?$/, use: '@ngtools/webpack' },
{ test: /\.html?$/, use: 'raw-loader' }
]
},
resolve: { extensions: ['.ts', '.js'] },
plugins: [
new htmlWebpackPlugin({
template: '.' + outputPath + 'index.html',
inject: false
}),
new AngularCompilerPlugin({
mainPath: './src/main/app/app.module.angular.ts',
tsConfigPath: './tsconfig.json',
})
],
optimization:{
minimize: false,
noEmitOnErrors: true,
}
当我从上面的配置开始时,我得到这个错误:
angular.js:13920 Error: No NgModule metadata found for 'MainAppModule'.
at NgModuleResolver.resolve (https://localhost:8080/main/webpack.bundle.js:53749:23)
at CompileMetadataResolver.getNgModuleMetadata (https://localhost:8080/main/webpack.bundle.js:52856:43)
at JitCompiler._loadModules (https://localhost:8080/main/webpack.bundle.js:59037:51)
at JitCompiler._compileModuleAndComponents (https://localhost:8080/main/webpack.bundle.js:59018:36)
at JitCompiler.compileModuleAsync (https://localhost:8080/main/webpack.bundle.js:58978:37)
at CompilerImpl.compileModuleAsync (https://localhost:8080/main/webpack.bundle.js:107707:31)
at compileNgModuleFactory__PRE_R3__ (https://localhost:8080/main/webpack.bundle.js:27322:21)
at PlatformRef.bootstrapModule (https://localhost:8080/main/webpack.bundle.js:27536:16)
at app_module_angular_bootstrapFn (https://localhost:8080/main/webpack.bundle.js:110384:24)
at Object.<anonymous> (https://localhost:8080/main/webpack.bundle.js:109133:26) <shop1 class="ng-scope">
此外,组件定义中的模板引用在不同的 weboack 设置中工作不一样:
jit 设置需要:
template: require('./shop.component.html').default;
而 aot 适用于:
templateUrl: './shop.component.html'
如何解决上述错误?
有没有办法让 jit 和 aot 共存而不需要对每个组件做重大修改?
谢谢
抱歉问题太长:)
我最终通过将应用模块从主模块中分离出来解决了这个问题,有 main.ts 和 main.aot.ts 文件,它们只是设置降级模块并导入 AppModule。
main.aot.ts 看起来像这样:
import 'reflect-metadata';
import * as angular from 'angular';
import { platformBrowser } from '@angular/platform-browser';
// in main.ts: import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { NgModule, StaticProvider, Inject } from '@angular/core';
import { downgradeModule } from '@angular/upgrade/static';
import { MainAppModuleNgFactory } from './app/app.module.angular.ngfactory';
// in main.ts: import { MainAppModule } from './app/app.module.angular';
enableProdMode(); // not present in main.ts
const bootstrapFn = (extraProviders: StaticProvider[]) => {
const platformRef = platformBrowser(extraProviders);
return platformRef.bootstrapModuleFactory(MainAppModuleNgFactory);
};
const MainAngularDowngradedModule = angular
.module( 'app.angular', [ downgradeModule(bootstrapFn)] );
aot 的 webpack 配置也如下所示:
module.exports = {
mode: 'production',
devtool: false,
entry: path.resolve(__dirname, './src/main/main.aot.ts'),
output: {
filename: 'webpack.bundle.js'
},
module: {
rules: [
{
test: /\.ts?$/,
use: '@ngtools/webpack',
exclude: [
/node_modules/,
path.resolve(__dirname, './src/main/main.ts'),
]
},{
test: /\.html?$/,
use: 'raw-loader',
},{
test: /\.scss?$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
},
resolve: {
extensions: ['.ts', '.js']
},
plugins: [
new AngularCompilerPlugin({
entryModule: path.resolve(__dirname, './src/main/main.aot.ts#MainAppModule'),
tsConfigPath: './tsconfig.aot.json',
}),
],
optimization:{
minimize: true,
noEmitOnErrors: true,
}
};
最后,gulp 任务如下所示:
gulp.task('bundle:main-webpack', function(){
const config = (conf.env === ENVIRONMENTS.PRODUCTION || conf.env === ENVIRONMENTS.STAGING)
? '../webpack.prod.config.js'
: '../webpack.main.config.js';
return gulp.src(paths.src + '/**/*.ts')
.pipe(webpackStream(require(config), webpack))
.on('error', (err) => {
gutil.log('WEBPACK ERROR', err);
})
.pipe(gulp.dest(paths.dist + '/main'));
});
此设置仍有一些 space 可优化,但至少不会失败 :)
在我的 Angular 项目构建中,由 gulp 完成,我需要设置一个混合 angular 应用程序。
目前,我通过以下方式使用 webpack 进行操作:
gulp 运行 webpack 并将它的包注入 dist
文件夹 以前 由 gulp 生成。
我的 webpack 配置:
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: path.resolve(__dirname, './src/main/app/app.module.angular.ts'),
output: {
filename: 'webpack.bundle.js'
},
module: {
rules: [
{ test: /\.ts?$/, use: 'ts-loader', exclude: '/node_modules/' },
{ test: /\.html?$/, use: 'raw-loader' }
]
},
resolve: { extensions: ['.ts', '.js'] },
plugins: [
new htmlWebpackPlugin({
template: '.' + outputPath + 'index.html',
inject: false // <script> reference already in file
})
],
optimization: {
minimize: false
}
};
我的gulp启动webpack的任务:
gulp.task('main-webpack', (done) => {
return gulp.src(path.join(paths.src, '/**/*.ts'))
.pipe(webpackStream(require('../webpack.main.config.js'), webpack))
.on('error', (err) => {
gutil.log('WEBPACK ERROR', err);
})
.pipe(gulp.dest(gulp.paths.serve.main));
});
我的 angular 降级模块是这样定义和引导的:
@NgModule({
imports: [
BrowserModule,
CommonModule,
HttpClientModule,
TranslateModule.forRoot()
],
declarations: COMPONENTS,
entryComponents: COMPONENTS,
providers: [...]
})
export class MainAppModule {
constructor() { }
ngDoBootstrap(){} // required to start hybrid app
}
const bootstrapFn = (extraProviders: StaticProvider[]) => {
const platformRef = platformBrowserDynamic(extraProviders);
return platformRef.bootstrapModule(MainAppModule);
};
const MainAngularDowngradedModule = angular
.module(
'app.angular',
[ downgradeModule(bootstrapFn)]
);
之后,我将 'app.angular'
添加为 angularjs 应用程序根模块的依赖项,一切正常。
但我想通过使用 AoT 编译从捆绑包中删除 angular 编译器。
我尝试使用 https://www.npmjs.com/package/@ngtools/webpack
使用以下 webpack 配置:
mode: 'production',
devtool: false,
entry: path.resolve(__dirname, './src/main/app/app.module.angular.ts'),
output: { filename: 'webpack.bundle.js' },
module: {
rules: [
{ test: /\.ts?$/, use: '@ngtools/webpack' },
{ test: /\.html?$/, use: 'raw-loader' }
]
},
resolve: { extensions: ['.ts', '.js'] },
plugins: [
new htmlWebpackPlugin({
template: '.' + outputPath + 'index.html',
inject: false
}),
new AngularCompilerPlugin({
mainPath: './src/main/app/app.module.angular.ts',
tsConfigPath: './tsconfig.json',
})
],
optimization:{
minimize: false,
noEmitOnErrors: true,
}
当我从上面的配置开始时,我得到这个错误:
angular.js:13920 Error: No NgModule metadata found for 'MainAppModule'.
at NgModuleResolver.resolve (https://localhost:8080/main/webpack.bundle.js:53749:23)
at CompileMetadataResolver.getNgModuleMetadata (https://localhost:8080/main/webpack.bundle.js:52856:43)
at JitCompiler._loadModules (https://localhost:8080/main/webpack.bundle.js:59037:51)
at JitCompiler._compileModuleAndComponents (https://localhost:8080/main/webpack.bundle.js:59018:36)
at JitCompiler.compileModuleAsync (https://localhost:8080/main/webpack.bundle.js:58978:37)
at CompilerImpl.compileModuleAsync (https://localhost:8080/main/webpack.bundle.js:107707:31)
at compileNgModuleFactory__PRE_R3__ (https://localhost:8080/main/webpack.bundle.js:27322:21)
at PlatformRef.bootstrapModule (https://localhost:8080/main/webpack.bundle.js:27536:16)
at app_module_angular_bootstrapFn (https://localhost:8080/main/webpack.bundle.js:110384:24)
at Object.<anonymous> (https://localhost:8080/main/webpack.bundle.js:109133:26) <shop1 class="ng-scope">
此外,组件定义中的模板引用在不同的 weboack 设置中工作不一样:
jit 设置需要:
template: require('./shop.component.html').default;
而 aot 适用于:
templateUrl: './shop.component.html'
如何解决上述错误? 有没有办法让 jit 和 aot 共存而不需要对每个组件做重大修改?
谢谢 抱歉问题太长:)
我最终通过将应用模块从主模块中分离出来解决了这个问题,有 main.ts 和 main.aot.ts 文件,它们只是设置降级模块并导入 AppModule。 main.aot.ts 看起来像这样:
import 'reflect-metadata';
import * as angular from 'angular';
import { platformBrowser } from '@angular/platform-browser';
// in main.ts: import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { NgModule, StaticProvider, Inject } from '@angular/core';
import { downgradeModule } from '@angular/upgrade/static';
import { MainAppModuleNgFactory } from './app/app.module.angular.ngfactory';
// in main.ts: import { MainAppModule } from './app/app.module.angular';
enableProdMode(); // not present in main.ts
const bootstrapFn = (extraProviders: StaticProvider[]) => {
const platformRef = platformBrowser(extraProviders);
return platformRef.bootstrapModuleFactory(MainAppModuleNgFactory);
};
const MainAngularDowngradedModule = angular
.module( 'app.angular', [ downgradeModule(bootstrapFn)] );
aot 的 webpack 配置也如下所示:
module.exports = {
mode: 'production',
devtool: false,
entry: path.resolve(__dirname, './src/main/main.aot.ts'),
output: {
filename: 'webpack.bundle.js'
},
module: {
rules: [
{
test: /\.ts?$/,
use: '@ngtools/webpack',
exclude: [
/node_modules/,
path.resolve(__dirname, './src/main/main.ts'),
]
},{
test: /\.html?$/,
use: 'raw-loader',
},{
test: /\.scss?$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
},
resolve: {
extensions: ['.ts', '.js']
},
plugins: [
new AngularCompilerPlugin({
entryModule: path.resolve(__dirname, './src/main/main.aot.ts#MainAppModule'),
tsConfigPath: './tsconfig.aot.json',
}),
],
optimization:{
minimize: true,
noEmitOnErrors: true,
}
};
最后,gulp 任务如下所示:
gulp.task('bundle:main-webpack', function(){
const config = (conf.env === ENVIRONMENTS.PRODUCTION || conf.env === ENVIRONMENTS.STAGING)
? '../webpack.prod.config.js'
: '../webpack.main.config.js';
return gulp.src(paths.src + '/**/*.ts')
.pipe(webpackStream(require(config), webpack))
.on('error', (err) => {
gutil.log('WEBPACK ERROR', err);
})
.pipe(gulp.dest(paths.dist + '/main'));
});
此设置仍有一些 space 可优化,但至少不会失败 :)