Как лучше всего настроить библиотеку компонентов React с помощью Webpack, typescript, css-модулей и SASS

Я настраиваю библиотеку компонентов React для повторного использования в других наших проектах. Я хочу использовать это:

  • Машинопись для компонентов
  • Модули css
  • Sass
  • Webpack для бандла

Итак, это моя конфигурация веб-пакета:

    const childProcess = require('child_process');

const path = require('path');
const url = require('url');

const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const loadersConf = require('./webpack.loaders');

const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env

const targetIsRun = NPM_TARGET === 'run';
const targetIsTest = NPM_TARGET === 'test';
const targetIsStats = NPM_TARGET === 'stats';
const targetIsDevServer = NPM_TARGET === 'dev-server';

const DEV = targetIsRun || targetIsStats || targetIsDevServer;

const STANDARD_EXCLUDE = [
    path.join(__dirname, 'node_modules'),
];

// These files will be imported in every sass file
const sassResourcesPaths = [
    path.resolve(__dirname, 'src/styles/abstracts/_variables.sass'),
    path.resolve(__dirname, 'src/styles/abstracts/_mixins.sass'),
];

const config = {
    module: {
        rules: loadersConf,
    },
    resolve: {
        modules: [
            'node_modules',
            path.resolve(__dirname),
        ],
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.css', '.scss'],
    },
    performance: {
        hints: 'warning',
    },
    target: 'web',
    plugins: [
        new webpack.DefinePlugin({
            COMMIT_HASH: JSON.stringify(childProcess.execSync('git rev-parse HEAD || echo dev').toString()),
        }),
        new MiniCssExtractPlugin({
            filename: '[name].[contentHash].css',
            chunkFilename: '[name].[contentHash].css',
        }),
    ],
};

if (DEV) {
    config.mode = 'development';
    config.devtool = 'source-map';
}


const env = {};
if (DEV) {
} else {
    env.NODE_ENV = JSON.stringify('production');
}

config.plugins.push(new webpack.DefinePlugin({
    'process.env': env,
}));

module.exports = config;

А это загрузчики для webpack:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const STANDARD_EXCLUDE = [
    path.join(__dirname, 'node_modules'),
];

const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env
const targetIsRun = NPM_TARGET === 'run';
const targetIsTest = NPM_TARGET === 'test';
const targetIsStats = NPM_TARGET === 'stats';
const targetIsDevServer = NPM_TARGET === 'dev-server';

const DEV = targetIsRun || targetIsStats || targetIsDevServer;

// noinspection WebpackConfigHighlighting
module.exports = [
    {
        test: /\.(js|jsx|ts|tsx)?$/,
        exclude: STANDARD_EXCLUDE,
        use: {
            loader: 'babel-loader',
            options: {
                cacheDirectory: true,

                // Babel configuration is in .babelrc because jest requires it to be there.
            },
        },
    },
    {
        type: 'javascript/auto',
        test: /\.json$/,
        include: [
            path.resolve(__dirname, 'i18n'),
        ],
        exclude: [/en\.json$/],
        use: [
            {
                loader: 'file-loader?name=i18n/[name].[hash].[ext]',
            },
        ],
    },
    // ==========
    // = Styles =
    // ==========
    // Global CSS (from node_modules)
    // ==============================
    {
        test: /\.css/,
        include: path.resolve(__dirname, "node_modules"),
        use: [
            MiniCssExtractPlugin.loader,
            {
                loader: "style-loader"
            },
            {
                loader: 'css-loader'
            }
        ]
    },
    {
        test: /\.(sc|sa|c)ss$/,
        exclude: /\.st.css$/, //This must appear before the "oneOf" property
        use: [
            MiniCssExtractPlugin.loader,
            'style-loader',
            'css-modules-typescript-loader',
            {
                loader: 'css-loader',
                options: {
                    importLoaders: 2,
                    modules: true,
                    camelCase: "dashes",
                    localIdentName: DEV
                        ? '[name]__[local]___[hash:base64:5]'
                        : '_[hash:base64:5]',
                },
            },
            {
                loader: "postcss-loader",
                options: {
                    sourceMap: "inline",
                    extract: true,
                }
            },
            "sass-loader",
        ],
    },
    {
        test: /\.(png|eot|tiff|svg|woff2|woff|ttf|gif|mp3|jpg)$/,
        use: [
            {
                loader: 'file-loader',
                options: {
                    name: 'files/[hash].[ext]',
                },
            },
            {
                loader: 'image-webpack-loader',
                options: {},
            },
        ],
    },
];

Конфигурация Babel:

const config = {
    presets: [
        ['@babel/preset-env', {
            targets: {
                chrome: 66,
                firefox: 60,
                edge: 42,
                safari: 12,
            },
            modules: false,
            corejs: 3,
            useBuiltIns: 'usage',
            shippedProposals: true,
        }],
        ['@babel/preset-react', {
            useBuiltIns: true,
        }],
        ['@babel/typescript', {
            allExtensions: true,
            isTSX: true,
        }],
    ],
    plugins: [
        '@babel/plugin-transform-runtime',
        '@babel/plugin-syntax-dynamic-import',
        '@babel/proposal-class-properties',
        '@babel/proposal-object-rest-spread',
        '@babel/plugin-proposal-optional-chaining',
        ['module-resolver', {
            root: ['./src', './test'],
        }],
    ],
};

// Jest needs module transformation
config.env = {
    test: {
        presets: config.presets,
        plugins: config.plugins,
    },
};
config.env.test.presets[0][1].modules = 'auto';

module.exports = config;

Это демонстрационный компонент этой библиотеки:

import React from 'react';

const styles = require('./style.scss');

type Props = {
    children?: React.ReactNode;
    openLeft?: boolean;
    openUp?: boolean;
    id?: string;
    ariaLabel: string;
    customStyles?: object;
}

export default class Button extends React.PureComponent<Props> {
    public render() {
        return (
            <button className={styles.test}>
                {this.props.children}
            </button>
        );
    }
}

Итак, это команда разработки сборки:

"build": "cross-env NODE_ENV=production webpack --display-error-details --verbose",
    "run": "webpack --progress --watch",

когда я использую эту библиотеку:

import ExampleComponent from 'mylibrary';

Когда я запускаю команду BUILD или RUN, создается javascript, но не SCSS. Итак, в моем другом проекте сборка выдает ошибку:

can not find module './style.scss'

Эта ошибка возникает в ExampleComponent

Подскажите, пожалуйста, как решить. Спасибо большое!


person Enesy    schedule 24.12.2019    source источник
comment
Я считаю вашу конфигурацию webpack несколько сложной, но я знаю, что cssMiniExtractPlugin и загрузчик стилей не работают вместе. Также важен порядок погрузчиков.   -  person Karlan    schedule 24.12.2019


Ответы (1)


Это моя конфигурация веб-пакета для части стилей:

{
            test: /\.s?css$/,
            use: [
                {
                    loader: MiniCssExtractPlugin.loader
                },
                {
                    loader: 'css-loader'
                },
                {
                    loader: 'postcss-loader',
                    options: {
                        config: {
                            path: 'postcss.config.js'
                        }
                    }
                },
                {
                    loader: 'sass-loader'
                },
            ]
        }

и в моем postcss.config.js:

module.exports = {
    plugins: [
      require('autoprefixer')
    ]
  }
person Karlan    schedule 24.12.2019