JIT compiler unavailable after angular update

ANGULAR 13+ UPDATE

In addition to the steps below, the Angular Linker must now be used to process all .mjs files created by the Angular compiler or you’ll see the JIT error again. See the Example Configuration.

Background

The JIT compiler unavailable error can occur when using an outdated plugin (i.e. one that still the uses View Engine instead of Ivy).

According to Google’s Building Libraries with Ivy guide, libraries can be distributed in 3 formats: View Engine (now deprecated), Partial-Ivy (recommended), and Full-Ivy.

Ivy apps can still consume the View Engine format with NGCC, but View Engine is slated to be removed in Angular 13, so library authors should use the “partial-Ivy” format moving forward. Here’s a deep dive about the change.

How To Fix (3 steps)

1. Identify the problematic plugin.

Important: If your TerserPlugin config uses ngDevMode: false, Angular will throw a generic JIT compiler unavailable error. Removing the flag (or using ngDevMode: true) should reveal a more useful error that mentions the plugin by name. If that doesn’t help, try my debugging tips at the end of the answer. Be sure to set ngDevMode back to false once the issue is fixed; it can have a large impact on bundle size.

2. Ask the library author to update the plugin’s tsconfig.prod.json file:

"angularCompilerOptions": {
   "enableIvy": false // Remove this line or use true
   "compilationMode": "partial" // Add this line
}

3. Consume the format by compiling the library using the Angular Linker, which is 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):

rules: [
{
  // Explicit rule to run the linker over partial libraries
  test: /.*\.js$/,
  include: /node_modules\/ng-click-outside/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        configFile: false,
        plugins: ['@angular/compiler-cli/linker/babel'], // Required!
      }
    }
  ]
},
{
  // Regular rule for all non-library files
  test: /\.[jt]sx?$/,
  exclude: /node_modules/,
  use: [
    {loader: 'babel-loader'}, // Optional
    {
      loader: '@ngtools/webpack', // Required
      options: {
        directTemplateLoading: false, // See https://www.npmjs.com/package/@ngtools/webpack
      }
    },
    {loader: '@angular-devkit/build-optimizer/webpack-loader'}, // Optional
  ]
},

Credit for the webpack config goes to Robert van Hoesel from this Github issue.

Debugging Tips

1. While debugging the problem, you can add import '@angular/compiler'; in your main.ts file (as the OP has done), but this will output the JIT compiler in your prod build and isn’t a real fix. Do not use the JIT compiler in production.

Note: Once you get things working, if you still see the Angular Compiler in your production webpack bundle, you can safely remove it using Webpack’s ‘externals’ option. Some Angular versions require the compiler for JIT builds, but the compiler isn’t needed for AOT builds.

2. If you still don’t see a useful error message, remove Terser completely and make sure you’re not suppressing build errors.

3. When fixing Webpack issues in general, it can sometimes be useful to create a new Angular CLI project, add your plugins (or other code), and see if it builds. If it does, then you know your Webpack config is the problem, not Angular. I also find it useful to compare Angular CLI’s config files with my own (though it’s tedious).

Leave a Comment