swc icon indicating copy to clipboard operation
swc copied to clipboard

Support baseUrl (non-relative imports)

Open heygrady opened this issue 4 years ago • 7 comments

It is a common patten in TypeScript (and create react app) projects to specify a baseUrl in the tsconfig.json to allow for absolute URL imports.

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "src" // non-relative imports are relative to this path
  },
  "include": ["src"]
}

Example project structure:

src/
  helpers/bar.ts
  foo.ts
tsconfig.json

Example code:

// helpers/bar.ts (with baseUrl: src)
import { foo } from 'foo'
// helpers/bar.ts (without baseUrl)
import { foo } from '../foo'

Babel plugin or link to the feature description

  • https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url
  • https://create-react-app.dev/docs/importing-a-component/#absolute-imports
  • https://levelup.gitconnected.com/understand-and-configure-absolute-import-paths-in-javascript-5cde3be2630d

Additional context I am looking into using SWC to replace babel in a large monorepo I manage. I ran across very few issues but had to stop when I hit this snag. I think there is a large section of the existing JavaScript community that uses this feature (or a variation). For instance, something like non-relative imports is supported by:

  • TypeScript
  • Babel
  • Rollup
  • Webpack
  • ESLint

There are some pros and cons of using these types of imports in your code. There is no denying that it is popular and a positive developer experience. My sense is that the argument against something like baseUrl is that it (perhaps) doesn't fit well with the official spec for import resolving.

It seems like Node is providing some mechanisms for doing parent-relative import resolving. It is notable the NODE_PATH is explicitly not supported by Node's ES Modules.

  • https://nodejs.org/api/esm.html#esm_import_meta_resolve_specifier_parent
  • https://nodejs.org/api/esm.html#esm_no_node_path

ideal case

In an ideal world we could use non-relative imports in our source code and have them transpiled into relative paths in the final code.

// in
import { foo } from 'foo'

Building for ESM:

// out (esm)
import { foo } from '../foo'

Building for CJS:

// out (cjs; simplified for clarity)
const { foo } = require('../foo')

heygrady avatar Jan 11 '21 21:01 heygrady

  • https://www.npmjs.com/package/typescript-transform-paths
  • https://github.com/Microsoft/TypeScript/issues/15479#issuecomment-300240856
  • https://www.npmjs.com/package/babel-plugin-module-resolver

For more context, TypeScript has limited support for generating output code that respects the baseUrl settings. The transform paths plugin does this and it requires a custom compiler (ttypescript). Using Babel to transform your TypeScript means you can use the module resolver plugin to convert to relative imports.

What I'm most worried about is the right steps to get both the transpile and transform features we use today with our current babel/typescript rig.

SWC is appealing because it correctly recognizes that preset-env is 99% of that you need. However, the power of the tooling has spoiled us. We're dependent on bespoke productivity tools (like path transforms) that enhance developer experience but are not directly related to the core task of transpiling TypeScript/ES code to work in a variety of JavaScript environments.

heygrady avatar Jan 12 '21 00:01 heygrady

Do you mean you want to use baseUrl without paths?

kdy1 avatar Nov 11 '21 06:11 kdy1

Do you mean you want to use baseUrl without paths?

Hey @kdy1 !

I have this exact use case yes, where I have only baseUrl: 'src' and no paths configured.

Right now I cannot use swc because it does not work with this configuration.

adriencaccia avatar Jan 12 '22 18:01 adriencaccia

It may need some more thoughts, but I'm under impression we (swc/core) eventually get rid of custom resolving behavior including existing options but instead let userland plugin / module does custom resolving, as similar to babel's plugin which is referenced in here.

kwonoj avatar Jan 12 '22 18:01 kwonoj

are there currently any work arounds in combination with swc, previously i used just ttsc with a path transformer plugin.

would love to speed up my builds. anyway swc looks really nice. great job

alexn-s avatar Apr 09 '22 17:04 alexn-s

Any progress on this issue? I'm stuck.

mzvast avatar Aug 03 '22 14:08 mzvast

I checked if this is easily implementable, but I decided to postpone it as it requires resolving logic

kdy1 avatar Aug 17 '22 22:08 kdy1

I would also love this feature. I looked into rollup which has a plugin for this. But rollup builds my code 20 times slower than SWC (even with esbuild plugin). Refactored everything to relative imports for now, hoping that SWC will support absolute imports soon.

In the mean time if anyone has a good workaround please let me know. Thanks so much for an awesome tool :)

ziggy6792 avatar Nov 14 '22 10:11 ziggy6792

Would absolutely love this feature too! We are using SWC as the transpiler for our backend Nest.js project and skip webpack entirely. Currently relative imports + nodenext target is the way we do it, but would prefer being able to use absolute imports without specifying paths.

sannajammeh avatar Mar 08 '23 16:03 sannajammeh

I have project with baseUrl and without paths.

243083df avatar Mar 14 '23 14:03 243083df

@kdy1 Are there any plans to implement this in the immediate future (using baseUrl without paths specified)?

Currently using webpack for module resolution which then calls into SWC.

tayler-king avatar Mar 23 '23 22:03 tayler-king

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

swc-bot avatar May 21 '23 12:05 swc-bot