Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime error when paths are provided in .swcrc #31

Closed
GV94 opened this issue May 2, 2022 · 10 comments
Closed

Runtime error when paths are provided in .swcrc #31

GV94 opened this issue May 2, 2022 · 10 comments

Comments

@GV94
Copy link
Contributor

GV94 commented May 2, 2022

I am trying to add path aliases through .swcrc by specifying paths

Here is my .swcrc

{
  "jsc": {
    "parser": {
      "syntax": "typescript"
    },
    "target": "es2021",
    "baseUrl": ".",
    "paths": {
      "@connectors/*": ["./src/connectors/*"],
      "@operations/*": ["./src/operations/*"]
    }
  },
  "module": {
    "type": "commonjs"
  }
}

When paths are specified and I attempt to use the path-alias for an import, the build is successful but I get the following runtime error

 Error: Cannot find module '../../../../../../../../../../.cache/bazel/_bazel_victor/b76e982e01c6243367a3fb2de72a73de/execroot/[redacted]/bazel-out/k8-fastbuild/bin/backend/packages/grpc-error/index'

grpc-error is one of our other packages built with the bazel js-library rule.

It seems like "paths" is actually working, because it allows me to use the path-aliases, the build doesn't crash. However the resulting import path isn't valid, the file doesn't exist, and I am guessing there is some bazel magic I don't understand going on in the background. The resulting import path when paths is not specified and I don't attempt to use the path-alias looks like this @[package-name]/grpc-error, which is the name of the library.

To summarize

//.swcrc
{
...
    "paths": {
      "@connectors/*": ["./src/connectors/*"],
      "@operations/*": ["./src/operations/*"]
    }
...
}

results in

var _grpcError = require("../../../../../../../../../../.cache/bazel/_bazel_victor/b76e982e01c6243367a3fb2de72a73de/execroot/energy_services/bazel-out/k8-fastbuild/bin/backend/packages/grpc-error/index");

and a run-time error

and

// .swcrc
{
...
    // "paths": {
    // "@connectors/*": ["./src/connectors/*"],
    // "@operations/*": ["./src/operations/*"]
    // }
...
}

results in

var _grpcError = require("@ingka/grpc-error");
@alexeagle
Copy link
Member

As with the TypeScript compiler, the paths configuration is just to help it resolve paths at compile-time. In order to run the resulting code, the runtime also has to know where the paths should resolve.

I think the JS code with all the ../.. imports is not desirable. What JS imports do you want to have at runtime? I suspect you want require("@ingka/grpc-error") as your runtime probably has such a path under its node_modules.

If you could make a minimal repro (especially as a new folder under examples/ here in this repo) then I'm happy to understand more.

Note SWC has a bug swc-project/swc#3028 but from staring at your output path I don't think this bug is involved.

@GV94
Copy link
Contributor Author

GV94 commented May 2, 2022

The resulting path I want is var _grpcError = require("@ingka/grpc-error");, I don't expect swc to change this path since it is not in paths.

I also expect

import {
  grpcBadRequestError,
  grpcNotFoundError,
  grpcUnauthenticatedError,
  grpcUnhandledError,
} from '@ingka/grpc-error';
import { BadRequestError } from '@connectors/@types/errors/BadRequestError'; // notice use of path alias
import { NotFoundError } from '../../../connectors/@types/errors/NotFoundError';
import { UnauthenticatedError } from '../../../connectors/@types/errors/UnauthenticatedError';

to transpile to

var _grpcError = require("@ingka/grpc-error");
var _BadRequestError = require("../../../connectors/@types/errors/BadRequestError");
var _NotFoundError = require("../../../connectors/@types/errors/NotFoundError");
var _UnauthenticatedError = require("../../../connectors/@types/errors/UnauthenticatedError");

instead of

