Reputation: 8551
I try to shorten my imports in typescript
from import {Hello} from "./components/Hello";
to import {Hello} from "Hello";
For that I found out you can use resolve.alias
in webpack thus I configured that part as following
resolve: {
root: path.resolve(__dirname),
alias: {
Hello: "src/components/Hello"
},
extensions: ["", ".ts", ".tsx", ".js"]
},
Webpack builds, and the output bundle.js works. However typescript's intellisense complain it cannot find the module
So my question is whether or not webpack's resolve.alias works with typescript?
I found following issue but there's no answer to it.
Upvotes: 86
Views: 91034
Reputation: 165
In react 18/nextjs 14, typescript, storybook 7, this is what worked for me to mock a hook that is a named export (not a default export):
// .storybook/main.ts in the config setup
webpackFinal: async (config: Configuration, { configType }) => {
const myMock = path.resolve(
__dirname,
'../apps/src/myFunctionOrHookName'
);
config.resolve.alias = {
...config.resolve?.alias,
[myMock]: require.resolve(
'../__mocks__/myFunctionOrHookName'
),
};
}
Note:
myMock
is actually the resolved path of where the real import
sits currently in relation to the storybook main.ts
sits.myMock
is wrapped in square brackets []
as we need to have it calculated before webpack takes it as a string
type key which is what it's expecting..js
but we don't need to include it in the alias path.You might also find that because config's resolve
is optional, your linter goes crazy. I wrapped mine in an if
so it looked like below, so that I could try and force it to not silently fail if it was missing for whatever reason. So far it's never reached that else
(fingers crossed).
const myMock = path.resolve(
__dirname,
'../apps/src/myFunctionOrHookFileName'
);
if (config.resolve) {
config.resolve.alias = {
...config.resolve.alias,
[myMock]: require.resolve('../__mocks__/myFunctionOrHookFileName'),
}
} else {
throw new Error('Resolve should exist on Webpack build step');
}
Upvotes: 2
Reputation: 754
It's not good practice to use alias for just 1 particular component and you should tell to webpack config that you have existing aliases setup in my ts-config by using tsconfig-paths-webpack-plugin, here is the sample config
// webpack.config.js
module.exports = {
...
resolve: {
plugins: [new TsconfigPathsPlugin({/* options: see below */})]
}
...
}
//ts-config.json
{
"compilerOptions": {
"baseUrl": "./src",
"components/*": "components/*"
...
},
...
}
and second solution, you might as well manual resolve the issue by specifying the aliases what you want in webpack.config
, but if you don't want, you may follow the above config
// webpack.config.js
module.export = {
resolve: {
alias: {
'components': path.resolve(__dirname, 'src/components')
}
}
}
remember the role of tsconfig
or jsconfig
is to provide an intellisense to your editor and give direction to your bundler
//ts-config.json
{
"compilerOptions": {
"baseUrl": "./src",
"components/*": "components/*"
...
},
...
}
either what solution you chose, you should still use it as this
import {Home} from 'components';
...
and if you are out of your curiosity how webpack.config
rely on your tsconfig.json
, you may read ts-loader
Upvotes: 1
Reputation: 685
You can also configure tsconfig-paths-webpack-plugin
in order not to duplicate your aliases in several places. It will pick up aliases from tsconfig.json
file and automatically add them to webpack.
Upvotes: 14
Reputation: 1090
You are missing one very important point in tsconfig.json
:
The matching pattern!
It should be configured like this:
"baseUrl": ".",
"paths": {
"appSrc/*": [
"src/*"
]
}
The "*" is the important part to tell TS to match anything on the right side.
I found that out from this article: Type-safe es2015 module import path aliasing with Webpack, Typescript and Jest
NOTE
webpack.config.js
are updated (e.g. if you use
storybook). Upvotes: 96
Reputation: 464
There are 2 cases
"baseUrl": "./src"
in tsconfig and see the code work.Upvotes: 1
Reputation: 52867
As others have mentioned, you need to provide an alias
in your webpack.config.js:
resolve: {
extensions: [".ts", ".js"],
alias: {
forms: path.resolve(__dirname, "src/forms/")
}
},
This needs to be in synch with your tsconfig.json
file (baseUrl and paths are required).
"compilerOptions": {
baseUrl: "./",
...
paths: {
"forms/*": ["src/forms/*"]
}
}
Note: The wildcard pattern is necessary to match with your resolve alias configuration.
Then you can import any library using your alias:
import { FormsModule } from "forms/my-forms/my-forms.module";
Upvotes: 46
Reputation: 600
If anyone still have this issue, don't forget to add your folder to the "include" option on tsconfig.json like this:
{
"compilerOptions": {
"sourceMap": true,
"allowJs": true,
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
},
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"lib": [
"es2016",
"dom"
]
},
"outDir": "./built/",
"include": [
"./src/**/*",
"./tests/**/*"
]
}
Upvotes: 12
Reputation: 1196
I had to make a small adjustment to Caio Saldanha's solution to make it work in my environment.
I am using Babel 7 with babel-plugin-module-resolver
to resolve aliases. No ts-loader
or awesome-typescript-loader
as Babel 7 supports TypeScript out of the box using @babel/preset-typescript
. I had to add an extra path configuration for each alias to load the module root (e.g. index.ts
) automagically:
"baseUrl": ".",
"paths": { // this must be synchronized with .babelrc.js's module-resolver alias config
"component": ["src/component/index.ts"],
"component/*": ["src/component/*"],
...
}
Having an index.ts
in the /component
folder with the following content:
export { default as Logo } from './Logo';
Without the extra .../index.ts
line this import didn't work for me:
import { Logo } from 'component';
Alias config in .babelrc.js
:
plugins: [
[
'module-resolver',
{
extensions: ['.js', '.jsx', '.ts', '.tsx'],
root: ['./src'],
alias: {
// this must be synchronized with tsconfig.json's path configuration
component: './src/component',
},
},
],
Upvotes: 5
Reputation: 23483
If you're using ts-loader
, you might have to synchronize your webpack alias
/resolve
settings with your paths
setting in your tsconfig.json
.
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"Hello": ["src/components/Hello"]
}
}
}
If you're using awesome-typescript-loader
, then webpack can figure this out automatically from the paths
setting in your tsconfig.json
, as per the status on this issue from the repo. That way, you don't need to duplicate the same information in your Webpack alias
field.
Upvotes: 104
Reputation: 9386
I think you can do this and have it work the way you describe:
resolve: {
root: [
path.resolve(__dirname),
<path_to_components_directory> //e.g. path.resolve(__dirname, 'src', 'components')
],
extensions: ["", ".ts", ".tsx", ".js"]
},
Then you can do import {Hello} from "Hello";
I know I do this to resolve file paths in my src/js
directory. I am not using typescript though, but I don't think it would affect the result.
Upvotes: -3