Я занимаюсь извлечением основных компонентов нашего приложения React в отдельную библиотеку компонентов для использования в других клиентских приложениях. Эти компоненты используют значки SVG, которые уже работают в оригинальном приложении с помощью babel-loader.
Однако, поскольку компоненты написаны на Typescript, то, насколько я понял, мне нужно ts-loader
для корректной работы библиотеки, хотя проверить это я не смог, т.к. не могу даже скомпилировать библиотеку. Чтобы иметь возможность экспортировать SVG, я дополнительно включил babel-loader
с babel-plugin-named-asset-import
.
Это моя структура проекта:
.
├── config
│ └── webpack.config.js
├── global.d.ts
├── index.ts
├── package.json
├── package-lock.json
├── src
│ ├── assets
│ │ └── icons
│ │ ├── index.d.ts
│ │ ├── index.ts
│ │ └── upload.svg
│ ├── bar
│ │ └── index.ts
│ └── foo
│ ├── index.ts
│ └── Stuff.ts
└── tsconfig.json
веб-пакет.config.json:
const path = require("path");
module.exports = {
entry: "./index.ts",
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: "ts-loader",
},
exclude: /node_modules/,
},
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
loader: require.resolve("babel-loader"),
options: {
customize: require.resolve(
"babel-preset-react-app/webpack-overrides"
),
plugins: [
[
require.resolve("babel-plugin-named-asset-import"),
{
loaderMap: {
svg: {
ReactComponent: "@svgr/webpack?-svgo,+ref![path]",
},
},
},
],
],
},
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
};
tsconfig.json:
{
"include": ["./global.d.ts", "./index.ts", "src/**/*"],
"compilerOptions": {
"allowJs": false,
"jsx": "react",
"esModuleInterop": true,
"downlevelIteration": true,
"declaration": true,
"noEmit": false,
"outDir": "dist",
"moduleResolution": "node",
"module": "commonjs",
"target": "es5",
"lib": ["es5", "es6", "es7", "es2017", "dom"],
"sourceMap": true,
"typeRoots": ["./node_modules/@types", "./@types"],
"resolveJsonModule": true
}
}
global.d.ts — я выяснил, что часть declare module
здесь точно не действует, я получаю тот же результат и с ней, и без нее.
import 'jest-dom/extend-expect';
declare module '*.svg' {
const content: string;
export default content;
}
./src/assets/icons/index.ts должен отвечать за экспорт всех доступных значков в другие файлы для их импорта.
export { ReactComponent as Add } from "./add.svg";
./src/demo/index.ts
содержит код, который «использует» этот SVG:
import { Add } from "../assets/icons";
export default {
Add,
};
index.ts
в корневом каталоге содержит тот же контент, чтобы продемонстрировать несоответствие моей проблемы:
import { Add } from "../assets/icons";
export default {
Add,
};
Пока все хорошо, подумал я, поэтому я запустил webpack с npx webpack --config ./config/webpack.config.js
только для того, чтобы все это вышло из строя с этим сообщением об ошибке:
ERROR in C:\work\tstest\src\demo\index.ts
[tsl] ERROR in C:\work\tstest\src\demo\index.ts(1,21)
TS2306: File 'C:/work/tstest/src/assets/icons/index.ts' is not a module.
Это оставляет меня совершенно сбитым с толку несколькими вопросами:
- Как рассматриваемый файл не является модулем? Было бы здорово узнать, что мешает ts-loader правильно его распознать.
./src/demo/index.ts
и./index.ts
на 100% идентичны по содержанию. Тем не менее, компиляция работает для одного файла, но не для другого. Почему так и где такое поведение задокументировано?- Что я делаю не так?
- Как это правильнее осуществить?
Я предполагаю, что это происходит потому, что после того, как babel-loader сделал свое дело, ./src/assets/icons/index.ts
выглядит не так, как хочет ts-loader, но это не совсем объясняет, как два файла с одинаковым содержимым обрабатываются по-разному.