React imports since src [duplicate] - javascript

I'm struggling to get absolute path to work in a Vite react-ts project.
Here's how I created the project
npm init #vitejs/app
npx: installed 6 in 1.883s
√ Project name: ... test-vite
√ Select a framework: » react
√ Select a variant: » react-ts
Then I added baseUrl to tsconfig.json
based on the TS official doc:
{
"compilerOptions": {
"baseUrl": "./src",
...
followed by adding a simple component (T:\test-vite\src\components\Test.tsx)
import React from "react";
const Test = () => <h1>This is a Test.</h1>;
export default Test;
Finally I import the Test component in App.tsx
but it won't let me use absolute path:
import Test from "components/Test";
I get this error
whereas if I use relative path, the app works in dev & build mode without any error:
import Test from "./components/Test";
How can I make absolute path work in the project?

There are two problems here:
Tell typescript how to resolve import path
Tell vite how to build import path
You only tell typescript how to resolve, but vite don't konw how to build. So refer to the official document resolve.alias, maybe this is what you want:
// vite.config.ts
{
resolve: {
alias: [
{ find: '#', replacement: path.resolve(__dirname, 'src') },
],
},
// ...
}
You can import path like this (or any module under ./src):
import Test from "#/components/Test";
import bar from "#/foo/bar"
Moreover, you can use vite plugin vite-tsconfig-paths directly, it makes you don't have to manually configure resolve.alias
Follow the instructions below:
Install vite-tsconfig-paths as dev dependency
Inject vite-tsconfig-paths using the vite.config.ts module
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [tsconfigPaths()],
})

I came here through search results, I was looking for something different, namely, how to do a simple absolute import like import { foo } from 'src/lib/foo.ts'
So if you have a /src directory that contains all code and want to use an absolute import path.
vite.config.ts
export default defineConfig({
...
resolve: {
alias: {
src: path.resolve('src/'),
},
}
})
tsconfig.json
{
"compilerOptions": {
...
"baseUrl": "./"
}
}
Note that this is a trick: src is an alias, so it appears like the path is absolute in Vite. If you have another directory in the root dir, adjacent to /src, you will need to add another alias for that directory.

#Yuns solutions works, but it shows error in vscode. And it was breaking auto-import in vs code.
To make it work in vscode and vite both, I added alias in both tsconfig and vite.config.
// tsconfig.json
{
"paths": {
"#/*": ["src/*"]
}
// ...
}
// vite.config.ts
{
resolve: {
alias: [{ find: '#', replacement: '/src' }],
},
// ...
}
Then, I could import like below (svelte app is in src directory)
import Header from '#/components/Header.svelte

Looking for import {...} from "src/foo/bar";?
I also came here through search results like user Maciej Krawczyk, but the # part also wasn't what I was interested in. That user's answer helped me, but I had trouble with the path.resolve part (ReferenceError because path wasn't defined), so I used a slightly different approach:
vite.config.ts
export default defineConfig({
...
resolve: {
alias: {
src: "/src",
},
},
...
})
Vite's resolver considers the absolute path /src to be from where the server is serving (see GH issue). So if you're running/building from the root of your project with src as a top level directory -- which is pretty common -- this alias points Vite in the right direction.
tsconfig.json
{
"compilerOptions": {
...
"baseUrl": "./",
"paths": {
"src/*": [
"./src/*"
]
}
}
}
This is basically blindly following this StackOverflow answer. TypeScript needs to know that we have special resolving going on as well, otherwise TS will be freaked out about your non-existent src package and not know where it should go looking. (Note: After I changed my TS config, VSCode didn't immediately pick up the change, so I was still getting warnings. I quit, re-opened, and had to wait ~15sec for the warnings to go away.)

1) You need to install these packages:
npm i path
yarn add path
npm i #types/node
yarn add #types/node
npm i vite-tsconfig-paths
yarn add vite-tsconfig-paths
2) Then in the vite.config file:
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import path from 'path';
export default defineConfig({
base: './',
resolve: {
alias: {
Components: path.resolve(__dirname, './src/components'),
Assets: path.resolve(__dirname, './src/assets'),
},
},
plugins: [react(), tsconfigPaths()],
});
3) And now we have to tell TS those same paths that we defined in the alias:
{
"compilerOptions": {
...,
"baseUrl": "./",
"paths": {
"src/*": [ "./src/*" ],
// We define this path for all files/folders inside
// components folder:
"Components/*": [ "./src/components/*" ],
// We define this path for the index.ts file inside the
// components folder:
"Components": [ "./src/components" ],
"Assets/*": [ "./src/assets/*" ],
"Assets": [ "./src/assets" ]
}
},
...
}
4) reload vscode: As the comment above said, press Fn1 and type "reload with extensions disabled", re-enabling extensions from the popup.
Now try to import
import Test from "components/Test";
it should work.

