0

I want to use a library in Angular. (The npm package is cubing for reference). This library can run both in the browser or in node and has some specific code to both. I want it to run in the browser, but Angular compilation doesn't work because it can't find worker_threads. I asked the library owner and he said the intended solution is to tell your build system that this import should be ignored because it's only relevant for the node variant of the code.

But I can't figure out how to tell Angular this. How do I tell it: Please ignore this import in this node module, we're never going to reach the code that uses it?

Error: Can't resolve 'worker_threads' in REDACTED/node_modules/cubing/dist/esm

If that's not possible, I guess I could consider doing a node_modules patch, but I dislike that idea, for obvious reasons. And I heard it's hard to get it to work in production environments.

For reference, this is the github project (switch to branch scrambles for the problem at hand): https://github.com/Lykos/cube_trainer.git

And here the most relevant files:

Package.json:

{ "name": "cube-trainer", "private": true, "author": "Bernhard F. Brodowsky", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/Lykos/cube_trainer.git" }, "engines": { "node": "16.x", "npm": "8.x" }, "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build --configuration production", "build_development": "ng build --configuration development", "watch": "ng build --watch --configuration development", "test": "ng test", "test_ci": "ng test --karma-config client/karma-ci.conf.js", "lint": "ng lint" }, "dependencies": { "@angular/animations": "^13.0.2", "@angular/cdk": "^13.0.2", "@angular/common": "^13.0.2", "@angular/compiler": "^13.0.2", "@angular/core": "^13.0.2", "@angular/forms": "^13.0.2", "@angular/material": "^13.0.2", "@angular/platform-browser": "^13.0.2", "@angular/platform-browser-dynamic": "^13.0.2", "@angular/router": "^13.0.2", "@ngrx/component-store": "^13.0.2", "@ngrx/effects": "^13.0.2", "@ngrx/store": "^13.0.2", "@ngrx/store-devtools": "^13.0.2", "@rxweb/reactive-form-validators": "^2.1.6", "actioncable": "^5.2.6", "angular-token": "^7.0.1", "cubing": "^0.22.0", "file-saver": "^2.0.5", "ngx-cookie-service": "^13.0.1", "ngx-filesaver": "^12.0.0", "rxjs": "~7.4.0", "tslib": "^2.3.0", "zone.js": "~0.11.4" }, "devDependencies": { "@angular-devkit/build-angular": "~13.0.1", "@angular-eslint/builder": "12.6.1", "@angular-eslint/eslint-plugin": "12.6.1", "@angular-eslint/eslint-plugin-template": "12.6.1", "@angular-eslint/schematics": "12.6.1", "@angular-eslint/template-parser": "12.6.1", "@angular/cli": "~13.0.1", "@angular/compiler-cli": "~13.0.0", "@ngrx/schematics": "^13.0.2", "@types/actioncable": "^5.2.7", "@types/chai": "^4.2.22", "@types/file-saver": "^2.0.4", "@types/jasmine": "~3.10.0", "@types/node": "^12.11.1", "@typescript-eslint/eslint-plugin": "4.28.2", "@typescript-eslint/parser": "4.28.2", "angular-http-server": "^1.10.0", "chai": "^4.3.4", "eslint": "^7.26.0", "jasmine-core": "~3.10.0", "karma": "~6.3.0", "karma-chai": "^0.1.0", "karma-chrome-launcher": "~3.1.0", "karma-coverage": "~2.0.3", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "~1.7.0", "karma-mocha": "^2.0.1", "mocha": "^9.1.3", "typescript": "~4.4.4" } } 

angular.json

{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "cube-trainer": { "projectType": "application", "schematics": { "@schematics/angular:application": { "strict": true } }, "root": "", "sourceRoot": "client/src", "prefix": "app", "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "./public", "index": "client/src/index.html", "main": "client/src/main.ts", "polyfills": "client/src/polyfills.ts", "tsConfig": "client/tsconfig.app.json", "assets": [ "client/src/favicon.ico", "client/src/assets" ], "styles": [ "./node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css", "client/src/styles.css" ], "scripts": [], "webWorkerTsConfig": "client/tsconfig.worker.json" }, "configurations": { "production": { "budgets": [ { "type": "initial", "maximumWarning": "4mb", "maximumError": "5mb" }, { "type": "anyComponentStyle", "maximumWarning": "2kb", "maximumError": "4kb" } ], "fileReplacements": [ { "replace": "client/src/environments/environment.ts", "with": "client/src/environments/environment.prod.ts" } ], "outputHashing": "all" }, "development": { "buildOptimizer": false, "optimization": false, "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true, "outputHashing": "none" } }, "defaultConfiguration": "production" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "proxyConfig": "client/src/proxy.conf.json" }, "configurations": { "production": { "browserTarget": "cube-trainer:build:production" }, "development": { "browserTarget": "cube-trainer:build:development" } }, "defaultConfiguration": "development" }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "cube-trainer:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "client/src/test.ts", "polyfills": "client/src/polyfills.ts", "tsConfig": "client/tsconfig.spec.json", "karmaConfig": "client/karma.conf.js", "assets": [ "client/src/favicon.ico", "client/src/assets" ], "styles": [ "./node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css", "client/src/styles.css" ], "scripts": [] } }, "lint": { "builder": "@angular-eslint/builder:lint", "options": { "lintFilePatterns": [ "client/src/**/*.ts", "client/src/**/*.html" ] } } } } }, "defaultProject": "cube-trainer", "cli": { "defaultCollection": "@ngrx/schematics" } } 

