簡體   English   中英

如何使用 create-react-app(無彈出)導入共享 typescript 代碼?

[英]How to import shared typescript code using create-react-app (no eject)?

我試圖在非彈出模式下在 create-react-app 中實現 TypeScript 代碼共享,但我遇到了一個臭名昭著的限制,即不允許在src之外導入:

You attempted to import../../common/src/lib.ts which falls outside of the project src/ directory. [...]

對於非 TypeScript 案例,這里已詢問並回答了此問題,但我無法獲得與 TypeScript 一起使用的任何解決方案。 具體而言,所提出的解決方案的問題是:

  • ts-config.json中設置baseDir :此處 create-react-app 抱怨:您的項目的baseUrl只能設置為srcnode_modules Create React App 目前不支持其他值。

  • 基於 react-app-rewired 的方法:更有希望。 禁用ModuleScopePlugin使我擺脫了“嘗試在 src 外部導入”錯誤,但現在的問題是 typescript 文件的加載器無法播放:

    在此處輸入圖像描述

    我已經驗證.ts本身沒問題:復制到./src並從那里導入它工作正常。

    我還在ts-config.jsonincludes列表中添加了../../common/src文件夾。

    我的猜測是,不知何故,webpack 加載程序配置有一條規則阻止 TypeScript 加載程序轉譯與其預期路徑模式不匹配的文件。 如何使用 react-app-rewired 解決這個問題?

  • 符號鏈接源也不起作用——同樣的問題。 可能是因為 webpack 在內部解析了符號鏈接,並在正常加載器規則不適用的路徑中看到了文件。

  • 基於彈出的解決方案:我現在不想彈出,但我試過了,我基本上又遇到了同樣的問題。

我還發現了其他聽起來相關但沒有回答問題的問題:


在 mono 存儲庫中重新使用 TypeScript 類型似乎是一種相當合理的模式。 我是否遺漏了什么,或者為什么 create-react-app 讓這變得如此困難?


重現:我的代碼基本上是 100% 你從中得到的

npx create-react-app my-app --template typescript

添加了一個到外部的導入。

您可以使用craco (create-react-app 配置覆蓋)覆蓋 webpack 配置(抽象為 CRA 的一部分)而不彈出。
此外,您可以使用ts-loader直接在外部項目中引用未轉譯的 ts 代碼(例如,如果您想引用/使用共享代碼/lib 作為 mono-repo 的一部分)。

假設您的 CRA 應用程序位於client目錄中,您的項目結構如下所示:

client/
|--src/
|--package.json
shared/
|--package.json
|--(ts files)
package.json

cd client
yarn add -D @craco/craco ts-loader
  1. client/ (CRA) 目錄中創建一個craco.config.js文件
  2. 確保craco.config.js具有以下內容
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;
    }
  }
};
  1. craco替換client/package.json中的react-scripts命令
/* 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"
}

更新:由於 react-app-rewired 只是被動維護並且不支持 CRA 版本 2+(在撰寫本文時我們是三個主要版本),我不再推薦這種方法。


經過更多小時的試驗和閱讀 GitHub 問題后,我終於有了一個可行的解決方案。 非常感謝 BirukDmitry,他在 GitHub 上發表了這篇非常有幫助的帖子 分步指南:

  1. 安裝 react-app-rewired 和 customize-cra

     npm i react-app-rewired customize-cra --save-dev
  2. 使用最小的config-overrides.js配置 react-app-rewird,如下所示:

     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) ]) );

    設置 (1) 類似於一般繞過 import-outside-src 限制所需的設置(請參閱鏈接問題)。

    設置 (2) 對於其他路徑也啟用 babel-transpilation(因此,包括我認為的 TS 類型剝離)至關重要。 這是您必須添加要從中導入的路徑的地方。

  3. tsconfig.json不需要任何調整。

  4. 使用相對路徑導入,例如import * as mymodule from '../../common/src/mymodule'

craco 或 rewired create-react-app的別名解決方案是react-app-alias系統為: cracoreact-app- rewired , customize-cra

根據上述系統的文檔替換package.json中的react-scripts並配置下一個:

react-app-rewired

// config-overrides.js
const {aliasWebpack, aliasJest} = require('react-app-alias')

const options = {} // default is empty for most cases

module.exports = aliasWebpack(options)
module.exports.jest = aliasJest(options)

克拉科

// craco.config.js
const {CracoAliasPlugin} = require('react-app-alias')

module.exports = {
  plugins: [
    {
      plugin: CracoAliasPlugin,
      options: {}
    }
  ]
}

全部

在 json 中配置別名,如下所示:

// tsconfig.paths.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "example/*": ["example/src/*"],
      "@library/*": ["library/src/*"]
    }
  }
}

並將此文件添加到主 typescript 配置文件的extends部分:

// tsconfig.json
{
  "extends": "./tsconfig.paths.json",
  // ...
}

@bluenote10 解決方案成功了!

第 2 步中只有一個問題阻止 Babel 從 ../../common/src 轉換 ts 文件 那是 @bluenote10 代碼的修改版本(最終對我有用)


  1. 安裝 react-app-rewired 和 customize-cra

     npm i react-app-rewired customize-cra --save-dev
  2. 使用最小的config-overrides.js配置 react-app-rewird,如下所示:

     const { removeModuleScopePlugin, override, babelInclude } = require("customize-cra"); const path = require("path"); module.exports = function (config, env) { return Object.assign( // We need Object.assign() to not to loose initial config config, override( removeModuleScopePlugin(), //1 babelInclude([ path.resolve('src'), path.resolve('../common/src'), //2 ]) )(config, env) ) }

    設置 (1) 類似於一般繞過 import-outside-src 限制所需的設置(請參閱鏈接問題)。

    設置 (2) 對於其他路徑也啟用 babel-transpilation(因此,包括我認為的 TS 類型剝離)至關重要。 這是您必須添加要從中導入的路徑的地方。

  3. tsconfig.json不需要任何調整。

  4. 使用相對路徑導入,例如import * as mymodule from '../../common/src/mymodule'

問題../../common/src/mymodule住在哪里? 是另一個項目嗎? 如果它是另一個項目,為什么不鏈接他們

  • 在公共代碼項目中運行npm link

  • 在將使用公共代碼的項目中: npm link common-project

如果沒有兩個不同的項目。 為什么它必須在 src 之外?

您發布的鏈接src 目錄之外的 create-react-app 導入限制和您的案例/問題是兩個完全不同的東西,而且它們非常困難。 讓我告訴你這個問題和你的想法。

正如我們已經知道的那樣,CRA 創建了一個 SPA 單頁應用程序。 這意味着只有一個 html 文件。 一切都發生在位於<project>/public/index.htmlindex.html上。 如果我們編譯代碼,我們會注意到最終包可能看起來像這樣

build
--static
----js
----css
----media
--index.html
--...more hashed crap...
public
src

並且默認process.env.PUBLIC_URL設置為“/”什么? 是的,讓我告訴你。 有一句老話說一張圖解釋1000多字。 在此處輸入圖像描述

如果我們查看根據其路徑位於./src/styles/imageSlack.jpg或其他位置的圖像。 那么如果我們 console.log 它呢。

在此處輸入圖像描述

什么?! 他們在哪里做的? 你可以做的一件事來測試我的理論是如果你console.log(process.env.PUBLIC_URL)在你的代碼中的任何地方。 現在這是這個和那個之間的巨大差異。

瀏覽器本身不知道 Typescript。

因此,要么您在src中設置 yow 代碼,我們最終滿意,要么遵循關注點分離原則,我們使用共享代碼創建 npm package 並作為任何其他模塊導入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM