svg - ทำไม SVGR ถึงไม่สร้างไฟล์ประกาศ TypeScript ในการตั้งค่า esbuild ของฉัน?
ฉันกำลังสร้างไลบรารีไอคอน SVG ใน TypeScript จนถึงตอนนี้ SVGR ทำงานได้ยอดเยี่ยม แต่สิ่งสุดท้ายที่ฉันต้องการคือประเภทที่สร้างขึ้นเพื่อให้สามารถส่ง title และ ref ไปยังคอมโพเนนต์ที่รวมอยู่ได้
การสืบพันธุ์
ฉันไม่แน่ใจว่าทุกอย่างที่อาจมีประโยชน์ในการดูคืออะไร ดังนั้นฉันจะรวมรีโปและตัวอย่างโค้ดบางส่วน แต่ด้วยการตั้งค่าต่อไปนี้ svgr กำลังสร้างคอมโพเนนต์จากการนำเข้า SVG แต่ไม่มีการสร้างประเภทใด ๆ เป็นผลให้ทุกครั้งที่ฉันพยายามใช้ไอคอนจากแพ็กเกจนี้ ฉันจะได้รับคำเตือนว่าค้นหาไฟล์ประกาศสำหรับมันไม่พบ
ที่เก็บ POC: https://github.com/yuschick/icon-demo
src/index.ts
export { default as TestIcon } from "./svg/test.svg";
export { default as ArrowThinLeft } from './svg/arrow-thin-left.svg';
package.json
{
"module": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"scripts": {
"build": "node esbuild.config.js",
},
"devDependencies": {
"esbuild": "^0.14.39",
"esbuild-plugin-svgr": "^1.0.1",
"typescript": "^4.6.3"
}
}
esbuild.config.js
import esbuild from "esbuild";
import svgr from "esbuild-plugin-svgr";
esbuild.build({
bundle: true,
entryPoints: ["src/index.ts"],
external: ["react"],
format: "esm",
// minify: true,
outfile: "dist/index.js",
plugins: [svgr({ titleProp: true, ref: true, expandProps: false, typescript: true })],
})
.catch(() => process.exit(1));
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"alwaysStrict": true,
"baseUrl": "src",
"checkJs": true,
"declaration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"outDir": "dist",
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "esnext"
},
"include": ["src", "global.d.ts"]
}
global.d.ts
declare module '*.svg' {
const content: string;
export default content;
}
พฤติกรรมที่คาดหวัง
โดยการส่งค่า typescript: true เข้าไปในตัวเลือกของ svgr ผมคาดหวังว่าจะมีการสร้างไฟล์ index.d.tsx ขึ้นตามคอมโพเนนต์ที่สร้างขึ้น
ตามเอกสารของ SVGR:
สร้างไฟล์ .tsx พร้อมการพิมพ์ประเภทของ TypeScript
หมายเหตุ: ในขณะที่ฉันกำลังใช้ SVGR ร่วมกับ ESBuild ปัญหาเดียวกันก็เกิดขึ้นเมื่อพยายามใช้กับ Rollup ด้วยเช่นกัน
คำตอบ #1
ปัญหา
โดยการส่งค่า
typescript: trueเข้าไปในตัวเลือกของsvgrผมคาดหวังว่าจะมีการสร้างไฟล์index.d.tsxขึ้นตามคอมโพเนนต์ที่สร้างขึ้น
ความคาดหวังนี้ไม่ถูกต้อง SVGR จะสร้างไฟล์ .tsx เท่านั้นหากคุณระบุตัวเลือก typescript และไม่ใช่ไฟล์ .d.ts จากเอกสารประกอบ (ซึ่งคุณก็พบแล้วเช่นกัน):
TypeScript
สร้างไฟล์
.tsxพร้อมกับการกำหนดชนิดข้อมูล TypeScript
อย่างไรก็ตาม แม้จะระบุทางเลือกนี้แล้ว SVGR ก็จะไม่สร้างไฟล์ .tsx เพราะคุณกำลังใช้สิ่งนี้ภายในปลั๊กอิน esbuild esbuild-plugin-svgr ในพื้นหลังจะใช้ฟังก์ชัน transform จาก @svgr/core (ดู esbuild-plugin-svgr/index.js:L4) ฟังก์ชัน transform จะเปลี่ยน SVG เป็น JSX หรือ TSX เท่านั้น แต่จะไม่เขียนผลลัพธ์ @svgr/cli จัดการเขียนผลลัพธ์ไปยังไฟล์ เช่น ดู @svgr/cli/src/dirCommand.ts.
วิธีแก้ปัญหา
ฉันคิดว่าคุณมีตัวเลือกสองอย่าง:
แยก SVGR ออกจาก esbuild จากนั้นสร้างไฟล์ .d.ts
ในคำอื่น ๆ ให้หยุดใช้ esbuild-plugin-svgr และใช้ @svgr/cli แทน จากนั้นคุณจะต้องรัน SVGR ก่อน esbuild; ไม่ว่าจะทำด้วยตนเอง, เชื่อมต่อคำสั่งในสคริปต์ หรือใช้ pre-script hook ของ npm หลังจากนั้นคุณจะต้องสร้าง .d.ts file แต่เมื่อดูที่ esbuild#95 ดูเหมือนไม่รองรับโดยตรง คุณอาจต้องการสำรวจข้อเสนอแนะที่ระบุไว้ที่นั่นรวมถึง:
- การใช้คอมไพเลอร์ TypeScript เพื่อสร้างไฟล์ประกาศ (
tsc --emitDeclarationOnly) - การใช้ปลั๊กอิน เช่น
esbuild-plugin-d.ts
โซ่การสร้างของคุณอาจดูเหมือนแบบนี้ในตอนท้าย:
- สร้างไฟล์
.tsxจาก SVG โดยใช้@svgr/cli - รวมแพ็กเกจโดยใช้ esbuild
- สร้างไฟล์
.d.tsได้ ไม่ว่าจะเป็นขั้นตอนแยกโดยใช้tscหรือผสานกับขั้นตอนข้างต้นโดยใช้ปลั๊กอินของ esbuild
สร้างไฟล์ .d.ts จากชุดไฟล์ JavaScript ของคุณ
ถ้าด้วยเหตุผลบางอย่างคุณต้องการเก็บการตั้งค่าการสร้างปัจจุบันของคุณจริงๆ คุณสามารถสร้างไฟล์ .d.ts จากไฟล์ JavaScript bundle ของคุณด้วย tsc dist/index.js --declaration --allowJs --emitDeclarationOnly (ดูเอกสาร TypeScript) ข้อควรระวังคือ TypeScript อาจไม่สามารถสรุปประเภททั้งหมดได้ ดังนั้นคุณอาจมีไฟล์ประกาศประเภทที่ไม่สมบูรณ์
คำตอบ #2
เคยมีปัญาคล้ายกันกับ svgr ตอนพยายามรวมประเภทของ TypeScript ด้วยปลั๊กอิน rollup-plugin-dts
แก้ไขโดยการสร้างไฟล์ icon.d.ts ไฟล์เดียว:
import { SVGProps } from 'react';
declare const ReactComponent: (props: SVGProps<SVGSVGElement>) => JSX.Element;
export { ReactComponent };
และจากนั้นใช้ปลั๊กอิน alias ดังนี้:
import alias from '@rollup/plugin-alias';
...
plugins: [
alias({
entries: [
{
find: /^.*\.svg$/,
replacement: 'src/types/icon.d.ts',
},
],
}),
dts(),
],
