In my React-Native application, import paths are like this.
import {
ScreenContainer,
SLButton,
SLTextInput,
} from '../../../../../components';
import { KeyBoardTypes } from '../../../../../enums';
import { SIGN_UP_FORM } from '../../../../constants/forms';
I have seen some applications, there the paths are more clear and elegant without '../../../'s. How can I achieve this in React-Native??
I saw in my solution that, in every folder there was a package.json file. I'm not sure if that is the proper way to do it.
You need to configure alias in webpack.config.js. You can find an example here and here
webpack.config.js:
alias: {
'#': path.join(__dirname, 'src')
}
your.js.file.js
import '#/utils/classComponentHooks';
if you don't use wepback for react-native (despite you can). You can also try .babelrc
[
'module-resolver',
{
root: ['./src'],
alias: {
'#': './src',
},
},
];
Starting around React Native version 0.55 (I'm not sure exactly when this was enabled) you can just use your project name as the path root.
import {DatePanel} from 'MyProject/components/panels';
import HomeScreen from 'MyProject/screens/HomeScreen';
No problems with flow, Xcode, etc.
It's possible. I've done it, but I don't recommend it. It doesn't work when xcode starts bundler because you have to do npm start -- --reset-cache. You have to use workarounds to learn your IDE understand this paths. It doesn't work with Flow.
You can use npm babel-plugin-module-resolver. Babel is used by metro budler.
.babelrc.
{
"presets": ["react-native"],
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"alias": {
"src": "./src",
"root": "./"
}
}
]
],
}
Related
Just started working again with Visual studio code after years on PHPStorm/Webstorm
I've decided to take the transition just because of how lightweight VSCode is and because I don't want to rely on a paid service/having it on every computer since VSCode is almost everywhere and free.
I started fresh
Vite + Vue3
Now I've come across several issues with
Imports
CTRL+Click - goto reference
Autocompletes
my Vite.config is as follows - to enable aliases
import { defineConfig } from "vite";
import { fileURLToPath, URL } from "url";
import vue from "#vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
/// <reference types="vitest" />
export default defineConfig({
resolve: {
extensions: [".js", ".json", ".vue", ".scss", ".css"],
fallback: {
crypto: path.resolve("crypto-browserify"),
stream: path.resolve("stream-browserify"),
},
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
img: path.resolve(__dirname, "./public/img"),
},
},
plugins: [vue()],
test: {},
server: {
port: 8080,
},
build: {
sourcemap: false,
minify: false,
assetsDir: "chunks",
},
css: {
preprocessorOptions: {
scss: {
additionalData: `#use "sass:math"; #import "./src/assets/scss/v2/legacy.scss"; #import "./src/assets/scss/common.scss";`,
},
},
},
});
Now, with vite config alone I can import using the "#" alias - but no intellisense is taking place,
I can't autocomplete imports nor can I ctrl + click
After adding a jsconfig.json file
{
"compilerOptions": {
"target": "ESNext",
"baseUrl": ".",
"paths": {
"#/*": ["src/*"]
}
}
}
I am now able to import my components using the "#" and also have full intellisense on them and can CTRL+click them
BUT, now I've lost the ability to import node_modules - lost all intellisense on that
So, if I use my vite/jsconfig I can ctrl+click/have auto complete on "#" alias
but I lost my node_module import capabilities
If I remove those vite.config alias configuration and remove jsconfig
I get back node_module intellisense and lost my project's intellisense.
What am I missing here? please help me figure this out.
I've also removed any / every npm import extension just so that I can understand how this works
The problem that you have here because of jsconfig.json file.
The presence of jsconfig.json file in a directory indicates that the directory is the root of a JavaScript Project. The jsconfig.json file specifies the root files and the options for the features provided by the JavaScript language service (vscode).
Most of the time you don't need it, but there is some examples where u can use it like IntelliSense customization. examples
more details:
jsconfig.json is a descendant of tsconfig.json, which is a configuration file for TypeScript. jsconfig.json is tsconfig.json with "allowJs" attribute set to true and since there is no actual compilation is required for JavaScript. These attributes exist because jsconfig.json is a descendant of tsconfig.json (just)
So, not all options are the same here like target :
The target setting changes which JS features are downleveled and which are left intact. For example, an arrow function () => this will be turned into an equivalent function expression if target is ES5 or lower.
Changing target also changes the default value of lib.
With that being said, vscode IntelliSense can be effected by those changes. so if u remove it, everything will works as expected.
In other words target can effect IntelliSense on jsconfig.json.
For your case, you just need to add it as following:
jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/*": ["src/*"]
}
}
}
vite.config.js
alias: {
'#/': path.resolve(__dirname, './src')
}
For more reading about jsconfig.json for vscode: here
I'm trying to understand how to fix the following error using Jest in my unit tests in NodeJS.
The test run with this command "test": "NODE_ENV=test jest spec/* -i --coverage --passWithNoTests",
I'm also using babel and this is my config
{
"presets": [["#babel/env", { "targets": { "node": "current" } }]],
"plugins": [
"#babel/plugin-syntax-dynamic-import",
["babel-plugin-inline-import", { "extensions": [".gql"] }],
["#babel/plugin-proposal-decorators", { "legacy": true }]
]
}
In package.json I have this
"jest": {
"verbose": true,
"collectCoverageFrom": [
"spec/**/*.js"
]
},
I tried several guides online but cannot find a solution to this
You've got Jest successfully configured to transform your code, but it is not transforming modules that you're importing—in this case node-fetch, which has the import keyword in its source code (as seen in your error). This is because, by default, Jest is configured not to transform files in node_modules:
transformIgnorePatterns [array]
Default: ["/node_modules/", "\.pnp\.[^\/]+$"]
An array of regexp pattern strings that are matched against all source file paths before transformation. If the file path matches any of the patterns, it will not be transformed.
You can set transformIgnorePatterns to exclude certain packages in node_modules with a jest.config.js like this:
const esModules = [
'node-fetch',
'data-uri-to-buffer',
'fetch-blob',
'formdata-polyfill',
].join('|');
module.exports = {
transformIgnorePatterns: [
`/node_modules/(?!${esModules})`,
'\\.pnp\\.[^\\/]+$',
],
};
(see https://github.com/nrwl/nx/issues/812#issuecomment-429420861)
If you have .babelrc try to rename it to babel.config.js
Source:
https://babeljs.io/docs/en/configuration#whats-your-use-case
but also this (there's more in the discussion)
Jest won't transform the module - SyntaxError: Cannot use import statement outside a module
I have a project in which I bundle a components library using Rollup (generating a bundle.esm.js file). These components are then used in another project, that generates web pages which use these components - each page is using different components.
The problem is, that the entire components library is always bundled with the different page bundles, regardless of which components I'm using, unnecessarily increasing the bundle size.
This is my Rollup setup:
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import pkg from './package.json';
const extensions = [
'.js', '.jsx', '.ts', '.tsx',
];
export default [
{
input: './src/base/index.ts',
plugins: [
peerDepsExternal(),
resolve({ extensions }),
babel({
exclude: 'node_modules/**',
extensions,
}),
commonjs(),
],
output: [
{ file: pkg.main, format: 'cjs', sourcemap: true },
{ file: pkg.module, format: 'es', sourcemap: true },
],
watch: {
clearScreen: false,
},
},
];
I have "modules" set to false in webpack, as well.
There are things you will need to do to achieve treeshakable code from both sides - the built package and the project using it.
From your code snippet, I see that you have not add flag preserveModules: true in the rollup config file to prevent the build output from bundling. Webpack can not treeshake a bundled file FYI.
export default {
...
preserveModules: true,
...
}
On the side of the project that using it, you have to specify sideEffects in the package.json - read the doc to know how to config them. Beside that, the optimization in webpack has to has sideEffects: true, also read the doc here.
Hope this helps!
As you don't know which components of your Component Library (CL) will be needed by the adopters repositories you need to export everything but in a way
the adopters can execute a tree-shaking on your CL when they do their own build (and just include what they really need).
In a few words, you have to make your CL, tree-shakable. In order to achieve this, on your CL repo you have to:
Use bundlers that support tree-shaking (rollup, webpack, etc..)
Create the build for modules of type es/esm, NOT commonJS/cjs, etc..
Ensure no transpilers/compilers (babel,tsconfig, etc..) usually used as plugins, transform your ES module syntax to another module syntax.
By the default, the behavior of the popular Babel preset #babel/preset-env may break this rule, see the documentation for more details.
// babelrc.json example that worked for me
[
"#babel/preset-env",
{
"targets": ">0.2%, not dead, not op_mini all"
}
],
In the codebase, you always have to use import/export (no require) syntax, and import specifically the things you need only.
import arrayUtils from "array-utils"; //WRONG
import { unique, implode, explode } from "array-utils"; //OK
Configure your sideEffects on the package.json.
"sideEffects": ["**/*.css"], //example 1
"sideEffects": false, //example 2
DO NOT create a single-bundle file but keep the files separated after your build process (official docs don't say this but was the only solution that worked for me)
// rollup.config.js example
const config = [
{
input: 'src/index.ts',
output: [
{
format: 'esm', // set ES modules
dir: 'lib', // indicate not create a single-file
preserveModules: true, // indicate not create a single-file
preserveModulesRoot: 'src', // optional but useful to create a more plain folder structure
sourcemap: true, //optional
},
],
... }]
Additionally, you may need to change your module entry point in order the adopters can directly access to the proper index.js file where you are exporting everthing:
// package.json example
{
...
"module": "lib/index.js", //set the entrypoint file
}
Note: Remember that tree-shaking is executed by an adopter repository that has a build process that supports tree-shaking (eg: a CRA repo) and usually tree-shaking is just executed on prod mode (npm run build), no on dev mode. So be sure to properly test if this is working or not.
Our app imports files using import ES2015 style syntax, utilizing Webpack 4.6.0 native support for ES2015 modules. We also use an alias to shorten our relative file paths.
Webpack.conf.js
resolve: {
extensions: ['.js', '.json', '.less'],
alias: {
'#': resolve('public/js'),
'handlebars': 'handlebars/dist/handlebars.js',
},
modules: ['less', 'node_modules']
},
example.js
import widget from '#/widgets/widget';
file structure
- webpack.conf.js
- .babelrc
- test/
- public/
- - js/
- - - widgets/
- - - - widget.js
When I imported for example example.js, which has an alias'd import, Jest would throw an error, "cannot resolve module '#/widgets/widget'.
According to a remarkably specific article as well as the Jest documentation, the solution is to use Jest's ModuleNameMapper config property to set up matching alias'. I have attempted to do so:
package.json
"jest": {
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
"#(.*)$": "<rootDir>/public/js/$1"
},
"verbose": true,
"transform": {
"^.+\\.js$": "babel-jest"
},
"globals": {
"NODE_ENV": "test"
},
"moduleFileExtensions": [
"js"
],
"moduleDirectories": [
"node_modules"
]
},
As well as properly configure babel:
.babelrc
{
"presets": [
[
"env",
{
"modules": false,
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
],
"es2015",
"stage-2"
],
"plugins": [
"syntax-dynamic-import"
]
}
Now, when I run Jest (with the --no-cache flag just in case), I get this error:
test/test.test.js
● Test suite failed to run
Configuration error:
Could not locate module #babel/code-frame (mapped as /home/calebjay/Documents/ide/public/js/babel/code-frame)
Please check:
"moduleNameMapper": {
"/#(.*)$/": "/home/calebjay/Documents/ide/public/js/$1"
},
"resolver": undefined
I can't find #babel/code-frame anywhere outside of package-lock.json, and just for giggles I stripped all mentions of #{{anything}} from there and ran tests again, same result.
Is jest stepping over babel somehow? How can I get my tests to run with Jest using aliases?
EDIT: To try to narrow down what is calling #babel/code-frame, I tried deleting es2015 and stage-2 from .babelrc, to no effect. I tried deleting the transform property of the Jest config in package.json, to no effect. I tried deleting the env.test.plugins property from .babelrc, to no effect. Same error.
EDIT2: Thinking maybe some other package is requiring it, I checked package.json. It seems jest-message-util requires #babel/code-frame. I do see #babel/code-frame in my node_modules though... so perhaps the problem is that jester is saying "ok, all instances of #, turn into public/js" ?
"#(.*)$": "<rootDir>/public/js/$1"
will convert #babel/code-frame to
"<rootDir>/public/js/babel/code-frame"
which doesn't exist. You need to make your pattern more specific and do
"#/(.*)$": "<rootDir>/public/js/$1"
Note the additional / at the beginning. That way it will still match your #/widgets/widget, but it won't match other scoped packages.
I have a react component in the path
src/components/test
import React from 'react';
import ReactDom from 'react-dom';
class TestComp extends React.Component {}
export default TestComp;
I am exposing the component in index.js from path
src/index.js
import TestComp from './components/test';
export {
TestComp
};
I have added main in package.json as "main": "src/index.js"
I have published a npm package test-comp of above application and using same in another application.
main.js
import {TestComp} from 'test-comp';
I am using grunt-browserify in this application with following options set.
options: {
"transform": [
[
"babelify",
{
"presets": [
"es2015",
"react",
"stage-0"
]
}
]
],
browserifyOptions: {
debug: true,
extensions: ['.js', '.jsx'],
entries: ['main.js']
}
}
When I run grunt browserify getting following error.
>> import TestComp from './components/test';
>> ^
>> ParseError: 'import' and 'export' may appear only with 'sourceType: module'
Warning: Error running grunt-browserify. Use --force to continue.
It probably not understanding the path mentioned in node module or rejecting to understand the same which linting. I even have tried adding following in .eslintrc but no luck
{
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"env": {
"browser": true,
"es6": true
},
"ecmaFeatures": {
"modules": true
}
}
I tried most of SO answers related to this error. But still stuck in same place.
EDIT
I am able to browserify first module directly with almost similar configuration. Getting this error when first module is loaded as node dependancy in other application as explained above.
So you wrote the module test-comp in ES6, using import and export, and the main entry of the package.json in test-comp refers to src/index.js.
The answer is that browserify transforms don't apply to every module you require. They only apply to the immediate project: not the project's dependencies.
If you want to require a module that uses ES6 syntax in browserify, you'll either need to
Add a prepublish script to test-comp that transpiles it to ES5, and change the main entry of test-comp to refer to that ES5 version, not the ES6 version
Add babelify as a dependency of test-comp and add babelify as a browserify transform in the package's 'browserify' entry, as documented in babelify.