tsconfig.json

/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "compileOnSave": false, "compilerOptions": { "baseUrl": "src/", "paths": { "@environment": ["environments/environment"], "@shared/*": ["app/shared/*"], "@utils/*": ["app/utils/*"], "@store/*": ["app/store/*"], "@effects/*": ["app/effects/*"], "@core/*": ["app/core/*"], "@training/*": ["app/training/*"] }, "outDir": "./dist/out-tsc", "forceConsistentCasingInFileNames": true, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "sourceMap": true, "declaration": false, "downlevelIteration": true, "experimentalDecorators": true, "moduleResolution": "node", "importHelpers": true, "target": "es2017", "module": "es2020", "lib": [ "es2020", "dom" ], "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, "noUnusedLocals": true, "noImplicitThis": true, "noImplicitReturns": true, "strict": true, "skipLibCheck": true }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": true, "strictInputAccessModifiers": true, "strictTemplates": true } } 

tsconfig.app.json

/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/app", "types": [] }, "files": [ "src/main.ts", "src/polyfills.ts" ], "include": [ "src/**/*.d.ts" ] } 
3
  • What builder/bundler are you using? Angular is the library Commented Jan 4, 2022 at 18:28
  • 1
    I use npm, ng build and ng serve and pretty much the defaults of what Angular tutorials tell me to use. If any of my package.json or angular.json or tsconfig.json are important , let me know and I will add them. Commented Jan 4, 2022 at 18:32
  • 1
    Ok, added all the files that I could think of that might be relevant and a link to Github. Let me know if anything else is useful. But as I understand it, the answer to your question is that I use the Angular buidl tools. Commented Jan 4, 2022 at 19:12

1 Answer 1

0

Looks like you might be able to exclude it in the tsconfig or in the angular.json, maybe try both?

Exclude files from build in Angular 2

// tsconfig { "exclude": [ "node_modules/thepath/tothedependency/orfile/using/worker_threads/I_guess", ] } 
// angular.json ... "configurations": { "production": { "assets": [ { "ignore": [ "**/test.json", "**/test" ], }, ... 

Something like that

You can also install a browser wrapper for worker_threads then configure angular build / webpack to substitute the old import for the new one.

If you do decide to patch it it might not be too bad. Forking on github and installing from your github fork is pretty easy. Or else saving a git patch file for the change and automatically applying that patch in your install step isn't crazy either.

This kind of thing is generally a pain in the ass, in esbuild and rollup and stuff too.

You can also modify your webpack config, which I think ng build is using under the hood, it's probably in /node_modules/angular/somejunk/config/webpack.config.json or something and add this:

Webpack ignore import

module.exports = { //... externals: { fetch: 'cross-fetch' } }; 

But then your back to applying a patch or using a git branch

Sign up to request clarification or add additional context in comments.

2 Comments

Hey, thanks a lot for your options. I didn't quite manage to get it to work yet though. I tried: * exclude in tsconfig doesn't work. Apparently that option is commonly misunderstood and isn't really excluding things in general, it's just removing those from the "includes" option. * What you suggested for angular.json causes parse errors. But my assets are only two files and this library isn't part of it, so I don't expect this to do much. * I tried patching using the patch-package package, but somehow ng serve seems to ignore the patches. * There is no webpack config in node_modules.
Ah wow, but your hint with the webpack config did help me solve the issue! I stumbled upon the @angular-builders/custom-webpack in your referenced question and that worked! Thanks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.