How To Import Shared Typescript Code Using Create-react-app (no Eject)?
Solution 1:
You could use craco (create-react-app config override) to override the webpack config (abstracted as part of CRA) without ejecting.
Additionally you could use ts-loader
to reference non-transpiled ts code directly in external projects (e.g. if you wanted to reference/use shared code/lib as part of a mono-repo).
Assuming your CRA app is in the client
directory your project structure is like the following:
client/
|--src/
|--package.json
shared/
|--package.json
|--(ts files)package.json
cd client
yarn add -D @craco/craco ts-loader
- create a
craco.config.js
file in theclient/
(CRA) directory - ensure the
craco.config.js
has the following content
const path = require("path");
module.exports = {
webpack: {
configure: webpackConfig => {
// ts-loader is required to reference external typescript projects/files (non-transpiled)
webpackConfig.module.rules.push({
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
transpileOnly: true,
configFile: 'tsconfig.json',
},
})
return webpackConfig;
}
}
};
- Replace
react-scripts
commands inclient/package.json
withcraco
/* client/package.json */
"scripts": {
- "start": "react-scripts start",
+ "start": "craco start",
- "build": "react-scripts build",
+ "build": "craco build"
- "test": "react-scripts test",
+ "test": "craco test"
}
Solution 2:
UPDATE: Since react-app-rewired is only maintained passively and doesn't support CRA versions 2+ (we are are three major versions later at the time of writing), I would no longer recommend this approach.
After more hours of experimenting and reading up on GitHub issues, I finally have a working solution. Big thanks to BirukDmitry who made this very helpful post on GitHub. Step-by-step guide:
Install react-app-rewired and customize-cra
npm i react-app-rewired customize-cra --save-dev
Configure react-app-rewird with a minimal
config-overrides.js
like this:const { removeModuleScopePlugin, override, babelInclude } = require("customize-cra"); const path = require("path"); module.exports = override( removeModuleScopePlugin(), // (1)babelInclude([ path.resolve("src"), path.resolve("../common/src"), // (2) ]) );
Setting (1) is similar to what is needed for getting around the import-outside-src limitation in general (see linked question).
Setting (2) is crucial though to enabled babel-transpilation (and thus, including TS type stripping I presume) for other paths as well. This is where you have to put add your paths from which you want to import.
No adaptations needed for
tsconfig.json
.Import using relative paths, e.g.,
import * as mymodule from '../../common/src/mymodule'
.
Solution 3:
The solution is react-app-rewire-alias (for react-app-rewired or customize-cra or craco) :
According to the mentioned docs replace react-scripts
in package.json
and configure the next:
- rewired cra version:
// config-overrides.jsconst {alias, configPaths} = require('react-app-rewire-alias')
const aliasMap = configPaths('./tsconfig.paths.json') // or jsconfig.paths.jsonmodule.exports = alias(aliasMap)
module.exports.jest = aliasJest(aliasMap)
- craco version:
// craco.config.jsconst {CracoAliasPlugin, configPaths} = require('react-app-rewire-alias')
module.exports = {plugins: [{
plugin: CracoAliasPlugin,
options: {alias: configPaths('./tsconfig.paths.json')}
}]}
Configure aliases in json like this:
// tsconfig.paths.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"common/*": ["../../common/src/*"],
"@library/*": ["../../library/src/*"]
}
}
}
And add this file in extends
section of main typescript config file:
// tsconfig.json
{
"extends": "./tsconfig.paths.json",
// ...
}
Solution 4:
question where does ../../common/src/mymodule
lives at ?
is it another project ?
If it is another project why dont you link'em
inside common code project run
npm link
inside the project that will use the common code:
npm link common-project
If there are not two different projects. why does it has to be outside of src ?
The link you posted The create-react-app imports restriction outside of src directory and your case/problem are two totally different thing, plus they be tripping so hard. let me give you and idea of that problem and yours.
As we already know CRA creates a SPA single page app. which means that there is only one single html file. everything happens at the index.html
which is located at <project>/public/index.html
. If we compile the code we'll notice something the end bundle might look some like this
build
--static
----js
----css
----media--index.html
--...more hashed crap...
public
src
and by default process.env.PUBLIC_URL
is set to "/"
WHAT?? 🤨 yes look let me show you. there is an old say a picture explains more than 1000 words.
if we look at the image that according to its path it is located at ./src/styles/imageSlack.jpg
or some.
So what if we console.log it.
WHAAAT!! where they do that at ? one thing you can do to test my theory is if you console.log(process.env.PUBLIC_URL)
any where in yow code. now here is the big diference between this and that.
Browsers natively do not know Typescript.
So either you set yow code inside src
and we end happy or
follow the separate of concerns principle and we create an npm package with the shared code and just imported as any other module.
Post a Comment for "How To Import Shared Typescript Code Using Create-react-app (no Eject)?"