![](/img/trans.png)
[英]How to use jsx files in an app created by create-react-app (without run “npm run eject”)?
[英]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
只能設置為src
或node_modules
。 Create React App 目前不支持其他值。
基於 react-app-rewired 的方法:更有希望。 禁用ModuleScopePlugin
使我擺脫了“嘗試在 src 外部導入”錯誤,但現在的問題是 typescript 文件的加載器無法播放:
我已經驗證.ts
本身沒問題:復制到./src
並從那里導入它工作正常。
我還在ts-config.json
的includes
列表中添加了../../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
client/
(CRA) 目錄中創建一個craco.config.js
文件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;
}
}
};
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 上發表了這篇非常有幫助的帖子。 分步指南:
安裝 react-app-rewired 和 customize-cra
npm i react-app-rewired customize-cra --save-dev
使用最小的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 類型剝離)至關重要。 這是您必須添加要從中導入的路徑的地方。
tsconfig.json
不需要任何調整。
使用相對路徑導入,例如import * as mymodule from '../../common/src/mymodule'
。
craco 或 rewired create-react-app的別名解決方案是react-app-alias系統為: craco , react-app- rewired , customize-cra
根據上述系統的文檔替換package.json
中的react-scripts
並配置下一個:
// 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 代碼的修改版本(最終對我有用)
安裝 react-app-rewired 和 customize-cra
npm i react-app-rewired customize-cra --save-dev
使用最小的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 類型剝離)至關重要。 這是您必須添加要從中導入的路徑的地方。
tsconfig.json
不需要任何調整。
使用相對路徑導入,例如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.html
的index.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.