Absolute paths with parcel and react - reactjs

I have a react app that uses parcel instead of webpack and I wanted to add absolute paths into the project so I followed this guide and it works perfectly (you can ctr click on the path and it finds it( BUT parcel is not happy with this because it cant resolve the path of the file if you say
/components/thisComponent/thisComponent.jsx
it says this instead
#parcel/resolver-default: Cannot load file '../../../thisComponent/thisComponent' in './src/thisComponent/thisComponent'.
💡 Did you mean '../../thisComponent/thisComponent'?
💡 Did you mean '../../../.thisComponents/thisComponents'?
is I tried using the ~ instead but that doesnt work as well. How can I use absolute paths with parcel ?

This has worked for me:
import {Button} from '../../../../../shared';
// changed to:
import {Button} from '~src/shared';
jsconfig.json:
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}

Related

How to import absolute paths in a #nrwl/nx monorepo?

I'm working on a #nrwl/nx monorepo. I want to import the folders inside the project src by the absolute paths. I tried specifying the baseUrl but didn't work. The only solution worked is, adding the path to the monorepo root tsConfig.json file as follows.
"paths": {
"*": ["apps/my-app/src/*"]
}
But, the problem is, if I have another project, I will have to add that project as well to this path. I tried something as follows.
"paths": {
"*": ["apps/*/src/*"]
}
But, this doesn't work anymore. It doesn't match the project folder name.
How can I solve this? Or, is there any better way to import by absolute paths?
I'm facing the same problem, due to organizing common DTOs and Event.ts files in the nx monorepo. I found useful to update the tsconfig.base.json with a simpler path shortcut, that allow cross app imports and at the same time mantains the options of setting an absolute path in the single apps tsconfig.json file.
Here's my base.json:
"baseUrl": ".",
"paths": {
"libs": [
"libs/"
],
"app1: [
"apps/app1/"
],
"app2": [
"apps/app2/"
],
}
Now I have a sort of absolute imports that point to app names as base:
import {CreateUserEvent} from 'libs/events/create-user.event';
This is a random file in the app1/src/app/ folder that import a file in libs folder
Folder structure is:
root ('.')
|__ app1/src/app/file_with_import.ts
|__ ...
|__ ...
|__ libs/events/create_user.event.ts
Hope it helps

Typescript library import with sub paths

I have a Typescript library that is being consumed from a React app. I wanted to import the TS library contents with sub-paths like
import {base} from "my-lib"
import {foo} from "my-lib/path1"
import {bar} from "my-lib/path2"
I came across the Github issue which states that this is not yet supported (exports in package.json) by Typescript. I'm using Typescript 4.3.
There is a workaround posted in the same thread - Github repo typescript-subpath-exports-workaround. It uses exports and typeVersions
{
"main": "dist/index.js",
"types": "dist-types/index.d.ts",
"exports": {
".": "./dist/index.js",
"./exported": "./dist/exported.js"
},
"typesVersions": {
"*": {
"exported": ["dist-types/exported"]
}
}
}
I created a new react app (via npx create-react-app command) and tried importing hello from typescript-subpath-exports-workaround and it worked fine. But couldn't import `typescript-subpath-exports-workaround/exported
import {hello} from "typescript-subpath-exports-workaround" //works fine
import {foo} from "typescript-subpath-exports-workaround/exported" //gives "Module not found" error
Full error is below:
./src/App.js
Module not found: Can't resolve 'typescript-subpath-exports-workaround/exported' in '/Users/...../my-react-app/src'
Codesandbox code - https://codesandbox.io/s/create-react-app-forked-5yxd8
UPDATE: The sub-path used in import and the folder structure are different. In the above example, there won't be a folder named path1 or path2.
Look at the Next.JS React Framework. You can see that they use exactly the same approach as you have described. You can create a simple typescript application with their CLI tool like this:
npx create-next-app#latest --typescript
Then pay attention on imports used for instance in ./pages/index.tsx.
Then if you'll look into the ./node_modules/next/package.json you will see that they expose built files in two ways: actual code and type defs are inside ./node_modules/next/dist/* and their re-exports are right in ./node_modules/next/*.
At least this is a real-life example and a good place to start your experiments. It doesn't mean you have to learn the whole their codebase. You just need to mimic the essencial parts of their package.json file (https://github.com/vercel/next.js/blob/canary/packages/next/package.json), specifically main, types and files in your Typescript library.
Update
Just look where absent imports could be imported from:
As you might understand, those are the places, where corresponding *.d.ts files are placed. So you just need to create reexport files in the root folder of you library and mention them in 'files' property of your lib's package.json.
The exactly similar picture I have for my own library.
I think there is no other way to impement imports of your lib the way you want, except of having either reexports or original type definitions right in the lib's root folder
This block in my package.json worked for me:
{
// ...
"files": [
"/dist"
],
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./types": "./dist/types/index.js",
"./generate": "./dist/generate/index.js"
},
"typesVersions": {
"*": {
"types": [
"./dist/types/index.d.ts"
],
"generate": [
"./dist/generate/index.d.ts"
]
}
}
}
My tsconfig.json looks like this:
{
"extends": "#tsconfig/node14/tsconfig.json",
"include": ["src/**/*"],
"compilerOptions": {
"lib": ["es2020", "dom"],
"declaration": true,
"outDir": "dist",
"module": "ESNext"
}
}
And this is my file structure:
package.json
tsconfig.json
dist/ // and all its subfolders
src/
generate/
index.ts
types/
index.ts
index.ts
Separately, I'm using TypeScript 4.7.4. Supposedly the exports field is supported with this version, but it didn't work for me. But this (maybe overly complex) workaround worked for me.
As answered in How to create a local module in TypeScript:
Using module-alias package might solve your problem.
Add this configuration below into package.json:
"_moduleAliases": { "my-module":
"<your_build_folder>/modules/my-module" },
And this code on first line
of your main file (server.ts/index.ts)
import 'module-alias/register';

