Skip to content

Instantly share code, notes, and snippets.

@nerdyman
Last active March 5, 2024 01:25
Show Gist options
  • Star 58 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save nerdyman/2f97b24ab826623bff9202750013f99e to your computer and use it in GitHub Desktop.
Save nerdyman/2f97b24ab826623bff9202750013f99e to your computer and use it in GitHub Desktop.
Convert TypeScript tsconfig paths to webpack alias paths
const { resolve } = require('path');
/**
* Resolve tsconfig.json paths to Webpack aliases
* @param {string} tsconfigPath - Path to tsconfig
* @param {string} webpackConfigBasePath - Path from tsconfig to Webpack config to create absolute aliases
* @return {object} - Webpack alias config
*/
function resolveTsconfigPathsToAlias({
tsconfigPath = './tsconfig.json',
webpackConfigBasePath = __dirname,
} = {}) {
const { paths } = require(tsconfigPath).compilerOptions;
const aliases = {};
Object.keys(paths).forEach((item) => {
const key = item.replace('/*', '');
const value = resolve(webpackConfigBasePath, paths[item][0].replace('/*', '').replace('*', ''));
aliases[key] = value;
});
return aliases;
}
module.exports = resolveTsconfigPathsToAlias;
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./dist",
"allowJs": true,
"target": "es6",
"jsx": "react",
"sourceMap": true,
"noImplicitAny": true,
"strictNullChecks": true,
"baseUrl": "./",
"lib": [
"DOM",
"ES5",
"ES6",
"es2017.object"
],
"paths": {
"Root/*": ["src/*"],
"Components/*": ["src/components/*"],
"Data/*": ["src/data/*"],
}
},
import Banner from 'Components/banner';
// add paths to webpack
const resolveTsconfigPathsToAlias = require('./resolve-tsconfig-path-to-webpack-alias');
module.exports = {
// ...
resolve: {
// ...
alias: resolveTsconfigPathsToAlias({
tsconfigPath: '../tsconfig.json', // Using custom path
webpackConfigBasePath: '../', // Using custom path
}),
}
}
@chrisabrams
Copy link

I can confirm this worked for me!

@Paradoxia
Copy link

I use IntelliJ and it uses tsconfig.json to resolve stuff in the IDE. Your code works perfectly. Thank you very much :)

@eralvarez
Copy link

this worked for me too, thx!

@bndynet
Copy link

bndynet commented Jan 7, 2019

Great! I look for it some days.

@ridaamirini
Copy link

+1

@adjiganoff
Copy link

Working, yay!

@arzyu
Copy link

arzyu commented Sep 10, 2019

@UberMouse
Copy link

One problem I encountered, if you have an alias such as "root" which is aliased to the root of your source code. Set up like this
"root": ["*"]
Then it will incorrectly be expanded to ${webpackConfigBasePath}/* instead of ${webpackConfigBasePath}. This can be fixed by appending .replace("*", "") to line 19

@nerdyman
Copy link
Author

nerdyman commented Oct 3, 2019

Is that a common use case UberMouse? I haven't seen root aliased by * before, would using * not include node_modules too?

Usually, I use "Root/*": ["src/*"].

Also, glad people found this useful! 😄

@UberMouse
Copy link

It's probably not, just a quirk of how ours are setup (our path prefixes point directly to src/ in your example, not to the folder containing src).

Definitely useful, I used to maintain three mappings. One for tsconfig, one for jest and one for Webpack. I set this up yesterday and a Jest equivalent the other day so now I just need to maintain one set of mapping which is great.

@nicolad
Copy link

nicolad commented Feb 6, 2020

Works great, many thx @nerdyman

@phuctm97
Copy link

phuctm97 commented Apr 12, 2020

Great idea! Thank you!

However, there're couple of things can be improved. I wrote my modification which helps improve:

  • Handle and ignore cases in which paths.values is empty.
  • Cleaner code as it's written in a more declarative manner.
  • More performant as it doesn't alter the object, instead it returns a constant which can be cached by either Node.js or Webpack.

See https://gist.github.com/phuctm97/7470a3b981fd80a501b4047e1e99a9f4 for more details or appreciation. Thank you!

const path = require('path');

/**
 * Helper function infers Webpack aliases from tsconfig.json compilerOptions.baseUrl and
 * compilerOptions.paths.
 *
 * @param {string} tsconfigPath - Path to tsconfig.json (Can be either relative or absolute path).
 * @return {object} An object representing corresponding Webpack alias.
 */