For anyone looking specifically to add the nice import "#/something-in-src" syntax like Vue has with the latest (as of posting this answer) version of Vite + React + TypeScript, here's how I did it:
Make sure #types/node is installed as a dev dependency. This didn't come with the latest version of Vite for me, and it will make "path" and __dirname throw an undefined error.
vite.config.ts
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: [{ find: "#", replacement: path.resolve(__dirname, "src") }],
},
plugins: [react()],
});
tsconfig.json
Add:
{
"compilerOptions": {
"paths": {
"#/*": ["./src/*"]
}
}
}

For anyone who stucks after all required changes, you need to reload vscode.
My config files:
tsconfig.json
"baseUrl": "./",
"paths": {
"#/*": ["src/*"]
}
vite.config.ts
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: { '#': path.resolve(__dirname, './src') },
},
plugins: [react()],
});
In above code you need to have 2 libraries installed:
'path': npm i path
'#types/node': npm i #types/node
After configure your project files you need to reload vscode. To do that press ctrl + P and type ">reload with extensions disabled", after that you will get popUp to activate extensions again click it, and your absoulte path should work
If someone installed vite-tsconfig-paths library, you also need to reload the vscode, remember to import given library to vite.config.ts
export default defineConfig({ plugins: [react(), tsconfigPaths()] });
With package you get default 'components/File' import instead of '#components/File' import.

Related

React alias - module not found / javascript webpack

I'm trying to set up an alias in my app built with create-react-app .
I don't use typescript . The IDE (WebStorm) sees my alias paths. Shows the contents of a folder. But when I refresh the page, I get the error:
Module not found: Error: Can't resolve '#HomePage/HomePage' in 'C:\Users\ASUS\WebstormProjects\spnew\client\src'
I'm going to add the HomePage component which is in the HomePage folder.
My way:
1) I made an eject
2) Created a 'jsconfig.json' file in the root directory with react
{
"compilerOptions": {
"baseUrl": ".",
paths: {
"#HomePage/*": ["./src/pages/HomePage/*"]
}
},
"exclude": ["node_modules"]
}
p.s. tried without #, tried to remove './'
p.s.s. after adding this file, the IDE reacts to:
import {...} from "#HomePage/"; tells you what files are in this folder.
3) The auto-generated webpack.config.js file has very few features.
On the Internet they write what needs to be done like this:
modules.exports = {
resolve: {
extensions: ['.js', '.jsx'],
alias: {
Components: path.resolve(__dirname, '../src/components/'),
}
},
...
resolve: {
...
}
}
I already have over 700 lines in this file!
But the structure is the same. I found module.exports which has nested resollve which has nested alias. And added a line with the path.
It looks like this:
alias: {
HomePage: path.resolve(__dirname, "../src/pages/HomePage"),
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
// Allows for better profiling with ReactDevTools
...(isEnvProductionProfile && {
'react-dom$': 'react-dom/profiling',
'scheduler/tracing': 'scheduler/tracing-profiling',
}),
...(modules.webpackAliases || {}),
}
p.s. I tried to write the path './' '../' and without it.
When importing, I get the same error!
Compiled with problems:X
ERROR in ./src/routes.js 9:0-46
Module not found: Error: Can't resolve '#HomePage/HomePage' in 'C:\Users\ASUS\WebstormProjects\spnew\client\src'

SWC with JavaScript: How to handle CSS imports and how to absolute imports?

TL;DR
How can you tell SWC to compile CSS files imported in React components?
How can you tell SWC to compile absolute imports in tests and in React components?
Here is a minimal reproducible example.
Context
We're migrating from Babel to SWC. (I asked a question a little while ago. I'm improving on that question's answer.)
We're migrated the command from:
"test": "NODE_ENV=test riteway -r #babel/register 'src/**/*.test.js' | tap-nirvana",
to
"test": "SWC_NODE_PROJECT=./jsconfig.json riteway -r #swc-node/register src/**/*.test.js | tap-nirvana",
where the jsconfig.json looks like this:
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "./src",
"jsx": "react-jsx"
}
}
If we write try to compile a test for a self-contained component (no absolute imports, no CSS) it works:
import { describe } from 'riteway';
import render from 'riteway/render-component';
function HomePageComponent({ user: { email } }) {
return <p>{email}</p>;
}
describe('home page component', async assert => {
const user = { email: 'foo' };
const $ = render(<HomePageComponent user={user} />);
assert({
given: 'a user',
should: 'render its email',
actual: $('p').text(),
expected: user.email,
});
});
The test compiles fine.
With Babel we had a .babelrc like this:
{
"env": {
"test": {
"plugins": [
[
"module-resolver",
{
"root": [
"."
],
"alias": {
"components": "./src/components",
"config": "./src/config",
"features": "./src/features",
"hocs": "./src/hocs",
"hooks": "./src/hooks",
"pages": "./src/pages",
"redux": "./src/redux",
"styles": "./src/styles",
"tests": "./src/tests",
"utils": "./src/utils"
}
}
]
]
}
},
"presets": [
[
"next/babel",
{
"ramda": {}
}
]
],
"plugins": [
["styled-components", { "ssr": true }]
]
}
Where the styles where taken care of by styled-components and the absolute imports where defined via the module-resolver plugin. (We switched away from styled-components to CSS modules, which is why we import from .module.css CSS files. Anyways ...)
If we write the test how we wanted to write it with their actual imports like this:
import { describe } from 'riteway';
import render from 'riteway/render-component';
import { createPopulatedUserProfile } from 'user-profile/user-profile-factories';
import HomePageComponent from './home-page-component';
describe('home page component', async assert => {
const user = createPopulatedUserProfile();
const $ = render(<HomePageComponent user={user} />);
assert({
given: 'a user',
should: 'render its email',
actual: $('p').text(),
expected: user.email,
});
});
It fails with:
$ SWC_NODE_PROJECT=./jsconfig.json riteway -r #swc-node/register src/features/home/home-page-component.test.js | tap-nirvana
/Users/janhesters/dev/my-project/src/features/home/home.module.css:1
(function (exports, require, module, __filename, __dirname) { .container {
^
SyntaxError: Unexpected token '.'
when we leave in the CSS import in home-page-component.js, or with:
$ SWC_NODE_PROJECT=./jsconfig.json riteway -r #swc-node/register src/features/home/home-page-component.test.js | tap-nirvana
node:internal/modules/cjs/loader:936
throw err;
^
Error: Cannot find module 'user-profile/user-profile-factories'
Require stack:
- /Users/janhesters/dev/my-project/src/features/home/home-page-component.test.js
- /Users/janhesters/dev/my-project/node_modules/riteway/bin/riteway
respectively, when we get rid of the CSS import.
How can we help SWC understand CSS (or mock CSS modules) and how can we help it understand absolute imports?
We already set the baseUrl in jsconfig.json ...
About absolute path
You already add baseUrl in the jsconfig.json file but didn't add the paths, you should modify your config file like mine:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"#screens": ["./screens"],
"#shared": ["./shared"],
"#shared/*": ["./shared/*"]
},
The paths are the alias of module-resolver, and I guess your root shouldn't be ".", it should be exactly like your jsconfig.json file, I mean the baseUrl value.
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"extensions": [".ts", ".tsx", ".js", ".jsx", ".json"],
"alias": {
"#screens": "./src/screens",
"#shared": "./src/shared"
}
}
]
],
If you have Webpack, you should have alias config in your resolve key off Webpack config object, like mine:
const resolve = {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
alias: {
'#screens': path.join(__dirname, 'src/screens/'),
'#shared': path.join(__dirname, 'src/shared/'),
},
modules: ['src', 'node_modules'],
descriptionFiles: ['package.json'],
};
About CSS
Actually, you are using CSS file as CSS-Modules not like recommended NexJS doc, in docs developer should import CSS like import './styles.css' and then use it as string in JSX like <div className="main"
But
You are importing it like a module (CSS-Module):
// you did it
import styles from './styles.css';
<div className={styles.main}
As you know it is built-in support by this doc, it is supported by NextJS, but SWC cannot understand it. I put in hours to find a way for it, but it seems SWC doesn't support CSS-Module yet. you should create your own plugin for SWC to support CSS-Module.
How can we help SWC understand CSS (or mock CSS modules)? - SWC doesn't understand css natively, and neither did Babel. As you noted, when you were using Babel, the plugin styled-components took care of this. You'll need to do the same with SWC. I can't find an existing SWC plugin that does this, but you can roll your own. Obviously this is a pain, but such is the cost of using new tooling.
How can we help SWC understand absolute imports? - The .swrc options for baseUrl and paths should do what you want, but that, too, seems to have some issues.
You may have better luck creating issues directly in the #swc-node GitHub repo, but given the comments there it feels like you might be SOL for a while. Might be faster/easier to rewrite your tests using one of the libraries that Next supports out of the box.
I was able to solve all issues without writing any plugins. I pushed the solution to my example repo from the question.
Firstly, use the official SWC project's register. This means, you have to compile your tests like this:
"test": "riteway -r #swc/register 'src/**/*.test.js' | tap-nirvana",
You can install it by running:
yarn add --dev #swc/core #swc/register
We need this version of register, because it takes into account an .swcrc file, which the other one did not.
Secondly, you need both "path" and "baseUrl" to fix the absolute imports because for some reason SWC doesn't infer all paths with only a "baseUrl" provided. And you need to adapt your .swcrc to handle React.
{
"jsc": {
"baseUrl": "./src",
"paths": {
"*.css": ["utils/identity-object-proxy.js"],
"utils/*": ["utils/*"]
},
"parser": {
"jsx": true,
"syntax": "ecmascript"
},
"transform": {
"react": {
"runtime": "automatic"
}
}
},
"module": {
"type": "commonjs"
}
}
Thirdly, to solve .css you need to remap all imports to .css files to an identity object proxy, which you can see in the .swcrc example above. An identity object proxy is an object that, when you reference any property, returns the stringified key that you're trying to reference. You can create one yourself like this:
const identityObjectProxy = new Proxy(
{},
{
get: function getter(target, key) {
if (key === '__esModule') {
return false;
}
return key;
},
},
);
export default identityObjectProxy;
For the .css remap to go into effect you need to make all your imports to .css files absolute imports. (import styles from './styles.module.css won't work!)

How to make an import shortcut/alias in create-react-app?

How to set import shortcuts/aliases in create-react-app?
From this:
import { Layout } from '../../Components/Layout'
to this:
import { Layout } from '#Components/Layout'
I have a webpack 4.42.0 version.
I don't have a webpack.config.js file in the root directory. I've tried to create one myself with this code inside:
const path = require('path')
module.exports = {
resolve: {
alias: {
'#': path.resolve(__dirname, 'src/'),
}
}
};
But it doesn't seem to work. I've seen the NODE_PATH=. variant in .env file. But I believe, it is deprecated - better not to use. And also, I have a posstcss.config.js file. Because I've installed the TailwindCss and I import the CSS library there. I've tried to paste the same code there, but it also didn't work.
It is finally possible with Create React App v.3
Just put:
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
into jsconfig.json or tsconfig.json if you use Typescript
Here is wonderful article about this.
Simplest way to archive this follow below steps. (same way as #DennisVash showed as but in simple form)
Installation - install and setup CRACO.
yarn add #craco/craco
# OR
npm install #craco/craco --save
Create a craco.config.js file in the root directory and configure CRACO:
/* craco.config.js */
const path = require(`path`);
module.exports = {
webpack: {
alias: {
'#': path.resolve(__dirname, 'src/'),
'#Components': path.resolve(__dirname, 'src/components'),
'#So_on': path.resolve(__dirname, 'src/so_on'),
}
},
};
Update the existing calls to react-scripts in the scripts section of your package.json file to use the craco CLI:
/* package.json */
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test"
}
Done! Setup is completed.
Now let's test it.
// Before
import Button from "./form/Button"
import { Layout } from '../../Components/Layout'
// After
import Button from "#/form/Button"
import { Layout } from '#Components/Layout'
Documentation Craco
Thank you. :)
// Absolute path: paths which are relative to a specific path
import Input from 'components' // src/components
import UsersUtils from 'page/users/utils' // src/page/users/utils
// Alias path: other naming to specific path
import Input from '#components' // src/components
import UsersUtils from '#userUtils' // src/page/users/utils
In order for webpack's aliases to work, you need to configure the default webpack.config.js of create-react-app.
The official way is to use the eject script.
But the recommended way is to use a library without ejecting (find the most modern library for that).
VSCode IntelliSense
In addition, you should add jsconfig.json file for path IntelliSense in VSCode (or tsconfig.json), see followup question.
Now such code with IntelliSense will work:
// NOTE THAT THOSE ARE ALIASES, NOT ABSOLUTE PATHS
// AutoComplete and redirection works
import {ColorBox} from '#atoms';
import {RECOIL_STATE} from '#state';
If you want to use:
// this:
import MyUtilFn from 'utils/MyUtilFn';
// Instead of this:
import MyUtilFn from '../../../../utils/MyUtilFn';
use the node module plugin for resolving the urls https://www.npmjs.com/package/babel-plugin-module-resolver. By installing it and adding it to your webpack/babel.rc file.
Step 1
yarn add --dev babel-plugin-module-resolver
add this plugin
Step 2
in babel.config.js file
ALIAS NAME ALIAS PATH
#navigation ./src/navigation
#components ./src/components
#assets ./assets
[
"module-resolver",
{
root: ["./src"],
alias: {
"^~(.+)": "./src/\\1",
},
extensions: [
".ios.js",
".android.js",
".js",
".jsx",
".json",
".tsx",
".ts",
".native.js",
],
},
];
Step 3
import example
import SomeComponent from '#components/SomeComponent.js';
Step 4
restart server
yarn start
Reference link: How to use import aliases with React native and VSCode

Typescript can't find modules which are imported with webpack alias

I am currently setting up my project to be a bit cleaner, especially in the frontend part with references.
In hindsight I noticed that I was very generous with the folder structure for my frontend files and ended up with lots of layers. That's why I decided to look into what webpack can do for this case, and found out about the alias functionality.
This is how I set it up:
resolve: {
alias: {
components: path.resolve(__dirname, "Scripts/Views/Components"),
data: path.resolve(__dirname, "Scripts/Data"),
definitions: path.resolve(__dirname, "Scripts/Definitions"),
helper: path.resolve(__dirname, "Scripts/Helper"),
scripts: path.resolve(__dirname, "Scripts"),
views: path.resolve(__dirname, "Scripts/Views"),
},
extensions: [".tsx", ".ts", ".js", ".jsx"],
modules: ["node_modules"]
}
As you can see, I created alias' for various folders here.
This is my folder structure:
Now, let's hop into e.g. the LoginDialog.tsx. Here I am trying to import like this:
import { IErrorAttachedProperty } from "definitions/formHelper";
However, all I end up with here is an error that no module could be found this way.
What am I doing wrong here?
If it is of any significance - The webpack.config.js resides in the same directory as the Scripts folder.
you have to config tsconfig.json for typescript
"baseUrl": "./",
"paths": {
"components/*": [
"./src(or any other path)/Scripts/Views/Components"
]
},
here is nice example ts alias
Ok, so to avoid confusion for others I'm posting my solution/findings:
Yes, you can just use tsconfig.json without needing resolve/alias in Webpack. You should just do it once with Typescript setup.
EDIT: Nope, turns out you do need resolve/alias section in webpack.config.js. Typescript will be happy without it, but then you will get Webpack errors when it builds. Do both to make it work.
TIP: Make sure the paths you provide in the paths section of tsconfig.json are relative to the baseUrl entry point. Don't make them relative to the tsconfig.json file, baseUrl is like the project root for the non-relative module imports defined with paths.
From Typescript docs, absolute modules names (import * from package-a) are relative to baseUrl ~ https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url
All module imports with non-relative names are assumed to be relative to the baseUrl.
Relative modules (import * from ./packages) are just from current file as stated:
Note that relative module imports are not impacted by setting the baseUrl, as they are always resolved relative to their importing files.
So if you have:
./packages
./package-a
./package-b
./index.ts
./tsconfig.json
Your tsconfig.json would look like:
{
"compilerOptions": {
"baseUrl": "./packages",
"paths": {
"package-a/*": [ "./package-a/*" ],
},
},
"include": [
"./packages/**/*"
]
}
Then your webpack.config.json would look like:
{
resolve: {
alias: {
'package-a': path.resolve(__dirname, 'packages/package-a/'),
}
},
}
Then you can import from index.ts like this:
import { pkgAThing } from 'package-a';
// or
import { otherPkgAThing } from 'package-a/dir/dir`;
Which is alternative to relative style:
import { pkgAThing } from './packages/package-a`;

React import root path helper

In react because I have to import varies helper or component I have this problem
import approxPerDay from '../../../utils/approxPerDay.js'
import otherstuff from '../components/otherstuff'
and in another file it might be import approxPerDay from '../utils/approxPerDay.js'
It's really hard and time consuming to find is the relative path is. Is there any npm or helper can solve this issue?
I was experiencing a similar problem. I finally resolved it by following this article: https://medium.com/#ktruong008/absolute-imports-with-create-react-app-4338fbca7e3d
Create a .env file in the root of the react app
Add a line NODE_PATH = src/
That worked for me.
It depends on your module bundler. For Webpack 2 you can do something like this:
module.exports = {
...
resolve: {
modules: [
'node_modules',
path.resolve(__dirname + '/src')
],
alias: {
src: path.resolve(__dirname + '/src')
}
},
...
}
the same for Webpack 1:
module.exports = {
...
resolve: {
root: [
path.resolve(__dirname + '/src')
],
alias: {
src: path.resolve(__dirname + '/src')
}
},
...
}
Than you will be able to use src as a native path like this:
import approxPerDay from 'src/utils/approxPerDay.js'
import otherstuff from '../components/otherstuff'
The thing you are asking is called "absolute import".
"create react app" already provides a standard solution and recommends creating a jsconfig.json file in your root directory of react project.
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
Later you can import components as such:
import Button from 'components/Button';
Go to this link of official docs related to importing component and there u will find absolute import section:
https://create-react-app.dev/docs/importing-a-component/
And Yes don't forget to restart your react server after doing the changes : )
If you need to specify the .env file and relative path, the IDE needs to know about it.
For this, the following lines worked for on my IDE.
File
jsconfig.json
{
"compilerOptions": {
"baseUrl": "src"
},
"include": [
"src"
]
}

Categories

Resources