I've got this somewhat old Angular web application which was updated from Angular 6 to Angular 12, however, Angular CLI is not being used for building it, instead it relies on Webpack 5, its loaders and AngularWebpackPlugin from @ngtools/webpack.
Recently, I needed to upgrade to a latest version of a library I was using and I got greeted with the following warning after my production build:
Uncaught Error: The injectable 'j' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.
The injectable is part of a library that has been partially compiled.
However, the Angular Linker has not processed the library such that JIT compilation is used as fallback.
Ideally, the library is processed using the Angular Linker to become fully AOT compiled.
Alternatively, the JIT compiler should be loaded by bootstrapping using '@angular/platform-browser-dynamic' or '@angular/platform-server',
or manually provide the compiler with 'import "@angular/compiler";' before bootstrapping.
After removing the minimizer and looking at the error stack trace in more detail, it appears to be an issue with that new library, specifically.
Now, I did some digging and found out that, since Angular 11.1, libraries can now be partially compiled for Ivy and shipped to NPM that way, not requiring ngcc. And, as expected, that library's source code indicates that, indeed, the major difference between the older version that I was using and the newer one that I am trying to use is that the newer one is partially compiled.
Now, my application's webpack configuration is as follows (I only left settings i consider relevant, if needed I can provide the entire configuration file):
module.exports = {
...
module: {
rules: [
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
loader: '@ngtools/webpack'
}
],
},
...
plugins: [
new CleanWebpackPlugin(),
new AngularWebpackPlugin({
tsconfig: './tsconfig-aot.json'
}),
new HtmlWebpackPlugin({
...
}),
new CopyWebpackPlugin({
patterns: [...]
})
]
};
My question is am I missing a step here? Is there a certain plugin i need to use to "link" the partially compiled libraries so I avoid this issue? Is it even possible to compile Angular application for production using Webpack in this way? I've tried a bunch of things, but everything points out to me missing a step in this entire process. Also, I created a test application using Angular CLI and used it to install the library and compile it using production mode and it all works like a charm so I can rule out the idea of it being the library creator's fault.
App dependencies are as follows:
"dependencies": {
"@angular/animations": "12.2.0",
"@angular/cdk": "^12.2.0",
"@angular/common": "12.2.0",
"@angular/compiler": "12.2.0",
"@angular/core": "12.2.0",
"@angular/forms": "12.2.0",
"@angular/platform-browser": "12.2.0",
"@angular/platform-browser-dynamic": "12.2.0",
"@angular/platform-server": "12.2.0",
"@angular/router": "12.2.0",
"@angular/upgrade": "12.2.0",
"@fullcalendar/core": "^5.9.0",
"angular-auth-oidc-client": "^12.0.2",
"angular-google-tag-manager": "^1.4.2",
"angular2-ladda": "^2.0.0",
"angular2-uuid": "1.1.1",
"core-js": "^3.16.1",
"headroom.js": "^0.12.0",
"ngx-google-places-autocomplete": "^2.0.5",
"ngx-headroom": "^1.0.6",
"primeicons": "^4.1.0",
"primeng": "^11.4.5",
"protractor": "^7.0.0",
"rxjs": "^6.6.7",
"tslib": "^2.3.0",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^12.2.0",
"@angular/cli": "12.2.0",
"@angular/compiler-cli": "^12.2.2",
"@ngtools/webpack": "^12.2.2",
"@types/core-js": "^2.5.5",
"@types/google.maps": "^3.45.6",
"@types/jasmine": "^3.8.2",
"@types/node": "10.11.7",
"angular-router-loader": "0.8.5",
"angular2-template-loader": "0.6.2",
"autoprefixer": "^9.8.6",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^6.4.1",
"css-loader": "^1.0.0",
"file-loader": "2.0.0",
"html-webpack-plugin": "^5.3.2",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine": "^3.8.0",
"jasmine-spec-reporter": "^5.0.2",
"jasmine-ts": "^0.4.0",
"karma": "^6.3.4",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.0.3",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^4.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
"karma-webpack": "^5.0.0",
"postcss-loader": "3.0.0",
"raw-loader": "0.5.1",
"rxjs-tslint": "^0.1.8",
"sass": "^1.37.5",
"sass-loader": "^10.2.0",
"source-map-loader": "^0.2.4",
"style-loader": "0.23.1",
"terser-webpack-plugin": "^4.2.3",
"ts-loader": "^8.3.0",
"ts-node": "^8.10.2",
"tslint": "^6.1.3",
"tslint-loader": "3.5.4",
"typescript": "^4.3.5",
"webpack": "^5.51.0",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.0.0"
}
Yes! You need to add the Angular Linker to process the problematic plugin. It's currently only available as a Babel plugin:
@angular/compiler-cli/linker/babel
In short, add this to your Webpack config and replace
ng-click-outside
with your plugin(s):Also, you should remove your old
@ngtools/webpack
rule. You no longer need to process 'ngfactory' or 'ngstyle' files in Angular 12.For more details, see my other SO answer here. Credit for the webpack config goes to Robert van Hoesel from this Github issue.