var _grpcError = require("../../../../../../../../../../.cache/bazel/_bazel_victor/b76e982e01c6243367a3fb2de72a73de/execroot/energy_services/bazel-out/k8-fastbuild/bin/backend/packages/grpc-error/index");
var _BadRequestError = require("../../../../../../../../../../.cache/bazel/_bazel_victor/b76e982e01c6243367a3fb2de72a73de/sandbox/linux-sandbox/7526/execroot/energy_services/backend/electricity-subscription/services/-partner-svc/src/connectors/@types/errorsBadRequestError");
var _NotFoundError = require("../../../connectors/@types/errors/NotFoundError");
var _UnauthenticatedError = require("../../../connectors/@types/errors/UnauthenticatedError");

It feels like swc is resolving the paths based on a different baseUrl than I specify in .swcrc. "." in the bazel sandbox environment becomes something different than I expect. I expect it to be the root of my project folder (one level up from src), but in reality it becomes the root of the sandbox environment, and the folder structure in that environment is different both than my project structure, and the output folder. I hope this makes sense, I feel like I am having trouble explaining what I mean.

I'll try to create a repro to illustrate the problem.

@alexeagle
Copy link
Member

We are just rolling out a new ruleset, https://github.com/aspect-build/rules_js which is specifically to solve problems related to nodejs or nodejs tools behaving differently when they see Bazel's filesystem layout. Take a look at the README there for a quick explanation.
I suspect the problem is solved there - looking forward to trying it on your repro :)

@GV94
Copy link
Contributor Author

GV94 commented May 3, 2022

Hey, there is a repro at GV94#1

Not sure if this is the preferred way of doing this, this is my first ever repro. Let me know if I should do it differently or if you have any other issues @alexeagle

Note that I didn't create a separate package with js_library and import it, I think the example is demonstrative of the issue as it is. I can extend the repro and do that if you think it is necessary.

@iamricard
Copy link

fwiw we're running into the same issue when trying these rules, and the repro seems representative of our setup.

@alexeagle how do rules_js help rules_swc? as far as i can tell, the issue is what @GV94 pointed out: when SWC rewrites the paths it seems it ends up using some unexpected location for the baseUrl. is rules_js supposed to help rules_swc run in some other way?

@alexeagle
Copy link
Member

thanks for the repro @GV94

Bazel is just running swc like so:

$ bazel build //examples/paths:transpile --subcommands
...
BAZEL_BINDIR=bazel-out/k8-fastbuild/bin \
    SWC_BINARY_PATH=../../../external/default_swc_linux-x64-gnu/swc.linux-x64-gnu.node \
  bazel-out/k8-opt-exec-2B5CBBC6/bin/swc/_cli_launcher.sh --source-maps false --config-file examples/paths/.swcrc examples/paths/src/index.ts --out-file examples/paths/src/index.js -q

We're not doing anything funny there, and if you cd into that folder and run SWC you don't get the strange path.

That leaves bazel sandboxing as the difference - when bazel spawns an action, the default strategy is to run within a filesystem sandbox, trying to help you discover non-hermeticity when the action depends on some undeclared input. To confirm, you can add --spawn_strategy=local to your bazel run. You'll see the imports are written the way you expect.

So I think this is simply an SWC bug when the input files are symlinks, which is already reported: swc-project/swc#4057

@alexeagle
Copy link
Member

alexeagle commented May 4, 2022

Note that using --spawn_strategy=local turns off sandboxing for ALL actions in your build, which is too broad. I added a commit on top of your repro demonstrating a nicer fix, just adding the no-sandbox tag to all swc transpile actions.
#33
are you okay with me adding your commits to the upstream project?

@GV94
Copy link
Contributor Author

GV94 commented May 5, 2022

@alexeagle Thanks for the response. I agree, seems like that bug is the cause of all this.

Yes, feel free to use my commits in any way you please.

@alexeagle
Copy link
Member

Do you mind signing the CLA over on that PR? I think for legal I could just point to your approval on this thread, but that would be easier for me :)

@GV94
Copy link
Contributor Author

GV94 commented May 5, 2022

@alexeagle I think I already did?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants