将 style[hash].css 拆分为动态加载的块

split style[hash].css into dynamically loaded chunks

由于生成的输出的大小,我试图将样式代码拆分成更小的块。我正在使用 react 进行开发,所以我用 React.lazy().

解决了 javascript 加载问题

假设有一个大型应用程序可以打开 50 个不同的视图。并非所有用户都可以使用所有视图。

我在路由器中所做的是:

...
const view = React.lazy(() => import("./views/view"));
...

...
<view />
...

这样做是将整个应用程序分成 50 个单独的 js 动态加载的文件,这很好。

然而,它并没有以相同的方式划分样式。那么让我们看看其中一种观点:

import React, { Component } from "react";
import "../../scss/view.scss";

class view extends Component {
    ...
}

export default view;

因此每个视图都有自己的 scss 专用于该视图的文件,这使得它们几乎是独立的。问题是 webpack 仍然只生成一个大 style[hash].css 文件。

Webpack 配置:

const HtmlWebPackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");

const htmlPlugin = new HtmlWebPackPlugin({
    template: "./src/index.html",
    filename: "index.html"
});

const extractTextPlugin = new ExtractTextPlugin({
    filename: "css/style.[hash:8].css",
    allChunks: true
});

module.exports = {
    output: {
        filename: "js/main.[hash:8].js"
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: "babel-loader"
            },
            {
                test: /\.(png|jpg|gif|ico|svg|eot|ttf|woff|woff2)$/,
                loader: "url-loader",
                options: {
                    limit: 25000,
                    outputPath: "/assets/",
                    name: "[name].[hash:8].[ext]"
                }
            },
            {
                test: /\.(scss|sass|css)$/i,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: [
                        { loader: "css-loader" },
                        { loader: "postcss-loader", options: { sourceMap: true } },
                        { loader: "sass-loader", options: { sourceMap: true } }
                    ]
                })
            }
        ]
    },
    resolve: {
        extensions: [".js", ".jsx", ".json"]
    },
    plugins: [htmlPlugin, extractTextPlugin],
    devServer: {
        historyApiFallback: {
            rewrites: [{ from: /^\/$/, to: "/index.html" }]
        }
    }
};

有什么方法可以使样式也根据其 js 文件动态生成和加载,例如,如果我打开视图 10,它会加载 10.main[hash].js10.style[hash].css

此问题的答案是替换实际上缺少此功能(将样式拆分为相应块)的已弃用 extract-text-webpack-plugin 包。

应该使用 mini-css-extract-plugin,它会自动运行。

更新工作 webpack 配置文件:

const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const htmlPlugin = new HtmlWebPackPlugin({
    template: "./src/index.html",
    filename: "index.html",
});

const miniCssExtractPlugin = new MiniCssExtractPlugin({
    filename: "css/style.[hash:8].css",
    chunkFilename: "css/[id].style.[hash:8].css",
});

module.exports = {
    output: {
        filename: "js/main.[hash:8].js",
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: "babel-loader",
            },
            {
                test: /\.(png|jpg|jpeg|gif|ico|svg|eot|ttf|woff|woff2)$/,
                loader: "url-loader",
                options: {
                    limit: 25000,
                    outputPath: "/assets/",
                    name: "[name].[hash:8].[ext]",
                },
            },
            {
                test: /\.(scss|sass|css)$/i,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader",
                    "postcss-loader",
                    "sass-loader",
                ],
            },
        ],
    },
    resolve: {
        extensions: [".js", ".jsx", ".json"],
    },
    plugins: [htmlPlugin, miniCssExtractPlugin],
    devServer: {
        historyApiFallback: {
            rewrites: [{ from: /^\/$/, to: "/index.html" }],
        },
    },
};