module.exports = (tsconfigPath = './tsconfig.json') => {
  const tsconfig = require(tsconfigPath);
  const { paths, baseUrl } = tsconfig.compilerOptions;

  return Object.fromEntries(Object.entries(paths)
    .filter(([, pathValues]) => pathValues.length > 0)
    .map(([pathKey, pathValues]) => {
      const key = pathKey.replace('/*', '');
      const value = path.resolve(path.dirname(tsconfigPath),
        baseUrl, pathValues[0].replace('/*', ''));
      return [key, value];
    }));
};

@jraoult
Copy link

jraoult commented Apr 29, 2020

Not sure you folks are aware of this https://www.npmjs.com/package/tsconfig-paths-webpack-plugin. May be it can help someone in the future.

@cdpark0530
Copy link

cdpark0530 commented Dec 31, 2020

At lease tsconfig-paths-webpack-plugin doesn't work with webpack:^5:11.1 as it seems now.
I really appreciate this @nerdyman

@MisaGu
Copy link

MisaGu commented Feb 9, 2021

Not sure you folks are aware of this https://www.npmjs.com/package/tsconfig-paths-webpack-plugin. May be it can help someone in the future.

this plugins replaces the context of resolve.alias object so u will not be able to add any custom aliases to your webpack configuration, and will be left in hands with only the one mentioned in tsconfig - what is kinda .... complicated )

@hansoksendahl
Copy link

@MisaGu Have you heard of the spread operator?

// add paths to webpack

const resolveTsconfigPathsToAlias = require('./resolve-tsconfig-path-to-webpack-alias');

module.exports = {
  // ...
  resolve: {
    // ...
    alias: {
      ...resolveTsconfigPathsToAlias({
	    tsconfigPath: '../tsconfig.json', // Using custom path
	    webpackConfigBasePath: '../', // Using custom path
      }),
      Utilities: path.resolve(__dirname, 'src/utilities/'),
      Templates: path.resolve(__dirname, 'src/templates/'),
    }
  }
}

@hansoksendahl
Copy link

hansoksendahl commented May 12, 2022

@nerdyman It seems to me that this gist is missing the baseUrl. I had to edit to this to get it working.

const { resolve } = require('path');

/**
 * Resolve tsconfig.json paths to Webpack aliases
 * @param  {string} tsconfigPath           - Path to tsconfig
 * @param  {string} webpackConfigBasePath  - Path from tsconfig to Webpack config to create absolute aliases
 * @return {object}                        - Webpack alias config
 */
function resolveTsconfigPathsToAlias({
  tsconfigPath = './tsconfig.json',
  webpackConfigBasePath = __dirname,
} = {}) {
  const { paths, baseUrl } = require(tsconfigPath).compilerOptions;

  const aliases = {};

  Object.keys(paths).forEach((item) => {
    const key = item.replace('/*', '');
    const value = resolve(webpackConfigBasePath, baseUrl, paths[item][0].replace('/*', '').replace('*', ''));

    aliases[key] = value;
  });

  return aliases;
}

module.exports = resolveTsconfigPathsToAlias;

@its-dibo
Copy link

there is an issue in this configuration, because the first matched alias is selected instead of the most specific one

@christophediprima
Copy link

@its-dibo moved more specific first in the tsconfig paths as a workaround...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment