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

Resolve package paths instead of relative ones? #2044

Closed
bufordtaylor opened this issue Feb 23, 2022 · 3 comments
Closed

Resolve package paths instead of relative ones? #2044

bufordtaylor opened this issue Feb 23, 2022 · 3 comments

Comments

@bufordtaylor
Copy link

Hi there, I thought I'd give Rails 7 + esbuild a spin and I'm running into a slight issue with path resolution. My team tends to re-use files across multiple projects and rewriting our absolute paths to relative ones over 100s of files would be cumbersome. Is there anyway to have esbuild use an absolute path?

Here are my files

app/javascript/
├── App.jsx
├── application.js
├── controllers
│   ├── application.js
│   ├── hello_controller.js
│   ├── index.js
├── pages
│  └── Test.jsx
├── shared
│   ├── Buttons.jsx
└── utils
    └── classNamesLocal.js

When I import files like this, it works

// app/javascript/pages/Text.jsx
import { PrimaryButton } from '../../shared/Buttons'

But when I try to resolve with an absolute path, I get this error

14:54:11 js.1   | [watch] build started (change: "app/javascript/shared/Buttons")
14:54:11 js.1   | ✘ [ERROR] Could not resolve "app/javascript/shared/Buttons"

Note: I've also tried with the same error

  1. import { PrimaryButton } from 'app/javascript/shared/Buttons'
  2. import { PrimaryButton } from 'javascript/shared/Buttons'
  3. import { PrimaryButton } from 'shared/Buttons'
  4. import { PrimaryButton } from './shared/Buttons'

Here is my config:

// esbuild.config.js
const path = require('path');

require("esbuild").build({
  entryPoints: ["application.js"],
  bundle: true,
  outdir: path.join(process.cwd(), "app/assets/builds"),
  absWorkingDir: path.join(process.cwd(), "app/javascript"),
  watch: true,
  // custom plugins will be inserted is this array
  plugins: [],
}).catch(() => process.exit(1));
// package.json
  "scripts": {
    "build": "node esbuild.config.js",
    "build:css": "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css"
  }
@evanw
Copy link
Owner

evanw commented Feb 23, 2022

These are package paths, not absolute paths. Absolute paths start with /, relative paths start with ./ or ../, and package paths are all other paths that are neither absolute nor relative.

Since esbuild uses node's path resolution algorithm, these package paths cause esbuild to look inside the node_modules directory for the corresponding file.

Here are some ways to get this to work:

  • You could create a tsconfig.json file that sets the baseUrl option. Since esbuild respects tsconfig.json files, it should respect this.

  • You could try using the NODE_PATH environment variable to specify a fallback directory to use when esbuild looks inside node_modules directories.

  • You could write an onResolve esbuild plugin to implement whatever custom path remapping logic you want.

@evanw evanw changed the title Resolve absolute paths instead of relative ones? Resolve package paths instead of relative ones? Feb 23, 2022
@guybedford
Copy link
Contributor

Per the Node.js resolution algorithm there are two features that can help here:

  1. Package own-name resolution - if the package.json defines a "name" field, it is possible to load the package from within itself as if it was being externally imported - in this case, setting the "name" field to "app"
  2. If using the exports field with package encapsulation, the imports field permits defining internal private names and private paths - "imports": { "#shared/*": "./shared/* } etc.

@bufordtaylor
Copy link
Author

This worked like a charm. Thanks!

For future readers, I added a tsconfig.json and then pointed the esbuild script to use that config.

//tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "app/javascript"
  }

esbuild app/javascript/*.* --bundle --tsconfig=./tsconfig.json --loader:.js=jsx --sourcemap --outdir=app/assets/builds

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