Webpack - scss/css 模块样式未在产品中应用

Posted

技术标签:

【中文标题】Webpack - scss/css 模块样式未在产品中应用【英文标题】:Webpack - scss/css modules styles not being applied in prod 【发布时间】:2020-03-27 15:16:21 【问题描述】:

我正在使用 scss 模块,所以我在我的 react 组件中使用了 styleName,并且一切都在 dev 中运行。 prod 中的元素看起来像 <div class="row" stylename="table"></div>,但没有对 table 应用任何样式。

webpack 配置被分成多个文件(webpack.profile.jswebpack.base.jswebpack.dev.jswebpack.prod.js

旁注:我还注意到某些 jenkins 作业无法处理 @ 变量,不确定它是否与 webpack/sass-loader 有关。

webpack.profile.js

const path = require('path')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CompressionPlugin = require('compression-webpack-plugin')
const VisualizerPlugin = require('webpack-visualizer-plugin')

module.exports = require('./webpack.base')(
    mode: 'production',
    devServer: 
        port: 3000,
        contentBase: path.join(process.cwd(), 'dist/')
    ,
    optimization: 
        minimizer: [
            new UglifyJsPlugin(
                cache: true,
                parallel: true
            ),
            new OptimizeCSSAssetsPlugin()
        ]
    ,
    module: 
        rules: [
            
                test: /\.(sc|sa|c)ss$/,
                use: [
                     loader: MiniCssExtractPlugin.loader ,
                        
                        loader: "css-loader",
                        options: 
                                modules: true,
                                sourceMap: true,
                                localIdentName: "[name]_[local]_[hash:base64:5]"
                        
                        
                ]
            
        ]
    ,
    plugins: [
        new CompressionPlugin(
            test: /\.(js|css|html)$/
        ),
        new VisualizerPlugin(
            filename: '../stats/bundleStats.html'
        ),
        new MiniCssExtractPlugin(
            filename: '[name].[hash].css',
            chunkFilename: '[id].[hash].css'
        )
    ]
)

webpack.base.js

const path = require('path')
const Dotenv = require('dotenv-webpack')
const HtmlWebPackPlugin = require('html-webpack-plugin')

module.exports = options => 
    let envPath = '.env'
    process.argv.forEach(val => 
        if (val.includes('--env=')) 
            const curEnv = val.slice(6)
            if (['dev', 'stg'].includes(curEnv)) 
                envPath = `.env.$curEnv`
            
        
    )
    return 
        mode: options.mode,
        devServer: options.devServer,
        entry: [path.join(process.cwd(), 'src/main.js')],
        output: 
            path: path.join(__dirname, '../dist/'),
            publicPath: '/',
            filename: '[name].[hash].js',
            chunkFilename: '[id].[hash].js'
        ,
        resolve: 
            extensions: ['.js', '.jsx'],
            modules: [
                path.join(__dirname, '../src'),
                path.join(__dirname, '../node_modules')
            ],
            alias: 
                '@constants': path.join(__dirname, '../src/constants'),
                '@c': path.join(__dirname, '../src/components'),
                '@C': path.join(__dirname, '../src/containers')
            
        ,
        plugins: options.plugins.concat([
            new Dotenv(
                path: path.join(process.cwd(), envPath)
            ),
            new HtmlWebPackPlugin(
                inject: true,
                template: path.join(__dirname, '../src/static/index.html'),
                favicon: path.join(__dirname, '../src/static/favicon.ico')
            )
        ]),
        module: 
            rules: options.module.rules.concat([
                // 
                //  enforce: 'pre',
                //  test: /\.jsx?$/,
                //  exclude: /node_modules/,
                //  use: [
                //      
                //          loader: 'eslint-loader',
                //          options: 
                //              quiet: true
                //          
                //      
                //  ]
                // ,
                
                    test: /\.(woff|woff2|eot|ttf|otf)$/,
                    exclude: [ /\.scss$/ ],
                    use: [
                        
                            loader: 'file-loader',
                            options: 
                                name: '[hash].[ext]',
                                outputPath: 'fonts'
                            
                        
                    ]
                ,
                
                    test: /\.svg$/,
                    loader: 'svg-react-loader'
                ,
                
                    test: /\.(gif|png|jpe?g)$/i,
                    use: [
                        
                            loader: 'url-loader',
                            options: 
                                limit: 10 * 1024,
                                name: '[hash].[ext]',
                                outputPath: 'assets'
                            
                        ,
                        
                            loader: 'image-webpack-loader',
                            options: 
                                disable: options.mode === 'development'
                            
                        
                    ]
                
            ])
        
    

webpack.dev.js

const webpack = require('webpack')
const BrowserSyncPlugin = require('browser-sync-webpack-plugin')

module.exports = require('./webpack.base')(
    mode: 'development',
    devServer: 
        hot: true,
        port: 3000,
        historyApiFallback: true
    ,
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new BrowserSyncPlugin(
             proxy: 'http://localhost:3000/', open: false ,
             reload: false 
        )
    ],
    module: 
        rules: [
            
                test: /\.jsx?$/,
                exclude: /node_modules/,
                use: 
                    loader: 'babel-loader',
                    options: 
                        plugins: [
                            [
                                'react-css-modules',
                                
                                    "filetypes": 
                                        ".scss":  "syntax": "postcss-scss" 
                                    ,
                                    "generateScopedName": '[name]_[local]_[hash:base64:5]'
                                
                            ],
                        ],
                    ,
                ,
                resolve: 
                        extensions: ['.js', '.jsx']
                
            ,
            
                test: /\.(sa|sc)ss$/,
                use: [
                     loader: 'style-loader' ,
                    
                        loader: 'css-loader',
                        options: 
                            modules: true,
                            sourceMap: true,
                            localIdentName: '[name]_[local]_[hash:base64:5]'
                        
                    ,
                    
                        loader: 'sass-loader'
                    
                ]
            ,
            
                test: /\.css$/,
                use: ['style-loader', 'css-loader', 'postcss-loader']
            ,
        ]
    
)

webpack.prod.js

const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = require('./webpack.base')(
    mode: 'production',
    devServer: 
        port: 3000,
        contentBase: path.join(process.cwd(), 'dist/')
    ,
    optimization: 
        minimize: true,
        minimizer: [
            new TerserPlugin(
                cache: true,
                parallel: true
            ),
            new OptimizeCSSAssetsPlugin()
        ]
    ,
    module: 
        rules: [
            
                test: /\.jsx?$/,
                exclude: /node_modules\/@babel/,
                use: 
                    loader: 'babel-loader',
                    options: 
                        presets: [
                            [
                            '@babel/preset-env',
                                
                                    'targets': 
                                        'ie': '11'
                                    ,
                                    'loose': true,
                                    'forceAllTransforms': true
                                
                            ],
                            '@babel/preset-react'
                        ],
                        sourceType: 'unambiguous',
                        plugins: [
                            [
                                '@babel/plugin-proposal-decorators',
                                
                                    'legacy': true
                                
                            ],
                            '@babel/plugin-transform-runtime',
                            '@babel/plugin-syntax-dynamic-import',
                            '@babel/plugin-proposal-function-bind',
                            '@babel/plugin-proposal-class-properties',
                            '@babel/plugin-proposal-export-default-from',
                            '@babel/plugin-proposal-export-namespace-from'
                        ]
                    
                ,
                resolve: 
                    extensions: ['.js', '.jsx']
                
            ,
            
                test: /\.(sc|sa)ss$/,
                use: [
                     loader: MiniCssExtractPlugin.loader ,
                    
                    loader: "css-loader",
                    options: 
                        modules: true,
                        sourceMap: true,
                        localIdentName: "[name]_[local]_[hash:base64:5]"
                    
                    ,
                     loader: "postcss-loader" ,
                      loader: "sass-loader" 
                ]
            ,
            
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader'
                ]
            
        ]
    ,
    plugins: [
        new CleanWebpackPlugin([path.join(process.cwd(), '/dist')], 
            allowExternal: true
        ),
        new MiniCssExtractPlugin(
            filename: '[name].[hash].css',
            chunkFilename: '[id].[hash].css'
        ),
        new CompressionPlugin(
            test: /\.(js|css)$/,
            filename: asset => asset.file
        )
    ]
)

【问题讨论】:

【参考方案1】:

对于这行代码

test: /\.(sc|sa|c)ss$/,
                use: [
                     loader: MiniCssExtractPlugin.loader ,
                        
                        loader: "css-loader",

我很确定你不能这样做,因为 scss 和 sass 需要有 sass 或 scss 加载器,所以如果你使用 css-loader,它就无法处理 sass 或 scss

这是我的配置方式

module: 
        rules: [
                test: /\.scss$/,
                use: [
                    'style-loader',
                    MiniCssExtractPlugin.loader,
                    
                        loader: "css-loader",
                        options: 
                            minimize: true,
                            sourceMap: true
                        
                    ,
                    
                        loader: "sass-loader"
                    
                ]
            
        ]
    

你可以查看我的完整配置here

【讨论】:

我正在尝试使用 scss 模块并生成一个作用域名称,其中类名看起来像 table_3A5D。我的元素的类名/样式名正在转换,所以我不确定是否是未加载 scss 样式表,或者转换样式名是否可以解决问题。 我已经通过将react-css-modules 插件添加到babel-loader 来处理scss 文件类型来解决我的问题。

以上是关于Webpack - scss/css 模块样式未在产品中应用的主要内容,如果未能解决你的问题,请参考以下文章

Vue SFC 样式未在 webpack 生产构建中提取

Laravel 5.4 Webpack Mix - 合并SCSS和CSS

vue--加载模块详解

SCSS / CSS 最接近父选择器

Scss的使用场景

Webpack 中的相对 CSS url