How to use [bitdev] with react 18 running `bit tag` fails due to react testing library - reactjs

I am trying to use bit.dev for a front-end micro service and I am running into an issue when running bit tag with react 18 I get this error
The following errors were found while running the build pipeline
Failed task 1: "teambit.defender/tester:TestComponents" of env "teambit.react/react"
component: cagosto48.select-boxes/ui/wizard-select#0.0.1
Error: Cannot find module 'react-dom/client' from 'node_modules/.pnpm/registry.npmjs.org+#testing-library+react#13.3.0_sfoxds7t5ydpegc3knd667wn6m/node_modules/#testing-library/react/dist/pure.js'
Require stack:
node_modules/.pnpm/registry.npmjs.org+#testing-library+react#13.3.0_sfoxds7t5ydpegc3knd667wn6m/node_modules/#testing-library/react/dist/pure.js
node_modules/.pnpm/registry.npmjs.org+#testing-library+react#13.3.0_sfoxds7t5ydpegc3knd667wn6m/node_modules/#testing-library/react/dist/index.js
cagosto48.select-boxes_ui_wizard-select#0.0.1/dist/wizard-select.spec.js
Found 1 errors in 1 components
Failed task 2: "teambit.preview/preview:GeneratePreview" of env "teambit.react/react"
component: cagosto48.select-boxes/ui/wizard-select#0.0.1
ModuleNotFoundError: Module not found: Error: Can't resolve '#emotion/react' in '/Users/carlosagosto/Library/Caches/Bit/capsules/b89c12b2cff6d117ea54ad5513a8d8d3d0194e16/node_modules/.pnpm/registry.npmjs.org+#mui+styled-engine#5.10.3_react#17.0.2/node_modules/#mui/styled-engine'
ModuleNotFoundError: Module not found: Error: Can't resolve '#emotion/react' in '/Users/carlosagosto/Library/Caches/Bit/capsules/b89c12b2cff6d117ea54ad5513a8d8d3d0194e16/node_modules/.pnpm/registry.npmjs.org+#mui+styled-engine#5.10.3_react#17.0.2/node_modules/#mui/styled-engine'
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/Compilation.js:1773:28
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:811:13
at eval (eval at create (/Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:10:1)
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:286:22
at eval (eval at create (/Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:442:22
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:124:11
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:673:25
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:882:8
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:1002:5
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/neo-async/async.js:6883:13
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/lib/NormalModuleFactory.js:985:45
at finishWithoutResolve (/Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:312:11)
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:386:15
at /Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:435:5
at eval (eval at create (/Users/carlosagosto/.bvm/versions/0.0.832/bit-0.0.832/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
Found 1 errors in 1 components
✖ Total 7 tasks. 5 succeeded. 2 failed. 0 skipped. Total errors: 2.
I have look at this the docs for react 18 https://bit.cloud/bit-foundations/react/react-version-envs/react-18-env but still having this issue I updated my workspace.jsonc file to be this.
/**
* this is the main configuration file of your bit workspace.
* for full documentation, please see: https://bit.dev/docs/workspace/workspace-configuration
**/ {
"$schema": "https://static.bit.dev/teambit/schemas/schema.json",
/**
* main configuration of the Bit workspace.
**/
"teambit.workspace/workspace": {
/**
* the name of the component workspace. used for development purposes.
**/
"name": "my-workspace-name",
/**
* set the icon to be shown on the Bit server.
**/
"icon": "https://static.bit.dev/bit-logo.svg",
/**
* default directory to place a component during `bit import` and `bit create`.
* the following placeholders are available:
* name - component name includes namespace, e.g. 'ui/button'.
* scopeId - full scope-id includes the owner, e.g. 'teambit.compilation'.
* scope - scope name only, e.g. 'compilation'.
* owner - owner name in bit.dev, e.g. 'teambit'.
**/
"defaultDirectory": "{scope}/{name}",
/**
* default scope for all components in workspace.
**/
"defaultScope": "my-scope"
},
/**
* main configuration for component dependency resolution.
**/
"teambit.dependencies/dependency-resolver": {
/**
* choose the package manager for Bit to use. you can choose between 'yarn', 'pnpm'
*/
"packageManager": "teambit.dependencies/pnpm",
"policy": {
"dependencies": {
"#bit-foundations/react.react-version-envs.react-18-env": "0.0.3",
"#emotion/react": "^11.10.0",
"#emotion/styled": "^11.10.0",
"#mui/material": "^5.10.2"
},
"peerDependencies": {
"#testing-library/react": "^13.3.0",
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react-hooks": "^8.0.1",
"#testing-library/user-event": "^14.4.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"linkCoreAspects": true
},
/**
* workspace variants allow to set different subsets of configuration for components in your
* workspace. this is extremely useful for upgrading, aligning and building components with a new
* set of dependencies. a rule can be a directory or a component-id/namespace, in which case,
* wrap the rule with curly brackets (e.g. `"{ui/*}": {}`)
* see https://bit.dev/docs/workspace/variants for more info.
**/
"teambit.workspace/variants": {
"{ui/**}, {pages/**}": {
"bit-foundations.react/react-version-envs/react-18-env#0.0.3": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
/**
* "*" is a special rule which applied on all components in the workspace.
**/
"*": {
/**
* uncomment to apply the chosen environment on all components.
**/
// "teambit.react/react": { }
}
}
}

I have copied your workspace.jsonc to a new react environment and didn't have any trouble tagging a new component. Maybe updating bit will help.
As August 30th, 2022, the latest version is 0.0.833
bvm upgrade
Afterwards upgrading, make sure you delete pnpm-lock.yaml, node_modules and the capsule. Let's start to spin everything from zero.
rm -rf node_modules pnpm.lock-yaml
And also the capsule:
bit capsule delete
Now, re install and compile (twice):
bit install && bit compile && bit install && bit compile
Check that bit status is clean:
bit status
# fix any potential issue
That might solve it.
Otherwise, your problem comes from #emotion/react requesting react 17 which is not in your node_modules. You can try downgrading the peerDependencies in your policy:
"peerDependencies":{
"react": "^17.0.2"
}

Related

cannot remove google-recaptura v2 form devDependencies

I tried to remove this types from dev dependencies in every possible way but no luck any idea what is the issue ?
"devDependencies": {
"#types/react-google-recaptcha": "^2.1.3"
}

ReferenceError: $RefreshReg$ is not defined

In a CRA based React app I get this error in a webworker file (all code is using Typescript) when I import files that are also imported by normal application code (normal === non-worker) and run the app using the babel dev server in debug mode.
Searching for this error brings me to various module specific issue reports/solutions, which I cannot use, however. But it's clear that this is a React hot reloading problem and I wonder how to solve it, as it keeps me from using my app code also in web workers.
My dev dependencies are:
"devDependencies": {
"#babel/core": "^7.12.10",
"#babel/preset-env": "^7.11.11",
"#babel/preset-typescript": "^7.12.7",
"#testing-library/react": "^11.2.3",
"#types/classnames": "^2.2.11",
"#types/color": "^3.0.1",
"#types/d3": "^6.2.0",
"#types/history": "4.7.8",
"#types/jest": "^26.0.20",
"#types/lodash": "^4.14.168",
"#types/node": "^14.14.22",
"#types/react": "^17.0.0",
"#types/react-dom": "^17.0.0",
"#types/react-test-renderer": "^17.0.0",
"#types/react-window": "^1.8.2",
"#types/resize-observer-browser": "^0.1.5",
"#types/selenium-webdriver": "^4.0.11",
"#types/topojson": "^3.2.2",
"#types/uuid": "^8.3.0",
"#types/ws": "^7.4.0",
"#typescript-eslint/eslint-plugin-tslint": "^4.14.0",
"acorn": "^8.0.5",
"antlr4ts-cli": "^0.5.0-alpha.4",
"eslint": "^7.18.0",
"eslint-plugin-flowtype": "^5.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsdoc": "^31.3.3",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-prefer-arrow": "^1.2.2",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"identity-obj-proxy": "^3.0.0",
"jest": "26.6.0",
"jest-transform-stub": "^2.0.0",
"jest-websocket-mock": "^2.2.0",
"mock-socket": "^9.0.3",
"monaco-editor-webpack-plugin": "^1.9.1",
"monaco-typescript": "^4.2.0",
"raw-loader": "^4.0.2",
"react-app-rewired": "^2.1.8",
"react-scripts": "^4.0.3",
"react-test-renderer": "^17.0.1",
"selenium-webdriver": "^4.0.0-beta.1",
"ts-jest": "^26.5.2",
"tslint": "^6.1.3",
"typescript": "^4.1.3",
"typescript-eslint-parser": "22.0.0",
"webdriver-manager": "^12.1.8",
"webpack": "4.44.2",
"webpack-bundle-analyzer": "^4.4.0",
"worker-loader": "^3.0.8",
"ws": "^7.4.3"
},
The only promising solution I also could apply is: https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/176#issuecomment-683150213, but it didn't help. I still get the same error. My web worker code is:
/* eslint-disable no-restricted-globals */
/* eslint-disable no-eval */
/* eslint-disable #typescript-eslint/no-unused-vars */
(window as any).$RefreshReg$ = () => {/**/};
(window as any).$RefreshSig$ = () => () => {/**/};
import { ShellInterfaceSqlEditor } from "../../supplement/ShellInterface";
import { PrivateWorker, ExecutionResultType, IConsoleWorkerData } from "./console.worker-types";
const backend = new ShellInterfaceSqlEditor();
const ctx: PrivateWorker = self as any;
The further discussion there about changing the babel loader config is unfortunately beyond me, as I don't configure that myself (what I'm using, however, is react-app-rewired to configure some custom loaders).
What else could I try to fix the issue?
In my case, this error was happening when overwriting Webpack's mode option. After removing the line below I stopped receiving the error.
webpackConfig.mode = 'none'; // this line caused the bug
I believe this is because react-refresh requires webpack to be in mode: 'development' to function properly.
You may want to read about Webpack's modes here: https://webpack.js.org/configuration/mode/. It is also possible that you are setting Webpack mode from the NODE_ENV environment variable.
I tried many of the solutions in this answer and in various Github issues, but none of them resolved the issue for me. Eventually I found a solution via the Webpack sideEffects optimization and config!
tl;dr:
Ensure your Webpack config has an object optimization set and that the optimization object has an attribute sideEffects set to true. Seems like nx and potentially cra or craco defaults this to false, leading to unused React components being imported in WebWorker bundles if they're exported as part of a "barrel" file
If you're importing your own shared ui package which exports React components and some non-React components, then you need to specify the sideEffects config in your package's package.json file to ensure that the React components are marked as "pure" and safe to prune. See below for more details
After inspecting the bundles of my WebWorker, I realized that some React components were being bundled into the worker bundle from worker-loader, even though they weren't being used in the worker. At least one of these cases was happening in our app because we have a shared package which contained some React components and other normal TS utils.
Our WebWorker was importing a value (named export) from this package and for some reason, the entire package was being included in the WebWorker – including the React components that were not being used anywhere! The React Fast Refresh plugin (which is installed / used by CRA by default) then was augmenting our WebWorker bundle with the changes necessary to support hot refresh / reloading (calls to $RefreshReg$ and co).
Some Github issues regarding this problem referenced a Webpack tree shaking optimization called sideEffects, which you can read more about at https://webpack.js.org/guides/tree-shaking/. Here's the relevant bit:
The new webpack 4 release expands on this capability with a way to provide hints to the compiler via the "sideEffects" package.json property to denote which files in your project are "pure" and therefore safe to prune if unused.
In your package's package.json, you can either specify "sideEffects": false to mark the whole package as "pure" and safe to prune if unused, or you can specify the specific exports / paths that do have side effects, eg for us:
"sideEffects": [
"./src/styles/*"
],
However, setting this value didn't work for our app immediately, which was confusing. Eventually, I ran into a thread about this for nx where a very helpful comment noted that their Webpack config was disabling the sideEffects optimization for Webpack: (https://github.com/nrwl/nx/issues/9717#issuecomment-1163533981)
I found that Nx is passing optimization: { sideEffects: false } to webpack, which explicitly turns off tree shaking regardless of your package.json contents. The library that was not being tree shaken in my original issue (lodash-es) already has it's own package.json where it specifies the required setting to facilitate optimal tree shaking, however Nx was turning off tree shaking in Webpack globally, so that it doesn't happen at all for any library or any code in the project.
I tried explicitly setting webpackConfig.optimization.sideEffects = true in my app and boom! Issue resolved, React components being excluded from the WebWorker bundle.
You can try worker-plugin instead of worker-loader. I have been running into the same issue for a long time before trying worker-plugin.
I've also stumbled on this issue on a CRA project
I'm not using typescript for the Web Worker but adding this helped fix the error. (BTW I've only found it thanks to your question. Thanks!)
web.worker.js
if (process.env.NODE_ENV != 'production') {
global.$RefreshReg$ = () => {};
global.$RefreshSig$ = () => () => {};
}
Maybe if you try (global as any) it would work?
Another thing I'm doing is I only import libraries at the top and any code that is used by both main and the worker is added with a require before the usage
e.g.
web.worker.js
const generateSingle = async (client) => {
const mark = `generate for: ${client.id}`;
performance.mark(mark);
const { BillingReportDocument } = require('../pdf/PdfBillingReport');
/* ... */
}
Otherwise I get a different error like "browser is not defined" it's related to emotion/react being used in that file

Shared component library best practices

I am creating a shareable React component library.
The library contains many components but the end user may only need to use a few of them.
When you bundle code with Webpack (or Parcel or Rollup) it creates one single file with all the code.
For performance reasons I do not want to all that code to be downloaded by the browser unless it is actually used.
Am I right in thinking that I should not bundle the components? Should the bundling be left to the consumer of the components?
Do I leave anything else to the consumer of the components? Do I just transpile the JSX and that's it?
If the same repo contains lots of different components, what should be in main.js?
This is an extremely long answer because this question deserves an extremely long and detailed answer as the "best practice" way is more complicated than just a few-line response.
I've maintained our in-house libraries for 3.5+ years in that time I've settled on two ways I think libraries should be bundled the trade-offs depend on how big your library is and personally we compile both ways to please both subsets of consumers.
Method 1: Create an index.ts file with everything you want to be exposed exported and target rollup at this file as its input. Bundle your entire library into a single index.js file and index.css file; With external dependencies inherited from the consumer project to avoid duplication of library code.
(gist included at bottom of example config)
Pros: Easy to consume as project consumers can import everything from the root relative library path import { Foo, Bar } from "library"
Cons: This will never be tree shakable, and before people say to do this with ESM and it will be tree shakeable. NextJS doesn't support ESM at this current stage and neither do a lot of project setups that's why it's still a good idea to compile this build to just CJS. If someone imports 1 of your components they will get all the CSS and all the javascript for all your components.
Method 2: This is for advanced users: Create a new file for every export and use rollup-plugin-multi-input with the option "preserveModules: true" depending on how what CSS system you're using your also need to make sure that your CSS is NOT merged into a single file but that each CSS file requires(".css") statement is left inside the output file after rollup and that CSS file exists.
Pros: When users import { Foo } from "library/dist/foo" they will
only get the code for Foo, and the CSS for Foo, and nothing more.
Cons: This setup involves the consumer having to handle node_modules
require(".css") statements in their build configuration with NextJS
this is done with next-transpile-modules npm package.
Caveat: We use our own babel plugin you can find it here: https://www.npmjs.com/package/babel-plugin-qubic to allow people to import { Foo, Bar } from "library" and then with babel transform it to...
import { Foo } from "library/dist/export/foo"
import { Bar } from "library/dist/export/bar"
We have multiple rollup configurations where we actually use both methods; so for library consumers who don't care for tree shaking can just do "Foo from "library" and import the single CSS file, and for library consumers who do care for tree shaking and only using critical CSS they can just turn on our babel plugin.
Rollup guide for best practice:
whether you are using typescript or not ALWAYS build with "rollup-plugin-babel": "5.0.0-alpha.1"
Make sure your .babelrc looks like this.
{
"presets": [
["#babel/preset-env", {
"targets": {"chrome": "58", "ie": "11"},
"useBuiltIns": false
}],
"#babel/preset-react",
"#babel/preset-typescript"
],
"plugins": [
["#babel/plugin-transform-runtime", {
"absoluteRuntime": false,
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false,
"version": "^7.8.3"
}],
"#babel/plugin-proposal-class-properties",
"#babel/plugin-transform-classes",
["#babel/plugin-proposal-optional-chaining", {
"loose": true
}]
]
}
And with the babel plugin in rollup looking like this...
babel({
babelHelpers: "runtime",
extensions,
include: ["src/**/*"],
exclude: "node_modules/**",
babelrc: true
}),
And your package.json looking ATLEAST like this:
"dependencies": {
"#babel/runtime": "^7.8.3",
"react": "^16.10.2",
"react-dom": "^16.10.2",
"regenerator-runtime": "^0.13.3"
},
"peerDependencies": {
"react": "^16.12.0",
"react-dom": "^16.12.0",
}
And finally your externals in rollup looking ATLEAST like this.
const makeExternalPredicate = externalArr => {
if (externalArr.length === 0) return () => false;
return id => new RegExp(`^(${externalArr.join('|')})($|/)`).test(id);
};
//... rest of rollup config above external.
external: makeExternalPredicate(Object.keys(pkg.peerDependencies || {}).concat(Object.keys(pkg.dependencies || {}))),
// rest of rollup config below external.
Why?
This will bundle your shit to automatically to inherit
react/react-dom and your other peer/external dependencies from the
consumer project meaning they won't be duplicated in your bundle.
This will bundle to ES5
This will automatically require("..") in all the babel helper functions for objectSpread, classes, etc FROM the consumer project which will wipe another 15-25KB from your bundle size and mean that the helper functions for objectSpread won't be duplicated in your library output + the consuming projects bundled output.
Async functions will still work
externals will match anything that starts with that peer-dependency suffix i.e babel-helpers will match external for babel-helpers/helpers/object-spread
Finally here is a gist for an example single index.js file output rollup config file.
https://gist.github.com/ShanonJackson/deb65ebf5b2094b3eac6141b9c25a0e3
Where the target src/export/index.ts looks like this...
export { Button } from "../components/Button/Button";
export * from "../components/Button/Button.styles";
export { Checkbox } from "../components/Checkbox/Checkbox";
export * from "../components/Checkbox/Checkbox.styles";
export { DatePicker } from "../components/DateTimePicker/DatePicker/DatePicker";
export { TimePicker } from "../components/DateTimePicker/TimePicker/TimePicker";
export { DayPicker } from "../components/DayPicker/DayPicker";
// etc etc etc
Let me know if you experience any problems with babel, rollup, or have any questions about bundling/libraries.
When you bundle code with Webpack (or Parcel or Rollup) it creates one single file with all the code.
For performance reasons I do not want to all that code to be downloaded by the browser unless it is actually used
It's possible to have separate files generated for each component. Webpack has such ability by defining multiple entries and outputs. Let's say you have the following structure of a project
- my-cool-react-components
- src // Folder contains all source code
- index.js
- componentA.js
- componentB.js
- ...
- lib // Folder is generated when build
- index.js // Contains components all together
- componentA.js
- componentB.js
- ...
Webpack file would look something like this
const path = require('path');
module.exports = {
entry: {
index: './src/index.js',
componentA: './src/componentA.js',
componentB: './src/componentB.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'lib'),
},
};
More info on "code splitting" is here in Webpack docs
If the same repo contains lots of different components, what should be in main.js?
There is a single field in package.json file named main, it's good to put its value lib/index.js according to the project structure above. And in index.js file have all components exported. In case consumer wants to use single component it's reachable by simply doing
const componentX = require('my-cool-react-components/lib/componentX');
Am I right in thinking that I should not bundle the components? Should the bundling be left to the consumer of the components? Do I leave anything else to the consumer of the components? Do I just transpile the JSX and that's it?
Well, it's up to you. I've found that some React libraries are published in original way, others - are in bundled way. If you need some build process, then define it and export bundled version.
Hope, all your questions are answered :)
You can split your components like lodash is doing for their methods.
What you probably have is separate components that you could allow importing separately or through the main component.
Then the consumer could import the whole package
import {MyComponent} from 'my-components';
or its individual parts
import MyComponent from 'my-components/my-component';
Consumers will create their own bundles based on the components they import. That should prevent your whole bundle being downloaded.
You should take a look at Bit, I think this is a good solution to share, reuse and visualize components.
It is very easy to setup. You can install your bit library or just a component with:
npm i #bit/bit.your-library.components.buttons
Then you can import the component in your app with:
import Button3 from '#bit/bit.your-library.components.buttons';
The good part is that you don't have to worry about configuring Webpack and all that jazz. Bit even supports the versioning of your components. This example shows a title-list react component so you can take a look if this meets your requirements or not
There is a configuration in webpack to create chunk files. To start with it will create the main bundle into multiple chunks and get it loaded as when required. if your project has well structured modules, it will not load any code which is not required.

How to configure react-script so that it doesn't override tsconfig.json on 'start'

I'm currently using create-react-app to bootstrap one of my projects. Basically, I'm trying to set up paths in tsconfig.json by adding these to the default tsconfig.json generated by create-react-app:
"baseUrl": "./src",
"paths": {
"interfaces/*": [
"common/interfaces/*",
],
"components/*": [
"common/components/*",
],
},
However, every time I run yarn start which basically runs react-scripts start, it deletes my changes and generates the default configurations again.
How can I tell create-react-app to use my custom configs?
I was able to do this by using advice from this issue.
Put the configuration options react scripts likes to remove in a separate file (e.g. paths.json) and reference it from tsconfig.json via the extends directive.
paths.json:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"interfaces/*": [ "common/interfaces/*"],
"components/*": [ "common/components/*"],
}
}
}
tsconfig.json
{
"extends": "./paths.json"
...rest of tsconfig.json
}
Create React App does not currently support baseUrl. However there is a workaround...to setup baseUrl for both webpack and the IDE you have to do the following:
Create a .env file with the following code:
NODE_PATH=./
Create a tsconfig.paths.json file with the following code inside:
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"src/*": ["*"]
}
}
}
Add the following line to tsconfig.json
{
"extends": "./tsconfig.paths.json",
...
}
You can't and I am unsure when you will be able to. I have been trying to use baseUrl and paths so I can avoid relative imports but as you can see they are intentionally removing certain values. The "(yet)" is encouraging but (sigh) who knows when they will officially be supporting it. I recommend subscribing to this github issue to be alerted if/when this changes.
The following changes are being made to your tsconfig.json file:
- compilerOptions.baseUrl must not be set (absolute imports are not supported (yet))
- compilerOptions.paths must not be set (aliased imports are not supported)
If you are using react-scripts 4.0.0 like me then all you need to do is remove the line (around line 160 on my end):
paths: { value: undefined, reason: 'aliased imports are not supported' }
from the file node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
I was able to straight up add my baseUrl and paths config to my tsconfig.json file like so:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#domain/*": ["../src/domain/*"],
},
}
}
and finally compile and move on with my life.
Per usual, YMMV. Please test your stuff. This is obviously a hack but it worked for me so I'm posting here in case it helps someone.
Here's a patch if you feel like sharing with your team:
diff --git a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
index 00139ee..5ccf099 100644
--- a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
+++ b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
## -156,7 +156,8 ## function verifyTypeScriptSetup() {
: 'react',
reason: 'to support the new JSX transform in React 17',
},
- paths: { value: undefined, reason: 'aliased imports are not supported' },
+ // Removed this line so I can add paths to my tsconfig file
+ // paths: { value: undefined, reason: 'aliased imports are not supported' },
};
Edit
Per #Bartekus thoughtful suggestion in the comments thread I'm adding information on the package I use when I need to add (possibly) temporary changes like these to an npm package: patch-package
The package essentially provides a way to make changes to a package in a cleaner way. Especially when you consider collaboration it becomes very cumbersome to directly change an npm file and move on. The next time you update that package or even when you start developing in a new machine and run npm install your changes will be lost. Also, if you have teammates working on the same project they would never inherit the changes.
In essence you go through the following steps to patch a package:
# fix a bug in one of your dependencies
vim node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
# run patch-package to create a .patch file
npx patch-package react-scripts
# commit the patch file to share the fix with your team
git add patches/react-scripts+4.0.0.patch
git commit -m "Enable aliased imports in react-scripts"
Next time someone checks out the project and installs it, the patch will be applied automatically due to a post-install script you add during set up:
"scripts": {
+ "postinstall": "patch-package"
}
See up to date instructions in the package's documentation
I had a similar issue to this general problem (CRA overwrites "noEmit": false in my tsconfig.json of a React library I'm working on where I have two separate builds, one for local development, and another to build the production library with typings). Simple solution: use sed in a postbuild script in the package.json. For example: In-place edits with sed on OS X .
{
...
"scripts": {
...
"postbuild": "sed -i '' 's/{THING CRA IS REPLACING}/{WHAT YOU ACTUALLY WANT}/g' tsconfig.json # CRA is too opinionated on this one.",
...
}
...
}
This approach, however, is not cross-platform (unlike how rimraf is the cross-platform alternative to rm -rf).
For me, the problem was with VSCode using an older version of typescript (4.0.3), while the typescript version shipped with the project is (4.1.2).
The following did the trick for me:
Go to the command palette CTRL+Shift+P.
Choose "TypeScript: Select a TypeScript Version...".
Choose "Use workspace Version".
On Botpress (with react-scripts 4.0.3), we use a combination of 2 tricks to use paths without ejecting or patching the code. As Glenn and Microcipcip said, the first step is to extend the tsconfig.json file
tsconfig.path.json
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"~/*": ["src/*"],
"common/*": ["../bp/src/common/*"]
}
}
}
tsconfig.json
{
...
"extends": "./tsconfig.paths.json"
}
Then to make it work in the background, use the package react-app-rewired. It allows to make slight adjustments to the webpack configuration without actually ejecting CRA.
config-overrides.js
module.exports = {
webpack: (config, env) => {
config.resolve.alias['common'] = path.join(__dirname, '../bp/dist/common')
config.resolve.alias['~'] = path.join(__dirname, './src')
}
}
To see the full code, you can check the github repository https://github.com/botpress/botpress/tree/master/packages/ui-admin
For macOS this workaround should work.
package.json
"scripts": {
"start": "osascript -e 'tell app \"Terminal\" to do script \"cd $PATH_TO_REACT_APP && node ./setNoEmitFalse\"' && react-scripts start",
...
},
...
setNoEmitFalse.js
const fs = require('fs');
const { sleep } = require('sleep')
const path = './tsconfig.json'
const run = async () => {
sleep(2)
const tsconfig = fs.readFileSync(path, 'utf-8');
const fixed = tsconfig.replace('"noEmit": true', '"noEmit": false');
fs.writeFileSync(path, fixed)
}
run()
The execution of the javascript file in a separate terminal (osascript) provides the normal output for react-scripts in the original terminal.
Go to node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js and replace
const compilerOptions = {
...
};
by
const compilerOptions = { };

