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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect sourcemaps are being generated with @parcel/transformer-typescript-tsc #7570

Closed
iSplasher opened this issue Jan 18, 2022 · 8 comments

Comments

@iSplasher
Copy link

iSplasher commented Jan 18, 2022

馃悰 bug report

A sourcemap bug occurs when using

"transformers": {
    "*.{ts,tsx}": [
      "@parcel/transformer-typescript-tsc"
    ]
  }

You get duplicate entries in the sources field in the generated .map file.

"sources": [
   "node_modules/@parcel/runtime-browser-hmr/lib/runtime-2c252ac6c9223f3b.js",
   "packages/a/src/server.ts",
   "server.ts",
   "packages/b/src/index.ts",
   "index.ts",
   "node_modules/@parcel/transformer-js/src/esmodule-helpers.js",
   "packages/b/src/same.ts",
   "same.ts",
   "packages/a/src/same.ts"
 ],

Only the subsequent sources that only refer to the filenames are mapped (server.ts, index.ts, same.ts),
but these obviously point nowhere relative to the sourceRoot so they are invalid.

Additionally, if two filenames are identical when importing from another package in the mono repo,
their entries get overridden (notice how there is only one same.ts).

You can easily see this if you inspect the sourcemap on https://sourcemap-visualiser.vercel.app/
A sourcemap-info.json file has already been generated in the repro repo.

If you remove the transformer plugin from .parcelrc, correct sourcemaps are generated.

馃帥 Configuration (.babelrc, package.json, cli command)

{
  "extends": "@parcel/config-default",
  "reporters": [
    "...",
    "@parcel/reporter-sourcemap-visualiser"
  ],
  "transformers": {
    "*.{ts,tsx}": [
      "@parcel/transformer-typescript-tsc"
    ]
  }
}

馃 Expected Behavior

Correct sourcemap gets generated

  "sources": [
    "node_modules/@parcel/runtime-browser-hmr/lib/runtime-4af8d787c6a99a6a.js",
    "packages/a/src/server.ts",
    "packages/b/src/index.ts",
    "packages/b/src/same.ts",
    "node_modules/@parcel/transformer-js/src/esmodule-helpers.js",
    "packages/a/src/same.ts"
  ]

馃槸 Current Behavior

An incorrect sourcemap is generated

"sources": [
   "node_modules/@parcel/runtime-browser-hmr/lib/runtime-2c252ac6c9223f3b.js",
   "packages/a/src/server.ts",
   "server.ts",
   "packages/b/src/index.ts",
   "index.ts",
   "node_modules/@parcel/transformer-js/src/esmodule-helpers.js",
   "packages/b/src/same.ts",
   "same.ts",
   "packages/a/src/same.ts"
 ],

馃拋 Possible Solution

A workaround is to not use the the tsc transformer plugin, so remove this

"transformers": {
    "*.{ts,tsx}": [
      "@parcel/transformer-typescript-tsc"
    ]
  }

but this is not an option for me due to #7425

馃捇 Code Sample

I've set up a full reproduction of the issue here https://github.com/iSplasher/parcel-sourcemap-bug

馃實 Your Environment

Software Version(s)
Parcel 2.2.1
Node 16.13.2
npm/Yarn 3.1.1
Operating System Windows 11
@iSplasher iSplasher changed the title Incorrect souremaps are being generated with @parcel/transformer-typescript-tsc Incorrect sourcemaps are being generated with @parcel/transformer-typescript-tsc Jan 18, 2022
@iSplasher
Copy link
Author

iSplasher commented Jan 18, 2022

I played around with the transformer and found out that if we don't pass the sourceMap option, it'll work.

sourceMap: !!asset.env.sourceMap,

EDIT:
It will generate mappings based on the transpiled sources of course, which is not ideal, but I can live with that until this gets fixed

@iSplasher
Copy link
Author

Back at it again and after entering a deep rabbit hole I think I've fixed it, at least for my own use case.
I sourced the issue to this PR #7287 which tried to fix a similar issue. While it may have fixed the other issue, I think the change was insufficient. After reading the docs about source maps and also looking at how the babel transformer does it, I managed to figure out that I had to extend the original source map, if there was one, and also transform the paths returned by typescript.
I'm not confident in knowing Parcel's internals enough to push a PR but here's my custom transformer with the fix.

import type { TranspileOptions } from 'typescript';

