This question: "Cannot find module" error when using TypeScript 3 Project References was somewhat helpful.
So was this one: Project references in TypeScript 3 with separate `outDir`
But I am still having trouble getting this working efficiently with VSCode and React.
Project structure:
- client/src
- common
- server/src
common tsconfig:
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"rootDir": ".",
"composite": true,
"outDir": "build"
},
"references": []
}
client tsconfig:
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
},
"include": [
"src",
],
"references": [
{
"path": "../common"
}
]
}
server tsconfig
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"esnext"
],
"module": "commonjs",
"sourceMap": true,
"outDir": "build",
"allowJs": true,
"moduleResolution": "node",
"strict": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"baseUrl": ".",
},
"include": [
"src/**/*"
],
"references": [
{
"path": "../common"
}
]
}
I am using create-react-app in client. This has caused compilation issues. I believe I have solved this with create-app-rewired and customize-cra using this for config-overrides.js
const { override, removeModuleScopePlugin, getBabelLoader } = require("customize-cra");
const path = require("path");
const addCommon = (config) => {
const loader = getBabelLoader(config, false);
const commonPath = path.normalize(path.join(process.cwd(), "../common")).replace(/\\/g, "\\");
loader.include = [loader.include, commonPath];
return config;
};
module.exports = override(
addCommon,
removeModuleScopePlugin(),
);
In common, I have created a file index.ts which exports code from every file.
export * from "./messages/toServer/AuthMessage";
for example.
On the front-end and back-end, I can import code (to use) with a handwritten import statement:
import { AuthMessage } from "../../../common/build/messages/toServer/AuthMessage";
VSCode doesn't give any suggestions, but it accepts the import statement assuming the code is built.
I run tsc -b -w in common. This seems to work with manual imports.
It is possible to have:
- IntelliSense / auto-import When writing types such as
AuthMessage - Usable code that is imported. I have seen examples where types are supported, but code is not generated from common. Untested, but I imagine this works well for interfaces in a common directory
- Usability with React. Some relevant jabber: https://github.com/facebook/create-react-app/issues/6799. ts-loader supports project references, but I am unsure the status of babel-loader, which to the best of my knowledge, is the loader used by CRA. I got a partial solution with the code I provided above.
Guidance here: https://www.typescriptlang.org/docs/handbook/project-references.html#guidance is very confusing. Any help with an explanation here is appreciated.
Other solutions?
- I don't want to publish and update a private NPM module.
- Using a program such as dsynchronize: http://dimio.altervista.org/eng/ might be easier where code is duplicated across two projects, but included in the
srcof both projects. It's not clean, and I can see some disasters with refactoring and an IDE attempting to re-negotiate import paths if the program is running...
Any help is appreciated.