25

My Angular application is served via Node 16.13.0. After updating to Angular 13, I'm receiving the following error:

JIT compilation failed for injectable [class PlatformLocation] file:///Users/btaylor/work/angular-apps/dz-outages-ui/node_modules/@angular/core/fesm2015/core.mjs:4058 throw new Error(message); ^

Error: The injectable 'PlatformLocation' 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. at getCompilerFacade (file:///Users/btaylor/work/angular-apps/dz-outages-ui/node_modules/@angular/core/fesm2015/core.mjs:4058:15) at Module.ɵɵngDeclareFactory (file:///Users/btaylor/work/angular-apps/dz-outages-ui/node_modules/@angular/core/fesm2015/core.mjs:32999:22) at file:///Users/btaylor/work/angular-apps/dz-outages-ui/node_modules/@angular/common/fesm2015/common.mjs:90:28 at ModuleJob.run (node:internal/modules/esm/module_job:185:25) at async Promise.all (index 0) at async ESMLoader.import (node:internal/modules/esm/loader:281:24) at async loadESM (node:internal/process/esm_loader:88:5) at async handleMainPromise (node:internal/modules/run_main:65:12)

I have tried numerous solutions, such as: Angular JIT compilation failed: '@angular/compiler' not loaded

Currently, I have "type": "module" in my package.json

I have updated my postinstall command to: ngcc --properties es2020 browser module main --first-only --create-ivy-entry-points

I also added import '@angular/compiler'; to my main.ts file.

The project will compile, but won't run via Node.

Brandon Taylor
  • 33,823
  • 15
  • 104
  • 144
  • 1
    @RushPL me too. I need to find some time to make a minimal reproduction to raise a bug with the Angular team. I have another app using Universal with Angular 13 that works just fine. – Brandon Taylor Dec 06 '21 at 14:43
  • This problem must be due to a specific dependency, as I was able to convert another Angular 12 app with the same architecture to 13 without issue. – Brandon Taylor Dec 09 '21 at 16:59
  • Angular CLI shouldn't have this problem as it configures webpack+babel by itself. – RushPL Dec 11 '21 at 02:55
  • By chance did you ever figure this out? – WBuck Apr 24 '23 at 16:57
  • @WBuck No, I haven't had a chance to get back to this. I work on a ton of different projects at work and this upgrade feature on this app has been sidelined for a while. – Brandon Taylor Apr 24 '23 at 19:40

4 Answers4

16

I believe I have found the solution (presuming you are using jest as your test runner). In the test-setup.ts file my project still was using the outdated import for jest-preset-angular. Instead of import 'jest-preset-angular'; try using import 'jest-preset-angular/setup-jest';.

This addressed the issue for me.

Brett Eckert
  • 207
  • 2
  • 5
  • 5
    My scenario doesn't involve testing. I get the runtime error when serving the compiled code via Node. – Brandon Taylor Dec 08 '21 at 18:19
  • It works with jest. I was not using `test-setup.ts` initially. – Code Name Jack Jan 05 '22 at 10:46
  • Did someone found any solution? :/ – karina Jan 19 '22 at 15:52
  • 1
    The change I had to make for this was in my jest.config.js file. I had `require('jest-preset-angular/ngcc-jest-processor')` at the top, but switched it to a globalSetup property on the exports as such: ```module.exports = { ..., globalSetup: 'jest-preset-angular/global-setup'`, ... };``` – Shafiq Jetha Feb 01 '22 at 20:25
  • No dice for me. Seem to still get the same error. And a new one to go along with it when removing testbed and using jest standalone. " The injectable 'ActionsSubject' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available." – Lewis Morgans Mar 08 '23 at 11:20
  • this worked for me, changing `jest-setup.ts`. thank you – Jesper Kristiansen Aug 10 '23 at 21:04
7

It seems angular 13 made babel-loader a mandatory requirement to link Ivy-native packages. https://github.com/angular/angular/issues/44026#issuecomment-974137408 - and the issue is happening as core Angular libraries are already compiled with the Ivy package format.

I haven't yet made the change in my own projects, but processing .mjs files with babel and a special linker should be enough.

import { dynamicImport } from 'tsimportlib';

/**
 * Webpack configuration
 *
 * See: http://webpack.github.io/docs/configuration.html#cli
 */
export default async (options: IWebpackOptions) => {
    const linkerPlugin = await dynamicImport('@angular/compiler-cli/linker/babel', module);
    
    const config: any = {
        module: {
            rules: [{
                test: /\.mjs$/,
                loader: 'babel-loader',
                options: {
                    compact: false,
                    plugins: [linkerPlugin.default],
                },
                resolve: {
                    fullySpecified: false
                }
            }
        }
    }
}

I'll make more updated to this post once I am able to test it myself.

RushPL
  • 4,732
  • 1
  • 34
  • 44
  • Interesting. I haven't used custom webpack plugins with any of my projects. Do you have a reference for how to use/configure this with an existing project? – Brandon Taylor Dec 10 '21 at 19:56
  • why you use `dynamicImport`? I saw a similar snippet without it `import linkerPlugin from '@angular/compiler-cli/linker/babel'; ` then ` ... {options: {plugins: [linkerPlugin],}` @RushPL – Sh eldeeb Feb 08 '22 at 09:42
  • this should guide you how to setup custom-webpack in your code base `https://www.npmjs.com/package/@angular-builders/custom-webpack` – Sh eldeeb Feb 08 '22 at 09:43
  • having too many issues trying to use async/await. webpack is determined to not let me use iit. able to use `import linkerPlugin from '@angular/compiler-cli/linker/babel';`. but then unable to resolve following error from babel-loader: `Error: .plugins[0] must be a string, object, function.` this points specifically to the line `plugins: [linkerPlugin.default]` any help? – Akul Aggarwal May 05 '23 at 05:16
2

If I correctly understand, you use Angular Universal also.

I want to share my experience with the same problem which came to my project after updating Angular from v8 to v13.

First of all, I want to say that the main problem was with the incorrect started file for SSR. In my project, it was server.js and now it's main.js. So, maybe your project also tries to start from the incorrect file which doesn't have the necessary code to start it.

More details:

I updated the project step by step, increasing the version as recommended by the Angular team and according to https://update.angular.io/?l=3&v=8.2-13.0

Unfortunately, at every step, I only checked the version of SPA without SSR and only compiled the project to check that all is OK, but didn't start it with SSR. Now I can't say when the problem with the JIT compiler started.

And when I finished updating and fixing bugs with SPA, compiled the project with SSR, and tried to start it I saw this problem:

Error: The injectable 'PlatformLocation' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.

I tried different solutions like you, but nothing helped. After that, I created a new clean project with ng13 and added Angular Universal. And compare my project with new, generated by Angular-CLI.

What I changed in my project(sorry, I can't show the project - NDA):

  1. angular.json

"projects": {
  "projectName": {
    ...
    "architect": {
      ...
      "server": {
        ...
        "options": {
            "outputPath": "dist/server",
            //"main": "src/main.server.ts", //removed
            "main": "server.ts", //added
            ...
        }
      }
    }
  }
}
  1. package.json

"scripts": {
  ...
  //"serve:production:ssr":   "node dist/server --production" // removed. It was incorrect file server.js which gave the error from this case
  "serve:production:ssr":   "node dist/server/main --production", // added
  ...
  "postinstall": "ngcc --properties es5 browser module main --first-only" // added. In my case, actual version is es5
}

3.server.ts

import 'zone.js/node';

import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';

import { AppServerModule } from './src/main.server';
...
// after all imports I inserted previous code into function run()

...
export function run() {
  // previous code from project with some small changes
}

//and added next code from clean project:

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
    run();
}

export * from '../src/main.server';
  1. src/main.server.ts

// was only:
export { AppServerModule } from './app/app.server.module';

// replaced by code from clean project:

/***************************************************************************************************
 * Initialize the server environment - for example, adding DOM built-in types to the global scope.
 *
 * NOTE:
 * This import must come before any imports (direct or transitive) that rely on DOM built-ins being
 * available, such as `@angular/elements`.
 */
import '@angular/platform-server/init';

import { enableProdMode } from '@angular/core';

import { environment } from './environments/environment';

if (environment.production) {
    enableProdMode();
}

export { AppServerModule } from './app/app.server.module';
export { renderModule, renderModuleFactory } from '@angular/platform-server';
  1. src/main.ts

...
//this part of code
document.addEventListener("DOMContentLoaded", () => {
    platformBrowserDynamic()
        .bootstrapModule(AppModule)
        .catch(err => console.log(err));
});

// replaced by

function bootstrap() {
    platformBrowserDynamic().bootstrapModule(AppModule)
        .catch(err => console.error(err));
};


if (document.readyState === 'complete') {
    bootstrap();
} else {
    document.addEventListener('DOMContentLoaded', bootstrap);
}

//but I don't think it plays a role in solving the JIT problem. Wrote just in case
  1. tsconfig.server.json

{
  "extends": "./tsconfig.app.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app-server",
    "module": "commonjs",// it's only in my case, I don't have time for rewrote server.ts now
    "types": ["node"],
  },
  "files": [
    "src/main.server.ts",
    "server.ts"
  ],
  "include":["server/**/*.ts","node/*.ts"],
  
  "angularCompilerOptions": {
    "entryModule": "./src/app/app.server.module#AppServerModule"
  }
}

Ok, I think that's all. After all these edits I don't have file /dist/server.js and start the project from /dist/server/main.js without error from this case.

N.B.: When I was updating the project step-by-step I noticed that the process of updating nguniversal by Angular-CLI didn't change anything in the project. Only the version of packages. That's why I recommend comparing your project with an actual clean project manually

  • Well, I get a different error now. When running `serve:ssr` I get: `SyntaxError: Strict mode code may not include a with statement` – Brandon Taylor Feb 18 '22 at 02:32
  • I think it can be some bug in the project. Maybe this is a reason: https://github.com/angular/angular/issues/34970#issuecomment-581838896. – Vitalii Malynka Feb 18 '22 at 07:37
  • I saw that same link when investigating, but I've updated my code to no avail. I think I'll probably have to create a new project and start adding my code back piece by piece until it breaks. – Brandon Taylor Feb 18 '22 at 14:04
0

The solution to this problem in my case was missing the following configuration in the jest.config.js file:

setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts']

Configuration

sdv
  • 1
  • 1