Search code examples
angularngrxbazelbazel-rules-nodejs

Cannot use import statement outside a module (Bazel + Concatjs + NgRx)


The Issue

I am using Bazel to build my Angular application.

Everything works fine with NgRx version 9.

But after upgrading NgRx to v10 or greater, the Angular development server breaks with this error:

Uncaught SyntaxError: Cannot use import statement outside a module
    at ts_scripts.js?v=32020367:12007

Minimal Reproduction

To reproduce this issue follow these steps:

  1. git clone https://github.com/flolu/bazel-concatjs-ngrx-issue
  2. cd bazel-concatjs-ngrx-issue
  3. yarn install
  4. yarn start (Open http://localhost:4200, works fine)
  5. yarn upgrade-ngrx (Upgrade NgRx to v11)
  6. yarn start (Open http://localhost:4200, error in the browser console)

Note, that the production server yarn prod works fine on both versions of NgRx.

Therefore, this is a problem with the development server (in this case: @bazel/concatjs)


Solution

  • This issue is caused by the ngfactory.js files included with NgRx, however I'm unclear if these files should be part of the library distribution or not. It seems perhaps in older versions of Angular they were?

    In rules_nodejs, the BUILD file generation for node_modules includes these ngfactory files in the srcs attribute of the generated js_library. (I think that's incorrect now, so we can fix that), these sources include import statements which aren't allowed outside of the modules (as the error states) as we are loading UMD.

    A workaround around here is to either:

    • Patch rules_nodejs to not add those files to the generated js_library
    • Add a postinstall script to remove the ngfactory.js files from NgRx which runs before BUILD file generation. Example below:

    //:package.json

    diff --git a/package.json b/package.json
    index 137c115..b322b55 100644
    --- a/package.json
    +++ b/package.json
    @@ -7,7 +7,7 @@
         "@angular/platform-browser": "^11.2.4",
         "@angular/platform-browser-dynamic": "^11.2.4",
         "@angular/router": "^11.2.4",
    -    "@ngrx/store": "9.1.2",
    +    "@ngrx/store": "^11.0.1",
         "core-js": "2.6.9",
         "rxjs": "^6.6.3",
         "systemjs": "6.1.2",
    @@ -29,7 +29,7 @@
         "@bazel/rollup": "^3.2.0",
         "@bazel/terser": "^3.2.0",
         "@bazel/typescript": "^3.2.0",
    -    "@ngrx/store-devtools": "9.1.2",
    +    "@ngrx/store-devtools": "^11.0.1",
         "@types/jasmine": "^3.6.2",
         "@types/node": "^14.11.2",
         "@typescript-eslint/eslint-plugin": "^4.15.0",
    @@ -53,6 +53,7 @@
         "rollup": "^2.28.2",
         "rollup-plugin-commonjs": "^10.1.0",
         "rollup-plugin-node-resolve": "^5.2.0",
    +    "shelljs": "^0.8.4",
         "terser": "^5.3.4",
         "typescript": "^4.2.3"
       },
    @@ -60,7 +61,7 @@
         "start": "ibazel run //services/client:dev_server",
         "prod": "bazelisk run //services/client:app_server",
         "upgrade-ngrx": "yarn add @ngrx/store -D @ngrx/store-devtools",
    -    "postinstall": "patch-package && ngcc"
    +    "postinstall": "node postinstall.js && patch-package && ngcc"
    

    postinstall.js

    require('shelljs').rm(['node_modules/@ngrx/**/*.ngfactory.js', 'node_modules/@ngrx/**/*.ngsummary.json']);
    

    To have this run after via after the yarn install via bazel:

    //:BUILD.bazel

    diff --git a/BUILD.bazel b/BUILD.bazel
    index b91e927..d7a8767 100644
    --- a/BUILD.bazel
    +++ b/BUILD.bazel
    @@ -2,6 +2,8 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config")
    
     package(default_visibility = ["//:__subpackages__"])
    
    +exports_files(["postinstall.js"])
    +
     ts_config(
         name = "tsconfig",
         src = "tsconfig.json",
    

    //:WORKSPACE

    diff --git a/WORKSPACE b/WORKSPACE
    index 7fabecb..cd0e095 100644
    --- a/WORKSPACE
    +++ b/WORKSPACE
    @@ -18,6 +18,9 @@ yarn_install(
         package_json = "//:package.json",
         quiet = False,
         yarn_lock = "//:yarn.lock",
    +    data = [
    +        "//:postinstall.js",
    +    ],
     )
    
     load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
    

    Applying this to your repro produces the "Hello world" as expected with the updated NgRx deps.