Создание библиотеки компонентов React - PullRequest
0 голосов
/ 05 марта 2019

Я создаю модульную библиотеку компонентов с React и TypeScript с Babel 7.

Я хочу, чтобы пользователь моей библиотеки импортировал компоненты с помощью синтаксиса, подобного следующему:

import SomeComponent from "my-awesome-lib/SomeComponent"

SomeComponent - это модуль TSX в пакете my-awesome-lib:

import * as React from "react";

export default function () {
  return <h1>SomeComponent</h1>
}

И main Поле файла package.json компонента my-awesome-::

"main": "src/index.ts"

Я не хочу публиковать скомпилированную версию библиотеки компонентов, потому что я импортирую CSS и другие ресурсы в свои компоненты и ожидаю, что все пользователи моего пакета будут использовать Webpack с некоторыми конкретными настройками.

Теперь мойпроблема заключается в том, что `импорт SomeComponent из" my-awesome-lib / SomeComponent "завершается с ошибкой разбора:

ERROR in ../node_modules/wtf/index.tsx 4:9
Module parse failed: Unexpected token (4:9)
You may need an appropriate loader to handle this file type.
| 
| export default function () {
>   return <h1>WTF</h1>
| }

Кажется, Webpack не загружает и не преобразует файлы TSX в node_modules.

Я использую этот tsconifg.json в корне моего пользовательского приложения (которое импортирует my-awesome-lib):

{
  "compilerOptions": {
    "outDir": "./dist",
    "module": "commonjs",
    "target": "es5",
    "jsx": "react",
    "allowSyntheticDefaultImports": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "downlevelIteration": true,
    "lib": ["es5", "es2015", "dom", "scripthost"], 
    "typeRoots": ["node_modules/@types", "src/@types"],
  },
  "include": ["src/**/*", "node_modules/**/*"],
  "exclude": []
}

И соответствующие конфигурации Webpack:

const tsModules = {
  test: /\.(js|jsx|ts|tsx)$/,
  include: [path.resolve('src')],
  exclude: /node_modules/,
  loader: 'babel-loader'
}

const resolve = {
  alias: {
  },
  modules: [
    'node_modules'
  ],
  extensions: ['.tsx', '.ts', '.js']
}

module.exports = {
   ...
   context: resolve('src'),
   resolve: resolve,
   module: {
     rules: [
       tsModules,
       ...
     ]
   }
}

Как я могу сделать Webpack длязагрузить и преобразовать TSX-модули my-awesome-lib из node_modules?

Ответы [ 3 ]

0 голосов
/ 05 марта 2019

Я нашел create-react-library очень полезно

0 голосов
/ 05 марта 2019

Вы исключаете каталог node_modules (что, как правило, хорошо):

const tsModules = {
  test: /\.(js|jsx|ts|tsx)$/,
  include: [path.resolve('src')],
  exclude: /node_modules/,
  loader: 'babel-loader'
}

Помимо явного исключения папки node_modules, вы также разрешаете только содержимое папки srcдля обработки babel-loader из-за вашей include собственности в tsModules.Итак, эта ошибка:

ОШИБКА в ../node_modules/wtf/index.tsx 4: 9 Ошибка разбора модуля: неожиданный токен (4: 9)

имеет смысл.

Вы все еще можете исключить node_modules, за исключением одной папки, если вы удалите свойство tsModules.include и измените свое регулярное выражение в tsModules.exclude:

const tsModules = {
  // ...
  exclude: /node_modules\/(?!my-awesome-lib)\/*/
  // ...
}

Или вы можете,но я еще не проверял, добавьте my-awesome-lib dir к массиву include:

const tsModules = {
  // ...
  include: [
    path.resolve(__dirname, './src'),
    path.resolve(__dirname, './node-modules/my-awesome-lib')
  ]
  // ...
}

Тогда файлы в вашем каталоге node_modules/my-awesome-lib пройдут babel-loader, который преобразует машинописькод.

Редактировать: Я думаю, что ваша путаница исходит из вашего tsconfig.json файла с "include": ["src/**/*", "node_modules/**/*"],.Бабель передает ваш код, а не машинописный текст.Таким образом, наличие файла tsconfig.json в корневом каталоге может помочь вашей IDE (особенно если вы используете VScode от Microsoft), но не влияет на то, как babel и @babel/preset-typescript преобразуют ваш код.

0 голосов
/ 05 марта 2019

Эта установка предполагает, что вы используете стилевые компоненты и не имеете css / scss.

Здесь важно то, что у вас есть "module": commonJS в вашем tsconfig и libraryTarget: "commonJS" в вашем веб-конфигурационном пакете,Externals говорит веб-пакету не связывать вашу библиотеку с React или React-DOM или стилевыми компонентами, а вместо этого искать те пакеты внутри проекта, в который вы импортируете.

, который вам также понадобитсявозьмите React, Reaction-Dom и Styled-компоненты из ваших зависимостей package.json и поместите их в ваши равноправные зависимости

   const path = require("path");
    const fs = require("fs");
    const TerserPlugin = require('terser-webpack-plugin');
    const appIndex = path.join(__dirname, "../src/main.tsx");
    const appBuild = path.join(__dirname, "../storybook-static");
    const { TsConfigPathsPlugin } = require('awesome-typescript-loader');

    module.exports = {
        context: fs.realpathSync(process.cwd()),
        mode: "production",
        bail: true,
        devtool: false,
        entry: appIndex,
        output: {
            path: appBuild,
            filename: "dist/Components.bundle.js",
            publicPath: "/",
            libraryTarget: "commonjs"
        },
        externals: {
            react: {
                root: 'React',
                commonjs2: 'react',
                commonjs: 'react',
                amd: 'react'
            },
            'react-dom': {
                root: 'ReactDOM',
                commonjs2: 'react-dom',
                commonjs: 'react-dom',
                amd: 'react-dom'
            },
            "styled-components": {
                root: "styled-components",
                commonjs2: "styled-components",
                commonjs: "styled-components",
                amd: "styled-components"
            }
        },
        optimization: {
            minimizer: [
                new TerserPlugin({
                    terserOptions: {
                        parse: {
                            ecma: 8,
                        },
                        compress: {
                            ecma: 5,
                            warnings: false,
                            comparisons: false,
                            inline: 2,
                        },
                        mangle: {
                            safari10: true,
                        },
                        output: {
                            ecma: 5,
                            comments: false,
                            ascii_only: true,
                        },
                    },
                    parallel: true,
                    cache: true,
                    sourceMap: false,
                })
            ],
        },
        resolve: {
            extensions: [".web.js", ".mjs", ".js", ".json", ".web.jsx", ".jsx", ".ts", ".tsx"],
            alias: {
                "react-native": "react-native-web",
            },
        },
        module: {
            strictExportPresence: true,
            rules: [
                { parser: { requireEnsure: false } },
                {
                    test: /\.(ts|tsx)$/,
                    loader: require.resolve("tslint-loader"),
                    enforce: "pre",
                },
                {
                    oneOf: [
                        {
                            test: /\.(tsx?)$/,
                            loader: require.resolve('awesome-typescript-loader'),
                            options: {
                                configFileName: 'tsconfig.prod.json'
                            }
                        },
                    ],
                },
            ],
        },
        plugins: [
            new TsConfigPathsPlugin()
        ],
        node: {
            dgram: "empty",
            fs: "empty",
            net: "empty",
            tls: "empty",
            child_process: "empty",
        },
        performance: false,
    };

Примечание: важно, чтобы вы указали точку в вашем приложении какзапись, содержащая ТОЛЬКО компоненты, которые вы хотите экспортировать.

IE Для меня это Main.tsx, а внутри Main.tsx это выглядит так.

export { Checkbox } from "./components/Checkbox/Checkbox";
export { ColorUtils } from "./utils/color/color";
export { DataTable } from "./components/DataTable/DataTable";
export { DatePicker } from "./components/DateTimePicker/DatePicker/DatePicker";
export { DateTimePicker } from "./components/DateTimePicker/DateTimePicker/DateTimePicker";
export { Disclosure } from "./components/Disclosure/Disclosure";

Это означает, что webpack не будетсвязать вещи, которые вы не собираетесь экспортировать.Чтобы проверить, что вы работаете в связке, попробуйте импортировать что-то с синтаксисом require из комплекта, чтобы обойти типизацию и поверните allowJS true в tsconfig.

что-то вроде const Button = require ("../ path / to / js/bundle").Button console.log (кнопка);

...