egoist / tsup

The simplest and fastest way to bundle your TypeScript libraries.
https://tsup.egoist.dev
MIT License
8.89k stars 213 forks source link

How can I make tsup resolve my typescript absolute import paths? #905

Open isomorpheric opened 1 year ago

isomorpheric commented 1 year ago

:wave: Hi and thank you so much for your work ❤️ 🤟🏼

Description

tsup is not resolving typescript absolute imports. I have a tsconfig.json that defines multiple absolute imports (see below). tsup bundles it without resolving for those absolute imports, so it causes errors when consuming the lib in other projects.

In your docs, I can see NormalizedOptions - which uses tsconfigResolvePaths - but when I try to put it in my config (see below) typescript gets angry 😠:

'tsconfigResolvePaths' does not exist in type 'Options | Options[] | ((overrideOptions: Options) => MaybePromise<Options | Options[]>)'

tsconfig.json:

"compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@services/*": [
        "./services/*"
      ],
      "@vendors/*": [
        "./vendors/*"
      ],
// ....
    },

tsup.config.json:

import { defineConfig } from 'tsup';

export default defineConfig({
  entry: {
    index: 'index.ts',
    'services/marketing/index': 'services/marketing/index.ts',
    'vendors/index': 'vendors/index.ts',
  },
  tsconfig: './tsconfig.json',
  splitting: false,
  sourcemap: true,
  clean: true,
});

Upvote & Fund

Fund with Polar

wojtekKrol commented 11 months ago

have the same issue

dheerajsinghnagdali commented 10 months ago

I have the same issue as well.

undermuz commented 6 months ago

have the same issue

PureSci commented 5 months ago

this is still an issue

mehrangta commented 4 months ago

Any updates/workarounds on this ?

PHILLIPS71 commented 2 months ago

I'm encountering the same problem and have been using https://github.com/benyap/resolve-tspaths as a workaround. However, it doesn't function when minify is enabled 😞. It would be great if this feature were natively supported and working properly.

ThijsZijdel commented 1 month ago

bump..

Tomas2D commented 2 weeks ago

bump

Tomas2D commented 2 weeks ago

Since I have emitDecoratorMetadata: true in my tsconfig, tsup uses @swc/core to process it. But the problem is that tsup does not propagate related TSConfig information to the swc (here is the SWC plugin that I am talking about). However, there is a way how to do this.

My updated tsup.config.ts (simplified)

import { defineConfig } from "tsup";
import packageJson from "./package.json";
import swc, { JscConfig } from "@swc/core";
import type { JscTarget } from "@swc/types"; // 
import path from "node:path";

import tsConfig from "./tsconfig.json"; // important

export default defineConfig({
  entry: ["src/**/*.{ts,js}", "!src/**/*.test.ts"],
  tsconfig: "./tsconfig.json",
  sourcemap: true,
  dts: true,
  format: ["esm", "cjs"],
  plugins: [
    {
      name: "override-swc",
      esbuildOptions: (options) => {
        const plugin = options.plugins?.find((p) => p.name === "swc");
        if (plugin) {
          // Original Source: https://github.com/egoist/tsup/blob/49c11c3073ce977a01c84e7848fc070d5de0a652/src/esbuild/swc.ts#L14-L67
          // Reason: tsup does not provide a way to modify 'jsc' config
          plugin.setup = (build) => {
            // Force esbuild to keep class names as well
            build.initialOptions.keepNames = true;

            build.onLoad({ filter: /\.[jt]sx?$/ }, async (args: any) => {
              const isTs = /\.tsx?$/.test(args.path);

              const jsc: JscConfig = {
                parser: {
                  syntax: isTs ? "typescript" : "ecmascript",
                  decorators: true,
                },
                transform: {
                  legacyDecorator: true,
                  decoratorMetadata: true,
                },
                baseUrl: path.resolve(__dirname, tsConfig.compilerOptions.baseUrl || "."),  // this was missing
                paths: tsConfig.compilerOptions.paths,  // this was missing
                keepClassNames: true,
                target: (tsConfig.compilerOptions.target || "es2022").toLowerCase() as JscTarget,
              };

              const result = await swc.transformFile(args.path, {
                jsc,
                sourceMaps: true,
                configFile: false,
                swcrc: false,
              });

              let code = result.code;
              if (result.map) {
                const map: { sources: string[] } = JSON.parse(result.map);
                // Make sure sources are relative path
                map.sources = map.sources.map((source) => {
                  return path.isAbsolute(source)
                    ? path.relative(path.dirname(args.path), source)
                    : source;
                });
                code += `//# sourceMappingURL=data:application/json;base64,${Buffer.from(
                  JSON.stringify(map),
                ).toString("base64")}`;
              }
              return {
                contents: code,
              };
            });
          };
        }
      },
    },
  ],
  treeshake: true,
  shims: true,
  skipNodeModulesBundle: true,
  legacyOutput: false,
  bundle: false,
  splitting: false,
  silent: false,
  clean: true
});