How to make angularjs typing a global in my project

I'm working on a project that has pulled in Typescript definitions the deprecated typings way and I would like to now move over to using the #types method instead.
Currently we have a typings.json file in the root of the project like so:
{
"globalDependencies": {
"angular": "registry:dt/angular#1.5.0+20161101124950",
"angular-cookies": "registry:dt/angular-cookies#1.4.0+20160317120654",
"angular-material": "registry:dt/angular-material#1.1.0-rc5.0+20161208205836",
"angular-resource": "registry:dt/angular-resource#1.5.0+20160914132003",
"angular-translate": "registry:dt/angular-translate#2.4.0+20160729132354",
"d3": "registry:dt/d3#0.0.0+20160907005744",
"jquery": "registry:dt/jquery#1.10.0+20160929162922",
"lodash": "registry:dt/lodash#4.14.0+20161110215204",
"moment": "registry:dt/moment#2.11.1+20161010105546",
"require": "registry:dt/require#2.1.20+20160919185614"
},
"resolution": "src/client/typings",
"dependencies": {
"angular-local-storage": "registry:dt/angular-local-storage#0.1.5+20160726182927",
"angular-ui-router": "registry:dt/angular-ui-router#1.1.5+20161222093745",
"requirejs": "registry:npm/requirejs#2.2.0+20160319062357"
}
}
As you can clearly see, these are currently installed as globals and are appearing in a src/client/typings folder in our dir structure.
I can already see I have a #types folder under my node_modules which contains some of the typings I have listed in this typings.json file.
In our tsconfig.json file we have an includes config section:
"include": [
"./typings/index.d.ts",
"./app/**/*.module.ts",
"./app/**/*.run.ts",
"./app/**/*.routes.ts",
"./app/**/*.enum.ts",
"./app/**/*.controller.ts",
"./app/**/*.model.ts",
"./app/**/*.directive.ts",
"./app/**/*.filter.ts",
"./app/**/*.service.ts",
"./app/interfaces/**/*.ts"
],
I have since commented out the ./typings/index.d.ts to be sure none of the older typings (not in the #types folders) are being pulled in.
Now, when I look at an .ts file for some angularjs code, I see the angular object is not being resolved anymore:
Having read around, I can just add an import to the file to resolve this (e.g. import * as angular from 'angular'), but it would mean I would need to add to every one of our .ts files that contain any angular code.
Is there an easy\recommended way I can make the angular reference a global in my project, or is best practice to add these fine grained imports across all the files where needed?
Thanks
Create a common .ts file under 'Typings' folder and add all required reference in that file like below.
After that, only add common .ts file reference to all the place where ever all reference required like below.
/// <reference path="../../typings/common.d.ts" />

Resources