Angular 5 webpack 3 aot
Asked Answered
R

2

10

I'm trying to make an aot build with webpack 3 and angular 5, but there are so many tutorials on the net and none show complete example without questions, so far I've got the following configuration: (For those who have questions about paths - I use it in the java app)

webpack.config.aot.js:

const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const ngToolsWebpack = require('@ngtools/webpack');

module.exports = {
    context: __dirname + "/src/main/webapp/resources/script/",
    entry: {
        app: "./core/main.aot.ts",
        vendor: "./vendor.ts",
        polyfills: "./polyfills.ts"
    },
    output: {
        filename: 'js/[name].js',
        chunkFilename: "js/chunks/[id].chunk.js",
        publicPath: "resources/compiled/",
        path: __dirname + '/src/main/webapp/resources/compiled'
    },
    resolve: {
        alias: {
            STYLES: __dirname + "/src/main/webapp/resources/css/",
            SCRIPT: __dirname + "/src/main/webapp/script/"
        },
        extensions: [".js", ".json", ".scss", ".ts"]
    },
    module: {
        rules: [
            {
                test: /[\/]angular\.js$/,
                loader: 'exports-loader?angular'
            },
            {
                test: /\.html$/,
                loader: 'raw-loader'
            },
            {
                test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
                loader: '@ngtools/webpack'
            }
        ]
    },
    plugins: [
        new ngToolsWebpack.AngularCompilerPlugin({
            tsConfigPath: './tsconfig.aot.json',
            entryModule: './src/main/webapp/resources/script/core/i18n/app.module.en#AppModule'
        })
    ]
};

tsconfig.aot.json:

{
  "compilerOptions": {
    "module": "es2015",
    "moduleResolution": "node",
    "target": "es5",
    "noImplicitAny": false,
    "sourceMap": true,
    "mapRoot": "",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "es2015",
      "dom"
    ],
    "outDir": "lib",
    "skipLibCheck": true,
    "rootDir": "."
  },
  "exclude": [
    "node_modules/*",
    "target/*"
  ],
  "angularCompilerOptions": {
    "genDir": "./src/main/webapp/resources/script/factory",
    "rootDir": ".",
    "baseUrl": "/"
  }
}

main.aot.ts:

import {platformBrowser} from '@angular/platform-browser';
import {enableProdMode} from "@angular/core";
import {AppModuleNgFactory} from '../factory/app/app.module.ngfactory';

enableProdMode();

platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

File structure(simplified):

- webpack.config.aot.js
- tsconfig.aot.js
- src/
  - main/
    - webapp/
      - resources/
        - script/
          - vendor.ts
          - polyfills.ts
          - core/
            - main.aot.ts
            - i18n/
              - app.module.en.ts

(Please let me know if I haven't showed something relevant)

So when I'm tring to build it using webpack -p --config ./webpack.config.aot.js

I get following error:

ERROR in src/main/webapp/resources/script/core/main.aot.ts(5,34): error TS2307: Cannot find module '../factory/app/app.module.ngfactory'.

Which sound pretty legitimate as there is no AppModuleNgFactory there, but as i looked in tutorials it is supposed to be generated upon aot build, using genDir, am I right? (please not that if i omit app/ folder, so path looks '../factory/app.module.ngfactory' i get the same error)

Is it right to point at the non-existing AppModuleNgFactory on the aot build with @ngtools/webpack?

What is that AppModuleNgFactory? There is little to no documentation about anythig of it on the angular site

What should I change in my config to successfully generate aot build?

If I change main file to bootstrap AppModule itself, it builds successfully, but in browser i get NullInjectorError: No provider for t! error

Without minification it shows: No provider for CompilerFactory!

Regenerative answered 18/11, 2017 at 10:57 Comment(5)
Are you aware of the existence of angular-cli, which would do all this, and much much more, for you, with just ng build -aot?Arapaima
@JBNizet Sure, but I believe that webpack gives more control and flexibility to the process, am I misguided?Regenerative
My guess is that you'll have all you need and more, instantly, by using the CLI (and accepting the way it works rather than fight against its way of doing). If you really have something that blocks you, then you can always use eject and customize its webpack configuration.Arapaima
Does this related question help? I had a working 4.x config under webpack, but couldn't get 5.x working until I read the answer from @ckapillaCatgut
The problem with Angular CLI is that it doesn't support externals. With webpack you have full control. Sometimes for some reason (customer demand) some Javascript bundles need to be made external for central maintenance.Selfpossession
R
2

It appears that @ngtools/webpack could handle bootstraping module factory itself from original main file, eg webpack entry should be : path_to_file/main.ts

and main.ts contains:

platformBrowserDynamic().bootstrapModule(AppModule);

And whole thing will be handled itself, no additional configs!

It is really amazing

Regenerative answered 24/11, 2017 at 8:53 Comment(1)
If you use platformBrowserDynamic it isn't really AoT. You can tell from package size and by using the webpack BundleAnalyzerPlugin. With platformBrowserDynamic my final build was about 7MB and I could see all the raw source files inside the BundleAnalyzerPlugin output. With platformBrowser it was about 400KB and my outputted bundle in BundleAnalyzerPlugin was a single js file (e.g. app.[hash].js)Gastroenterology
E
-3

I do not think the accepted answer is correct. I had the same problem and there were two reasons for my problem:

I had to include the module in my includes in tsconfig:

"include": [
  "ng/src/main/app.module.ts",
  "ng/src/main.aot.ts"
]

My include in main.aot.ts just referenced the source file but with ngfactory suffix:

import { MainModuleNgFactory } from './main/app.module.ngfactory';
Error answered 27/4, 2018 at 9:55 Comment(8)
Actually if you've read accepted answer correctly you would understand that what you're doing is overkill, angular handles ngfactory referencing himself, we could omit all that work that you've doneRegenerative
Do you have a reference to this? In your answer you are using platformBrowserDynamic where as you would need to use platformBrowser for aot?Error
npmjs.com/package/@angular/platform-browser platform-browser is very much part of Angular 5.Error
This question was created because I haven't found any reference about it. I am sure my solution is correct because it actually works. I don't see any logical connection between platform browser being part of angular and the necessity of using it in aot build. Perhaps it was so in previous versions, but now it works with platformBrowserDynamic. Create an angular cli project and see for yourself that it uses just the same approach as I did. Do you think guys from angular doing this wrong?Regenerative
When you use platformBrowserDynamic, you are not actually using AOT.Error
Here is one way to check if your project is actually using AOT: #42360134Error
There is more easier and generic way to check it, using BundleAnalyzerPlugin (or analogues), if you see no angular compiler - this is aot. And there is no angular compiler in my bundlesRegenerative
If you have a normal app.module.ts file it has no ngfactory member to export.Gastroenterology

© 2022 - 2024 — McMap. All rights reserved.