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"
]
}
CodePudding user response:
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:
module.exports = {
//...
externals: {
fetch: 'cross-fetch'
}
};
But then your back to applying a patch or using a git branch