import typescript from 'typescript';

import { Transformer } from '@parcel/plugin';
import SourceMap from '@parcel/source-map';
import { loadTSConfig } from '@parcel/ts-utils';
import { relativeUrl } from '@parcel/utils';

export default new Transformer({
  loadConfig({ config, options }) {
    return loadTSConfig(config, options);
  },

  async transform({ asset, config, options }) {
    asset.type = 'js';

    let code = await asset.getCode();

    let transpiled = typescript.transpileModule(code, {
      compilerOptions: {
        // React is the default. Users can override this by supplying their own tsconfig,
        // which many TypeScript users will already have for typechecking, etc.
        jsx: typescript.JsxEmit.React,
        ...config,
        // Always emit output
        noEmit: false,
        // Don't compile ES `import`s -- scope hoisting prefers them and they will
        // otherwise compiled to CJS via babel in the js transformer
        module: typescript.ModuleKind.ESNext,
        sourceMap: !!asset.env.sourceMap,
      },
      fileName: asset.filePath, // Should be relativePath?
    } as TranspileOptions);

    const originalMap = await asset.getMap();

    let map: SourceMap;
    let { outputText, sourceMapText } = transpiled;
    if (sourceMapText != null) {
      map = new SourceMap(options.projectRoot);
      type Writeable<T> = { -readonly [P in keyof T]: Writeable<T[P]> };

      const sourcePath = relativeUrl(options.projectRoot, asset.filePath);

      const jsourceMap = JSON.parse(sourceMapText) as Writeable<
        Parameters<typeof map['addVLQMap']>[0]
      >;

      jsourceMap.file = sourcePath;

      // replace path with one relative to root
      jsourceMap.sources[0] = sourcePath;

      map.addVLQMap(jsourceMap);

      // extend original if there is one
      if (originalMap) {
        map.extends(originalMap.toBuffer());
      }

      outputText = outputText.substring(
        0,
        outputText.lastIndexOf('//# sourceMappingURL')
      );
    }

    return [
      {
        type: 'js',
        content: outputText,
        map,
      },
    ];
  },
});

@iSplasher
Copy link
Author

@ImpendingDoom28
I suggest looking at how other transformers are structured.
Parcel needs plugins to be installed so in short what you need to do is:

  1. create a new project with a package.json, remember to add "engines": { "parcel": "2.x"} and set source and main
  2. copy above code in the main file
  3. use npx or yarn dlx: npx parcel@latest build to build and bundle the typescript code
  4. install the package locally or publish to github so you can just add "<you-package>": "<github-url>" to your package.json
  5. add your plugin to .parcelrc like you would any other plugins, in this case, replace "@parcel/transformer-typescript-tsc".

I'm using a mono repo so in my case it was a simple matter of adding it under packages/

@ImpendingDoom28
Copy link

ImpendingDoom28 commented Jan 28, 2022

@iSplasher Thank you with for this detailed explanation and transformer! Maybe you consider to add it to the NPM registry? Or maybe I can try to do it...

@ImpendingDoom28
Copy link

ImpendingDoom28 commented Jan 29, 2022

I tried to create NPM package for this and it works like a charm! I'll give the credits to you @iSplasher

Leaving a link for everyone, who wants to install it: https://www.npmjs.com/package/parcel-transformer-tsc-sourcemaps

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.

@github-actions github-actions bot added the Stale Inactive issues label Jul 29, 2022
@Duckers
Copy link

Duckers commented Dec 30, 2022

I tried to create NPM package for this and it works like a charm! I'll give the credits to you @iSplasher

Leaving a link for everyone, who wants to install it: https://www.npmjs.com/package/parcel-transformer-tsc-sourcemaps

This worked! Life saving. A shame this doesn't work out of the box with the regular Parcel transformer

@github-actions github-actions bot removed the Stale Inactive issues label Dec 30, 2022
@mischnic
Copy link
Member

mischnic commented Jan 1, 2023

PR to fix this: #8734

brennie added a commit to mozilla/limelight that referenced this issue Jan 25, 2023
Correct sourcemaps for TypeScript files will now be generated. (See
parcel-bundler/parcel#7570 for more details.)
brennie added a commit to mozilla/limelight that referenced this issue Jan 25, 2023
Correct sourcemaps for TypeScript files will now be generated. (See
parcel-bundler/parcel#7570 for more details.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants