React Monorepo yarn workspaces + typescript + absolute imports - reactjs

I'm having issues setting up an React project with yarn workspaces and typescript.
My folder structure is:
-root
-package.json
-workspaces
-web
-common
and my package.json file is:
{
"name": "my-project-name",
"private": true,
"workspaces": [
"workspaces/web",
"workspaces/common"
],
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
]
}
My issue is: when I import files on web from the common project, it works fine if it's a .js file, but fails with TypeError: Object(...) is not a function when using .ts or .tsx files.
Any ideas on what I might be missing?

I recommend adopting the following file hierarchy:
- root
- package.json
- tsconfig.json
- packages
- common
- package.json
- tsconfig.json
- services
- web
- package.json
- tsconfig.json
Everything in the packages folder can be imported. Services are "leaf" projects that you don't want to import in other projects.
With that as a base, your root package.json should be setup like that:
{
"name": "my-project-name",
"private": true,
"workspaces": [
"packages": [
"packages/*",
"services/**/*"
],
],
}
Then, you also need to tell typescript how to resolve the imports.
In the root tsconfig.json, set the following:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#myproject/*": ["packages/*/src"]
},
}
Make sure that every tsconfig extends this base with "extends": "../../tsconfig.json"
Inside web/package.json or any package that needs to import common, define common as a dependency:
{
[...]
"dependencies": {
"#myproject/common": "*",
}
}
Now if your common package.json has a name set to `"#myproject/common", you can import your code inside web with :
import { myUtilFunction } from "#myproject/common";
I would advise you to also use learn with a setup like this.
You will also need to modify a bit your build pipeline, since you're importing files inside /web that are outside the /web folder. For a more complete example, you can check out this repo: https://github.com/NiGhTTraX/ts-monorepo

Related

How to resolve "Cannot use import statement outside a module" in jest

I have a React application (not using Create React App) built using TypeScript, Jest, Webpack, and Babel. When trying to run yarn jest, I get the following error:
I have tried removing all packages and re-adding them. It does not resolve this. I have looked at similar questions and documentation and I am still misunderstanding something. I went so far as to follow another guide for setting up this environment from scratch and still received this issue with my code.
Dependencies include...
"dependencies": {
"#babel/plugin-transform-runtime": "^7.6.2",
"#babel/polyfill": "^7.6.0",
"babel-jest": "^24.9.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-test-renderer": "^16.11.0",
"source-map-loader": "^0.2.4"
},
"devDependencies": {
"#babel/core": "^7.6.0",
"#babel/preset-env": "^7.6.0",
"#babel/preset-react": "^7.0.0",
"#types/enzyme": "^3.9.2",
"#types/enzyme-adapter-react-16": "^1.0.5",
"#types/jest": "^24.0.13",
The component's import lines...
import * as React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import HomePage from "./components/pages";
import {
Footer,
Header,
Navigation,
} from "./components/shared";
The test file....
import * as React from "react";
import * as renderer from "react-test-renderer";
import App from "../App";
it("Renders the Footer correctly", () => {
const tree = renderer
.create(<App />)
.toJSON();
expect(tree).toMatchSnapshot();
});
I expected to be able to use named imports in my components without my tests blowing up. It appears to fix the issue if I only use default imports through my solution, but I would prefer to not go that route.
Also using Babel, Typescript and Jest. Had the same failure, driving me crazy for hours.
Ended up creating a new babel.config.js file specifically for the tests. Had a large .babelrc that wasn't getting picked up by jest no matter what i did to it. Main app still uses the .babelrc as this overrides babel.config.js files.
Install jest, ts-jest and babel-jest:
npm i jest ts-jest babel-jest
babel.config.js (only used by jest)
module.exports = {presets: ['#babel/preset-env']}
jest.config.js
module.exports = {
preset: 'ts-jest',
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
"^.+\\.(js|jsx)$": "babel-jest",
}
};
package.json
"scripts": {
"test": "jest"
Use Babel to transpile those JS Modules and you'll be able to write your tests with es6.
Install Babel/preset-env
npm i -D #babel/preset-env
Create a babel configuration file with the preset
//babel.config.js
module.exports = {presets: ['#babel/preset-env']}
I solved this by migrating the .babelrc file to babel.config.js! Shocker.
For future references,
I solved the problem by using below jest config, after reading Logan Shoemaker's answer.
module.exports = {
verbose: true,
setupFilesAfterEnv: ["<rootDir>src/setupTests.ts"],
moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
moduleDirectories: ["node_modules", "src"],
moduleNameMapper: {
"\\.(css|less|scss)$": "identity-obj-proxy"
},
transform: {
'^.+\\.(ts|tsx)?$': 'ts-jest',
"^.+\\.(js|jsx)$": "babel-jest",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/file.js",
}
};
try this thing if you are using babel 6
Adding #babel/plugin-transform-modules-commonjs in the plugin section of babel.config.js
or
For my case import issue was due to the react file drop by adding that to transformIgnorePatterns
"transformIgnorePatterns": ["/node_modules/(?!react-file-drop)"]
I fixed it by simply appending the pattern after the run statement in package.json runner
{
"scripts": {
...
"test": "react-scripts test --transformIgnorePatterns 'node_modules/(?!my-library-dir)/'"
...
Then, just run npm test
Solution: my named imports were coming from index.js files and I believe ts-jest needed them as index.ts files (I'm using Typescript). If anyone else runs into this error, couldn't hurt to check if you derped your file extensions.
I wasted a lot of time on this, unfortunately, but I learned a lot about webpack configurations and Babel.
Add your test script in package.json with Node experimental feature: --experimental-vm-modules
In this way you won't require babel or other dependencies.
Examples:
"test": "NODE_OPTIONS='--experimental-vm-modules --experimental-specifier-resolution=node' jest"
If you get this error: zsh: command not found: jest, try with node passing jest.js like this:
"test": "NODE_OPTIONS='--experimental-vm-modules --experimental-specifier-resolution=node --trace-warnings' node node_modules/jest/bin/jest.js --detectOpenHandles"
I'm surprised that none of the answers does not give an elegant solution:
jest.config.js
module.exports = {
...,
globals: {
"ts-jest": {
isolatedModules: true,
},
},
};
This compiles each file separately therefore avoiding the no exports issue.
Create .babelrc on the main directory and add this code and install these packages
#babel/core, #babel/preset-env and #babel/preset-react
{
"presets": [
[
"#babel/preset-env",
{
"modules": "commonjs"
}
],
"#babel/preset-react"
]
}
Matching file extensions:
I importing a file named Todo.jsx in the root as ./src/Todo/. Whenever I changed it to Todo.js the problem went away.
Disclaimer: I'm not sure what the requirement is for having your file extension as jsx vs js for your components. It did not effect me at all, but I could imagine it could mess with intellisense or snippets.
For me renaming file to babel.config.js worked.
Here is my config file an NX project using next with Typescript along with Twin-macro
// .babelrc.js >> babel.config.js
module.exports = {
presets: [
[
"#nrwl/react/babel",
{
"runtime": "automatic",
"targets": {
"browsers": [">0.25%", "not dead"]
},
"preset-react": {
runtime: "automatic",
importSource: "#emotion/react",
},
}
],
'#babel/preset-env',
'#emotion/babel-preset-css-prop',
'#babel/preset-typescript'
],
plugins: ['#emotion', 'macros', '#babel/plugin-transform-runtime', 'react-docgen'],
}
Also, please note even updating package.json works,
https://kulshekhar.github.io/ts-jest/docs/getting-started/presets/#basic-usage
// package.json
"jest": {
// Replace `ts-jest` with the preset you want to use
// from the above list
"preset": "ts-jest"
}
I encountered the same problem with Typescript, Jest, and VueJS/VueCli 3. The normal build has no problem. only happens for Jest. I struggled for hours by searching. But no answer actually works. In my case, I have a dependency on my own typescript package which I specific "target": "es6" in the tsconfig.json. That's the root cause. So the solution is simply to change the dependent's (Not the same project) back to es5 tsconfig.json:
{
"compilerOptions": {
"target": "es5",
...
},
...
}
Personnaly I followed #ajwl setup but discovered that jsdom-worker inside setupFiles: section of jest.config.js was triggering that same error. Once removed, my tests were passing.
P.S. my babel.config.js is a bit different, since I have a Vuejs (v2) SPA (bundled with Vitejs):
module.exports = {
plugins: ['#babel/plugin-transform-modules-commonjs'],
presets: [['#babel/preset-env', { targets: { node: 'current' } }]]
}
The problem is likely that jest doesn't support esmodules natively. Which can cause problems if youre typescript target is es6 or greater.
If you are testing the built typescript output, you could simply add a module=commonjs flag while transpiling. That way, your code can run with es6 or greater and still work with Jest.
"scripts": {
"test": tsc --module commonjs && jest {your-output-folder}/
}
What's great about this is that I didn't have to add any additional babel dependencies or special jest runners :)
I solved it by changing my tsconfig.json to a compatible native output
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
It is not ideal in every scenario but you might be okay with this.
All I had to do, was simply updating the package #babel/preset-env in the dev dependencies to the latest version
// package.json
"#babel/preset-env": "^7.18.6"
None of the answers helped me, what did help me was making sure my NODE_ENV was set to test, since babel config is per NODE_ENV using the wrong NODE_ENV by accident that is not configured in babel config will mean you wont be using babel and the typescript files will not be transformed.
It took me couple of hours to figure this one out so i hope it will save someone else the time it took me.
Don't know why and how but how I solved the problem was really interesting.
Just add __mocks__ folder in your src folder and create an empty file inside __mocks__ named axios.js
I discovered that this error might be triggered when you try to load a dependency that is made for the browser and, thus, cannot work with jest (node).
I had a lot of trouble solving this issue for #zip.js/zip.js lib. But I could do it like that:
Here is my jest.config.js. Adapt it to your need. The trick here is the moduleNameMapper that will make all imports to zip.js point to the file __mocks__/#zip.js/zip.js I created in my root folder.
export default {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
'#zip.js/zip.js': '<rootDir>/__mocks__/#zip.js/zip.js',
},
}
And here is what I have in <rootDir>/__mocks__/#zip.js/zip.js file:
module.exports = {}
Too late for this answer :)
After trying all the possible solutions, this worked for me:
The solution, that works for me:
create a file named jest/mocks/#react-native-firebase/crashlytics.js
export default () => ({ log: jest.fn(), recordError: jest.fn(), });
create a file named jest/jestSetupFile.js
import mockFirebaseCrashlytics from './mocks/#react-native-firebase/crashlytics';
jest.mock('#react-native-firebase/crashlytics', () => mockFirebaseCrashlytics);
in package.json add
"jest": { "setupFiles": ["./jest/jestSetupFile.js"] },
I needed to do a couple things to get this to work for me
Rename my .babelrc to babel.config.js and make a little change:
// .babelrc
{
"presets": [
[
"#babel/preset-env",
{
"corejs": "3.26",
"useBuiltIns": "usage"
}
],
"#babel/preset-react"
],
...
}
// babel.config.js - This still works fine with webpack
module.exports = {
"presets": [
[
"#babel/preset-env",
{
"corejs": "3.26",
"useBuiltIns": "usage"
}
],
"#babel/preset-react"
],
...
}
Add the following to my jest config file:
{
...
"transformIgnorePatterns": [
"node_modules/(?!(react-leaflet-custom-control)/)"
],
...
}
Where react-leaflet-custom-control was the package causing issues for me.
If you're using TypeScript, and you have a tsconfig.json file, try removing "module": "esnext" if you're using it
Running npm ci fixed this problem for me.

Add absolute paths to app created by "Create React App"

I have created an app by Create React App and to be more specific I'm also using typescript.
I can't figerout how to set absolute paths to access to my components, pages, etc..
In a different scenario I would update my tscongig with something like:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#components/*": ["src/components/*"]
}
}
}
but I have no idea how to implement this as I'm using react-scripts
any idea?
Create a tsconfig.json file and add the code below.
{
"compilerOptions": {
"baseUrl": "src"
},
"include": [
"src"
]
}
Then you can import your components as
import Header from 'components/Header';
You should be able to use the same approach if create a jsconfig.json file in your solution, which supports the same baseUrl and rootPath properties as tsconfig.
Alternative is adding an .env file in your solution with the following line:
NODE_PATH=src/
Also, apart from the env file add this to your jsconfig.json
{
"rootDir": "src",
"compilerOptions": {
"baseUrl": "src",
"paths": {
"*": ["*"]
}
}
}
This should resolve both the compiler being able to find your absolute imports, and linter handling them properly.
See Building Your App / Importing a Component / Absolute Imports in the Create React App docs.
You can configure your application to support importing modules using absolute paths. This can be done by configuring a jsconfig.json or tsconfig.json file in the root of your project. If you're using TypeScript in your project, you will already have a tsconfig.json file.
Below is an example jsconfig.json file for a JavaScript project. You can create the file if it doesn't already exist:
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
If you're using TypeScript, you can configure the baseUrl setting inside the compilerOptions of your project's tsconfig.json file.
Now that you've configured your project to support absolute imports, if you want to import a module located at src/components/Button.js, you can import the module like so:
import Button from 'components/Button';

Upgrading to an Angular/AngularJS hybrid application: getting typescript errors / AngularJS import errors

We are in the process of upgrading an AngularJS application to Angular with the incremental approach: we would like to be able to create new components in Angular and upgrade existing AngularJS components one by one, all this still with a functional application during the process.
We use the official documentation as well as several articles about hybrid Angular/AngularJS applications on real world applications.
Here are our attempts and the errors we get.
Context
AngularJS 1.7.3
Angular 6.1.7
Typescript 2.7.2
angular-cli
First steps
upgrade to AngularJS 1.7
remove Grunt and use angular-cli
use ngUpgrade (app.module.ts and app.module.ajs.ts)
Moving to Typscript: dealing with errors
That's the official process: rename .js files to .ts.
We then moved from Node require() to TypeScript module loading (var ... = require --> import ... = require)
Ideally, we should correct all the typing errors due to using the TypeScript compiler.
But the TypeScript doc states that's it's possible to do an incremental migration: being tolerant to TypeScript errors at the beginning in order to compile the js code without modifications (and stricter later on after fixing the code).
To achieve this, we used the awesome-typescript-loader instead of tsc to get theses options: transpileOnly, errorsAsWarnings (this requires the use of angular-builders/custom-webpack).
The options allow to pass the compilation, but it appears that the compilation is done twice: first without errors (warnings or not), but second with errors... so the build fails. How can we run only the first compilation?
Alternative attempt: keeping .js files, errors in importing and bootstrapping
We tried also an unofficial and unusual way to migrate the js code incrementally, that is keeping the original .js files alongside new .ts files.
We got some errors at compilation or application loading, related to importing AngularJS and to module management. Indeed the TypsScript module documentation states that:
Some libraries are designed to be used in many module loaders, or with no module loading (global variables). These are known as UMD modules. These libraries can be accessed through either an import or a global variable. ... can be used as a global variable, but only inside of a script. (A script is a file with no imports or exports.)
What we noticed:
in .js files: access to the AngularJS global angular (if we remove require("angular")) - script mode
in .ts files: we can't use import from angular, otherwise we get the error angular.module is undefined - module mode
With this in mind, we made the application compile and load in the browser without errors, but at the end:
this.upgrade.bootstrap(document.body, [App])
generates an error on AngularJS bootstrapping:
Angular 1.x not loaded !
How to fix this? It may be because we didn't import AngularJS in the TypeScript module way to avoid the previous error?
The official documentation mentions angular.IAngularStatic (still get an error)?
We can try also setAngularJSGlobal() ? Used when AngularJS is loaded lazily, and not available on window
By the way what is the difference between using [App] or ["App"] when calling bootstrap()?
... Since we are new to this upgrade process, we may be doing completely wrong things. Thank you for sharing your experience!
Configuration files
angular.json
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "acd-banner-multicanal",
"projects": {
"acd-banner-multicanal": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "target",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "./tsconfig.json",
"assets": [
"src/i18n",
"src/conf/conf.txt",
"src/conf/conf_DEFAULT.txt",
"src/systemjs.config.js",
{ "glob": "font-banner*", "input": "./node_modules/elq-font-icon/build/", "output": "/assets/fonts" },
"src/assets/images",
{ "glob": "system.js*", "input": "./node_modules/systemjs/dist/", "output": "/assets" },
"src/assets/images",
{ "glob": "**/*", "input": "./node_modules/tinymce/plugins", "output": "/assets/tinymce/plugins" },
{ "glob": "**/*", "input": "./node_modules/tinymce/skins", "output": "/assets/tinymce/skins" }
],
"styles": [
"src/assets/styles/style.less"
],
"scripts": [
"./node_modules/jquery/dist/jquery.js",
"./node_modules/jquery-ui-dist/jquery-ui.js"
]
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"aot": true,
"buildOptimizer": true
}
}
},
"test": {
"builder": "#angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "./karma.conf.js",
"scripts": [],
"styles": [
"src/assets/main.less"
],
"assets": [
"src/i18n",
"src/favicon.ico"
]
}
},
"lint": {
"builder": "#angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"acd-ihm-angular-e2e": {
"root": "e2e/",
"sourceRoot": "e2e",
"projectType": "application",
}
},
"defaultProject": "acd-banner-multicanal",
"schematics": {
"#schematics/angular:component": {
"styleext": "less",
"lintFix": true
}
}
}
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./target",
"sourceMap": true,
"experimentalDecorators": true,
"allowJs": true,
"baseUrl": "./",
"lib": [
"es2017",
"dom"
],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"paths": {
"angular": ["node_modules/angular/angular"]
}
},
"include": [
"src/**/*"
],
"exclude": [
"src/**/*.spec.ts"
]
}
As for the angular 1.x not loaded error;
Did you install angularJS in the new application?
$ npm install --save angular#1.7.3 \
#types/angular
In the angular.json file you need to include the script:
"scripts": [
"../node_modules/angular/angular.js",
//etc...
],
Here's an example of upgrading an application that seem similar to what you have.
Alternatively you can bring in angular into the import chain by importing it in main.ts;
import * as angular from 'angular';
This might be a better option since it makes angular cli / webpack aware of angularJS and may prevent errors such as "WARNING: Tried to Load Angular More Than Once" that may arise if some other component (such as the hybrid router imports angular).
I confirm that the answer works, we've been able to run our application in hybrid mode. In fact, in AngularJs, we used grunt and browserify, and we had packaged some libraries using the package.json browser field. To do the same, we had to declare the libraries to load in the browser in angular.js / build.options.scripts:
"scripts": [
"./node_modules/jquery/dist/jquery.js",
"./node_modules/jquery-ui-dist/jquery-ui.js",
"./node_modules/moment/moment.js",
"./node_modules/bootstrap/dist/js/bootstrap.js",
"./node_modules/eonasdan-bootstrap-datetimepicker/src/js/bootstrap- datetimepicker.js",
"./node_modules/bootstrap-tour/build/js/bootstrap-tour.js",
"./node_modules/angular/angular.js",
"./node_modules/ng-table/bundles/ng-table.js"`
]
Thanks a lot.
That may be useful to add in the Angular documentation? Indeed, the examples given in https://angular.io/guide/upgrade#bootstrapping-hybrid-applications are based on SystemJS, whereas we just use Webpack (already used by Angular).
Indeed, there is an issue about the angular doc, the migration doc is not yet updated for angular-cli (that's why it is about SystemJS).

How to avoid using relative path imports (/../../../redux/action/action1) in create-react-app

I've been using create-react-app package for creating a react website. I was using relative paths throughout my app for importing components, resources, redux etc. eg, import action from '../../../redux/action
I have tried using module-alis npm package but with no success. Is there any plugin that I can use to import based on the folder name or alias i.e. an absolute path?
Eg., import action from '#redux/action' or import action from '#resource/css/style.css'
Create a file called .env in the project root and write there:
NODE_PATH=src
Then restart the development server. You should be able to import anything inside src without relative paths.
Note I would not recommend calling your folder src/redux because now it is confusing whether redux import refers to your app or the library. Instead you can call your folder src/app and import things from app/....
We intentionally don't support custom syntax like #redux because it's not compatible with Node resolution algorithm.
The approach in the accepted answer has now been superseded. Create React App now has a different way to set absolute paths as documented here.
To summarise, you can configure your application to support importing modules using absolute paths by doing the following:
Create/Edit your jsconfig.json/tsconfig.json in the root of your project with the following:
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
Once you have done this you can then import by specifying subdirectories of "src" (in the following example, components is a subdirectory of src) e.g.
import Button from 'components/Button'
We can use webpack 2 resolve property in the webpack config.
Sample webpack config using resolve :
Here component and utils are independent folder containing React components.
resolve: {
modules: ['src/scripts', 'node_modules'],
extensions: ['.jsx', '.js'],
unsafeCache: true,
alias: {
components: path.resolve(__dirname, 'src', 'scripts', 'components'),
utils: path.resolve(__dirname, 'src', 'scripts', 'utils'),
}
}
After that we can import directly in files :
import UiUtils from 'utils/UiUtils';
import TabContent from 'components/TabContent';
Webpack 2 Resolve Reference
After you try Ben Smith's solution above if you find eslint complains about importing absolute path add the following line to your eslint config:
settings: {
'import/resolver': {
node: {
paths: ['src'],
},
},
},
replace 'src' with your folder if you use your own boilerplate with your folder's name.
Feb 2010
Wasted about an hour on this.
An example is below:
Goal: Import App.css in HomePage.js
myapp\src\App.css
myapp\src\pages\HomePage.js
File: jsconfig.json
{
"compilerOptions": {
"baseUrl": "src"
}
}
File: src\pages\HomePage.js
import "App.css";
The alias solution for craco or rewired create-react-app is react-app-alias for systems as: craco, react-app-rewired, customize-cra
According docs of mentioned systems replace react-scripts in package.json and configure next:
react-app-rewired
// config-overrides.js
const {aliasWebpack, aliasJest} = require('react-app-alias')
const options = {} // default is empty for most cases
module.exports = aliasWebpack(options)
module.exports.jest = aliasJest(options)
craco
// craco.config.js
const {CracoAliasPlugin} = require('react-app-alias')
module.exports = {
plugins: [
{
plugin: CracoAliasPlugin,
options: {}
}
]
}
all
Configure aliases in json like this:
// tsconfig.paths.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"example/*": ["example/src/*"],
"#library/*": ["library/src/*"]
}
}
}
And add this file in extends section of main typescript config file:
// tsconfig.json
{
"extends": "./tsconfig.paths.json",
// ...
}
I am using babel-plugin-module-resolver for my project to resolve that problem.
babel-plugin-module-resolver also is the same as module-alis. So I think you should just resolve using module-alis problem.
Because you didn't tell us why using module-alis was fail? So i cant show you how to fix it.
Dont give up your solution while you dont know the reason!
in package.json file,
eject this code in the scripts object like this..
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js --env=jsdom",
"eject": "NODE_PATH=src/ react-scripts eject"
},
this will enable the absolute path imports in your app
None of the answers worked for me. Some didn't work at all and others worked but the import was already inside src, for example:
import something from 'path/to/file'.
Whereas I wanted to be able to do:
import something from 'src/path/to/file'
Here is how I solved it:
tsconfig.json
{
"compilerOptions": {
// ...
"baseUrl": ".",
"rootDirs": [
"src"
]
},
"include": [
"src"
]
}

Import react components with absolute path

Here is my test file
// /imports/components/main.test.js
import React from 'react'
import { shallow, mount } from 'enzyme'
import Main from './main'
import TextInput from "/imports/ui/textInput"
...
and the main.js has
// /imports/components/main.js
import { action1 } from "/imports/actions/myAction"
but it throws an error when I run the test, saying
Cannot find module '/imports/actions/myAction' from 'main.js'
If I comment the import './main', same thing happen with importing TextInput. I have no issue with importing modules in node_modules.
How can I tell Jest or webpack to import the component using absolute path from project directory (i.e import Foo from /imports/...)?
Better way to solve relative path import issue, is by creating jsconfig.json file adjacent to package.json file.
{
"compilerOptions": {
"baseUrl": "src"
}
}
then import { action1 } from "actions/myAction"; will work
If you're using Create React App, you can set up the absolute imports path in a jsconfig.json (need to create in a fresh JavaScript template) or tsconfig.json (already created in the TypeScript template) at the root of your project to serve your usage.
Example:
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
Official docs: https://create-react-app.dev/docs/importing-a-component/#absolute-imports
Another solution is to create an .env file within the root directory of your project.
Within it you will add NODE_PATH=src/
Thats all
Save the file and restart your dev environment in terminal.
Afterwards, you will go through your project and update some import statements accordingly.
My file structure follows exactly the same pattern as yours. To teach Jest into using imports beginning with a /, I use babel-plugin-module-resolver and its handy root option. My .babelrc for Jest looks like this:
{
"presets": ["es2015", "meteor"],
"plugins": [
"transform-class-properties",
"transform-react-constant-elements",
"transform-react-inline-elements",
"transform-react-remove-prop-types",
["module-resolver", {
"root": ["../"],
"alias": {
"react-router-dom": "react-router-dom/umd/react-router-dom.min.js",
"redux": "redux/dist/redux.min.js",
"react-redux": "react-redux/dist/react-redux.min.js"
}
}]
]
}
As I'm using Meteor which customized its root imports, I hide my Jest usage and configuration into a .jest directory at the root of my repository allowing me to have a specific .babelrc without risking conflicts with Meteor's one.
With webpack(v4) and babel, you can provide absolute paths in your directory.
Follow these steps
In your .babelrc file, make this entry for plugins.Make sure you have babel-plugin-root-import in your package.json as well.
"plugins": [
[
"babel-plugin-root-import",
{
"paths": [
{
"rootPathPrefix": "~",
"rootPathSuffix": "./"
},
{
"rootPathPrefix": "#src",
"rootPathSuffix": "src"
},
{
"rootPathPrefix": "#any-other-folder",
"rootPathSuffix": "src/client/../any-other-folder"
}
]
}
]
]
Now if you run into eslint issue, you can add these lines in your eslintrc:
"settings": {
"import/resolver": {
"babel-plugin-root-import": [
{
"rootPathPrefix": "#src",
"rootPathSuffix": "src"
},
{
"rootPathPrefix": "#any-other-folder",
"rootPathSuffix": "src/client/../any-other-folder"
}
]
}
}
Now to make your editor recognize these paths, you can create this entry in jsconfig file.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["/*"],
"#src/*": ["src/*"],
"#any-other-folder/*": ["src/client/../any-other-folder/*"] ==> absolute path to any other folder
}
},
"exclude": ["node_modules"]
}
Hope these entries help.
I had jest configs in package.json file (under "jest" key). So I just have added there this row:
"modulePaths": ["<rootDir>/src/"]
And this works for me. I hope it can help somebody else.

Resources