Creating custom absolute paths with create-react-app

I've created a React project with typescript using create-react-app version 3.4.1.
I'm trying to avoid the use of relative paths in my project. Here's a part of my project tree:
/
|_ public
|_ tests
|_ src
|____ Scenarios
|____ Components
|____c
What I basically want is to be able to to do something like import '#components/c'. I've tried to add this part to my tsconfig.json file:
{
"compilerOptions": {
...
"baseUrl": ".",
"paths": {
"*": ["src/*"],
"tests": ["tests/*"],
"public": ["public/*"],
"#components/*": ["src/Components/*"],
"#Scenarios/*": ["src/Scenarios/*"],
},
...
}
}
But every time I'm starting my app using yarn start my tsconfig deletes this part of my code (eveything but my "baseUrl" part). As far as I know since version 3 of react-create-app, solved this problem partially with enabling baseUrl property to affect the imports' root dir. But I couldn't find anywhere a working solution to set absolute paths from tsconfig path directory. The partial solution doesn't work for me as I'm probably going to import stuff from public directory.
I did try this solution from last year but it wouldn't work for me. Did anyone manage to get this or any other solution working?
Ideally the solution will enable me to still use create-react-app and not to use other packages but of course any solution would work.
you can do it with your solution by add tsconfig.extends.json and use craco or any library to custom webpack. This is my craco.config.js:
const path = require('path')
module.exports = {
webpack: {
alias: {
src: path.resolve(__dirname, './src/')
}
}
}

ESLint: 'cy' is not defined (Cypress)

I've just started using Cypress with my React Typescript project. I've gotten some simple tests to run:
describe('settings page', () => {
beforeEach(() => {
cy.visit('http://localhost:3000')
});
it('starts in a waiting state, with no settings.', () => {
cy.contains('Waiting for settings...')
});
it('shows settings once settings are received', () => {
const state = cy.window().its('store').invoke('getState')
console.log(state) // different question: how do I get this to be the state and not a $Chainer?
});
});
It runs in Cypress just fine. But I get Typescript errors in Webstorm, saying that cy is not defined (a TS and ESlint error) and an error on describe saying all files must be modules when the --isolatedModules flag is provided.
I can make it a JS file instead of a TS file, then I still get cy is not defined.
I've tried import cy from 'cypress' but then I get ParseError: 'import' and 'export' may appear only with 'sourceType: module' which is a whole other can of worms (I'm taking baby steps in writing my tests and haven't had to import anything yet...)
/// <reference types="cypress" /> does not work.
Update (sort of)
I've followed instructions here and have made a little progress. To my already very full React webpack.config.dev.js I added the recommended code:
{ // TODO inserted for cypress https://stackoverflow.com/a/56693706/6826164
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
to the end of the list of rules (just before the file loader).
When I do this as well as setting up the plugins/index file as indicated in the article, the cypress "home screen" runs but when I click to open my tests, it takes very many seconds and then shows lots of errors, starting with
integration\settings.spec.ts
This occurred while Cypress was compiling and bundling your test code. This is usually caused by:
A missing file or dependency
A syntax error in the file or one of its dependencies
Fix the error in your code and re-run your tests.
./cypress/integration/settings.spec.ts
Module build failed (from ./node_modules/ts-loader/index.js):
Error: TypeScript emitted no output for C:\Users\...\...\front_end\cypress\integration\settings.spec.ts.
# multi ./cypress/integration/settings.spec.ts main[0]
Followed by, actually, a lot of Typescript output such as this:
C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx
[tsl] ERROR in C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx(37,41)
TS2339: Property 'toBeTruthy' does not exist on type 'Assertion'.
C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx
[tsl] ERROR in C:\Users\jtuzman\dev\...\...\src\__tests__\Errors.test.tsx(41,45)
TS2339: Property 'toBeDefined' does not exist on type 'Assertion'.
Notice that these are now errors for code outside the test files (although perhaps that makes sense). Many of them are for files in which I'm using Jest rather than Cypress, and many errors, as you can see, seem to be related to it inferring an Assertion type on expect that is not Jest, such that it thinks the toEqual matcher is wrong.
All the while, in Webstorm ESLint is still complaining about all my cy and TypeScript is underlining all those Jest assertions mentioned in the output.
This is all with a ts test file. If I rename the file to js, it says the file has no tests.
Any help? I love Cypress but I'm having a hell of a time getting it to work fully!
I got that error after upgrading to cypress version 4+. I installed the eslint-plugin-cypress
https://github.com/cypress-io/eslint-plugin-cypress
and activated it in the extends configuration either in package.json or in separate config file:
"eslintConfig": {
"extends": [
"plugin:cypress/recommended"
]
},
Add .eslintrc.json to cypress directory
In .eslintrc.json
{
"extends": [
"plugin:cypress/recommended"
]
}
I do not install eslint-plugin-cypress, and it fix the problem
Specify cy in eslintrc globals
Answered here
cy is a global variable. Much like location. So really it is window.cy. You can add it to the globals in Eslint. Don't import cy from cypress.
{
"globals": {
"cy": true
}
}
Added that to my .eslintrc and fixed the issue
The Cypress ESLint plugin will get rid of these warnings:
yarn add -D eslint-plugin-cypress (https://github.com/cypress-io/eslint-plugin-cypress)
add .eslintrc to the root of your project with the following:
{
"plugins": ["cypress"],
"extends": ["plugin:cypress/recommended"],
"rules": {
"jest/expect-expect": "off"
}
}
Try.. import cy from "cypress" this solved the problem for me.
at the top of your file put
/// <reference types="cypress" />
or download the official types
source: official cypress intellisense docs
I struggled a lot then this helped...
by adding same line in two files, eslintrc.json and eslintrc.js
(if u have other dependencies in extends, append them as well after it)
extends: ['plugin:cypress/recommended'],
Just add these lines to your tsconfig.json file for e2e tests:
"compilerOptions": {
"types": ["cypress"]
}
This adds support for cypress types.
/* global cy */
import above in your test file
example:
suppose you have login test ("cypress test file ex: cypress/integration/login.js")
I replaced the old style of type referencing,
/// <reference types="cypress" />
with this silly import
import type {} from 'cypress';
And the IDE now both recognizes Cypress's globals while also avoiding the "isolatedModules" issue it has with tsconfig.json
Seems I found a remedy that works (at least) for me. Adding this import to the top of the test:
import _Cypress from "cypress";
relaxes and comforts the ESLint plugin. Actually any name for the import can be used instead of "_Cypress": any that conforms your sense of beauty, does not conflict with anything and starts with underscore (to not provoke ESLint again). Of course, it looks like a kind of voodoo. I don't know why it works and probably there are better ways to present ESLint Cypress's globals, but I don't know them.
add this to jest.config.js
testPathIgnorePatterns: [
'/cypress',
],
Wrap your config object with defineConfig in the cypress.confi.ts file
like so
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
return config;
},
},
component: {
devServer: {
framework: "create-react-app",
bundler: "webpack",
},
},
});
For me adding .eslintignore in root directory and placing *.cy.js for all my test files was only workaround.
It seems that for the rest of us the working solution really is installing eslint-plugin-cypress and adding:
"eslintConfig": {
"extends": [
"plugin:cypress/recommended"
]
},
but idt didn't helped in my case because this plugin is no longer supported (almost for a year now) so it ended with critical error when combined with cypress-axe.

ReactJS - Module not found when specifying "paths" in jsconfig.json

Consider the following settings in jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#components/*": ["src/components/*"],
"#constants/*": ["src/constants/*"]
}
}
}
When I attempt to import app-constants.js file in my components through:
import AppConstants from "#constants/app-constants";
I seem to get the following error:
Module not found: Can't resolve '#constants/app-constants'
My app-constants.js file is located directly in the src/constants folder:
Any idea why this is happening?
EDIT
I Tried using this:
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
And works when calling directly onto the folders like constants/app-constants.js
But doesn't when I try the first method.
It would be great if someone is able to enlighten me of my mistakes.
Your code looks good and you can verify it by intellisense e.g:
import AppConstants from "#constants/";
it will show app-constants in intellisense.
Now the problem is that react is not supporting aliases yet, but will support very soon.
I don't know if we will add support for aliases anytime soon. I
personally don't have time to work on it right now. I think the
current options with setting the baseUrl to . or src is sufficient for
tackling the struggles with relative imports. Beyond that it's just
personal preference like using # instead of src as prefix.
https://github.com/facebook/create-react-app/issues/7795

Resources