dividab / tsconfig-paths-webpack-plugin

Load modules according to tsconfig paths in webpack.
MIT License
597 stars 51 forks source link

Modules mapped through tsconfig.json risk being bundled differently than the same module mapped with default Webpack resolution #22

Open christoffer opened 6 years ago

christoffer commented 6 years ago

Some context from: https://github.com/dividab/tsconfig-paths/pull/46:

The browser field supports objects as well as strings to allow more specific overrides than a single file: unofficial, but most prominent, spec.

It seems like Webpack supports this spec: https://github.com/christoffer/webpack-resolution-example, and while the PR above (if merged) will adopt a part of the behavior, it would probably be a good idea to support the same behavior so that users end up with the same bundle whether or not the path is mapped through tsconfig-paths or a webpack alias.

For example, a module containing a package.json file like:

{
  "name": "my-module",
  "main": "./main.js",
  "browser": {
    "./main.js": "browser.js"
  }
}

would bundle "main.js" if a pattern in tsconfig.json matches the module path, but "browser.js" if not (on account to falling back to the Webpack standard resolver).

majo44 commented 4 years ago

I noticed this issue when I tried to use paths mapping like:

{
    "compilerOptions": {
        ...
        "paths": {
            "*": [
                "*",
                "./node_modules/@types/*",
                "./node_modules/*",
                "./packages/*"
            ]
        }
    }
}

The browser field from package.json is not interpreted in same way as is done by webpack: https://webpack.js.org/configuration/resolve/#resolvealiasfields , "Specify a field, such as browser, to be parsed according to this specification" : https://github.com/defunctzombie/package-browser-field-spec

cyrilchapon commented 4 years ago

I'm having a huge treeshaking issue, which I suspect is related to what's explained here.

Setup

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ES2020",
    "lib": ["ES2020", "DOM"],
    "jsx": "react",

    "rootDir": "./src",
    "noEmit": true,

    "strict": true,

    "moduleResolution": "node",
    "baseUrl": "./",
    "paths": {
      "$components/*": ["src/components/*"],
      "*": ["node_modules/*"]
    },
    "esModuleInterop": true,

    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

webpack.config.ts

const path = require("path");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;
const { TsconfigPathsPlugin } = require("tsconfig-paths-webpack-plugin")

module.exports = {
  mode: "production",
  entry: {
    main: [
      "./src/index"
    ]
  },
  resolve: {
    extensions: [".js", ".jsx", ".ts", ".tsx"],
    plugins: [new TsconfigPathsPlugin()]
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /\.(j|t)sx?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  plugins: [new BundleAnalyzerPlugin()]
};

Sources

src /
  index.tsx
  components /
    heading.tsx
    index.tsx
tsconfig.json
webpack.config.ts

Result

If I comment this plugins: [new TsconfigPathsPlugin()], I get that =>

Capture d’écran 2020-07-16 à 15 59 01

But if I leave plugins: [new TsconfigPathsPlugin()], I get this =>

Capture d’écran 2020-07-16 à 15 59 10

Assumptions

The trouble is when parsing this line

import { faCoffee } from "@fortawesome/free-solid-svg-icons";

As you can see

cyrilchapon commented 4 years ago

EDIT:

This line

"*": ["node_modules/*"]

Seems to cause the issue.