在 monorepo 代码共享中创建 React App + Typescript

Bra*_*onM 11 typescript create-react-app monorepo

我目前有一个 monorepo,其中有两个 (+) 使用纱线工作区的包:

root
  /packages
    /common
    /web
  ...

root/package.json

  ...
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "**"
    ],
  },
Run Code Online (Sandbox Code Playgroud)

web是一个带有 typescript 模板的普通 create-react-app。我有一些TS的代码common我想在使用web,但似乎CRA不支持编译的代码之外src,给我一个错误,当我尝试进口来自commonweb

../common/state/user/actions.ts 4:66
Module parse failed: Unexpected token (4:66)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import { UpdateUserParams } from './reducer';
| 
> export const login = createAction('USER/LOGIN')<{ username: string; password: string }>();
Run Code Online (Sandbox Code Playgroud)

因此,我在弹出后按照此注释中的说明将路径包含在 中/common,但似乎babel-loader加载了文件,但现在不是从打字稿编译它们:

./common/state/user/actions.ts
SyntaxError: /Users/brandon/Code/apps/packages/common/state/user/actions.ts: Unexpected token, expected "," (4:66)

  2 | import { UpdateUserParams } from './reducer';
  3 | 
> 4 | export const login = createAction('USER/LOGIN')<{ username: string; password: string }>();
    |                                                                   ^
  5 | 
  6 | export const logout = createAction('USER/LOGOUT')();
Run Code Online (Sandbox Code Playgroud)

如何让 webpack / babel 正确编译共同的代码?我知道我可以common编译它自己的代码,但我宁愿不必每次要进行更改时都重新编译共同的代码。让每个应用程序自己做是理想的。

Webpack.config.js:

root
  /packages
    /common
    /web
  ...

root/package.json

  ...
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "**"
    ],
  },
Run Code Online (Sandbox Code Playgroud)

路径.js

../common/state/user/actions.ts 4:66
Module parse failed: Unexpected token (4:66)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import { UpdateUserParams } from './reducer';
| 
> export const login = createAction('USER/LOGIN')<{ username: string; password: string }>();
Run Code Online (Sandbox Code Playgroud)

配置:

// base in root
{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": false,
    "esModuleInterop": true,
    "downlevelIteration": true,
    "lib": ["esnext", "dom"],
    "noUnusedLocals": true,
    "skipLibCheck": true,
    "strict": true,
    "target": "esnext",
    "noEmit": true,
    "moduleResolution": "node",
    "resolveJsonModule": true
  }
}

//packages/web/tsconfig.json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "jsx": "react",
    "baseUrl": "src",
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "isolatedModules": true,
    "typeRoots": ["./node_modules/@types"],
  },
  "include": [
    "src"
  ]
}

Run Code Online (Sandbox Code Playgroud)

Jos*_*e A 8

我想加 2 美分,因为我遇到了这个问题。我最初确实尝试编译共享组件文件夹,但这很糟糕......花了太长时间。

在这里,我向您展示如何使用react-scriptsv4 执行此操作并且TypeScript 无需弹出(我们需要使用 craco,否则这是不可能的)。

这是一步一步的。

  1. 在本例中,将共享组件文件夹common指向主 .tsx 或 .ts 文件。
  2. 创建一个craco.config.js加载 babel-loader 并转译它的文件。需要在 common 尝试加载的每个单独应用程序中复制此文件。

  1. 指向您的共享组件文件夹。打开你commonpackage.json(不是根目录!):

步骤1

检查您是否具有要从中导入它的名称(我在图片中使用的是我的实际应用程序的示例),将其设置privatetrue、 、sourcemain条目module,让它们指向您的条目文件。就我而言,这是index.ts

{
  "name": "common",
  "version": "0.1.0",
  "private": true,
  "source": "index.ts",
  "main": "./index.ts",
  "module": "./index.ts",
// The common's package.json content
...
}
Run Code Online (Sandbox Code Playgroud)
  1. 在您想要从中引用包的每个其他存储库common中,创建一个craco.config.js文件,并包含以下内容:
const path = require('path');
/**
 * ALlows us to edit create-react-app configuration
 * without ejecting.
 *
 *
 */
const { getLoader, loaderByName } = require('@craco/craco');
// Replace `components` with your folder's structure.
// Again, Here I'm showcasing my current project.
const absolutePath = path.join(__dirname, '../components');
/**
 * This is extremely important if you're using a CI/CD to build and deploy 
 * your code!!! Read!
 * 
 * If you create a package with a namespace, such as name is @schon/components, you need
 * to add what I've commented down below. Otherwise Yarn will fail in CI/CD environments!!
 */
// const schonComponents = path.join(
//   __dirname,
//   './node_modules/@schon/components',
// );

module.exports = {
  webpack: {
    configure: (webpackConfig, { env, paths }) => {
      // https://medium.com/frontend-digest/using-create-react-app-in-a-monorepo-a4e6f25be7aa
      const { isFound, match } = getLoader(
        webpackConfig,
        loaderByName('babel-loader'),
      );
      if (isFound) {
        const include = Array.isArray(match.loader.include)
          ? match.loader.include
          : [match.loader.include];
        // match.loader.include = include.concat(absolutePath, schonComponents);
        match.loader.include = include.concat(absolutePath);
      }
      return {
        ...webpackConfig,
        /**
         * Optionally, other webpack configuration details.
         */
        // optimization: {
        //   splitChunks: {
        //   },
        // },
      };
    },
  },
  
};
Run Code Online (Sandbox Code Playgroud)

第2步


Bra*_*onM 3

最终让它发挥作用。要使 TS 正常工作,['@babel/preset-typescript', { allExtensions: true, isTSX: true }], ['@babel/preset-react'],除了链接的解决方案之外,您还需要显式添加预设:到您的加载程序:

            // Process application JS with Babel.
            // The preset includes JSX, Flow, TypeScript, and some ESnext features.
            {
              test: /\.(js|mjs|jsx|ts|tsx)$/,
              include: [paths.appSrc, ...paths.appLernaModules],
              loader: require.resolve('babel-loader'),
              options: {
                customize: require.resolve('babel-preset-react-app/webpack-overrides'),
                presets: [// ADD THESE
                  ['@babel/preset-typescript', { allExtensions: true, isTSX: true }],
                  ['@babel/preset-react'],
                ],
                plugins: [
                  [
                    require.resolve('babel-plugin-named-asset-import'),
                    {
                      loaderMap: {
                        svg: {
                          ReactComponent: '@svgr/webpack?-svgo,+titleProp,+ref![path]',
                        },
                      },
                    },
                  ],
                ],
                // This is a feature of `babel-loader` for webpack (not Babel itself).
                // It enables caching results in ./node_modules/.cache/babel-loader/
                // directory for faster rebuilds.
                cacheDirectory: true,
                // See #6846 for context on why cacheCompression is disabled
                cacheCompression: false,
                compact: isEnvProduction,
              },
            },

Run Code Online (Sandbox Code Playgroud)

  • @BrookJordan,您可以使用 craco 或类似的方法进行覆盖,而无需弹出 https://github.com/gsoft-inc/craco/tree/master/packages/craco (2认同)