Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
141 views
in Technique[技术] by (71.8m points)

javascript - Webpack - scss/css modules styles not being applied in prod

I'm using scss modules so I'm using styleName in my react components and everything works in dev. The elements in prod looks like <div class="row" stylename="table"></div> but no styles have been applied to table.

The webpack configs are split up into multiple files (webpack.profile.js, webpack.base.js, webpack.dev.js, webpack.prod.js)

Side note: I'm also noticing that certain jenkins job can't process @ variables, not sure if it's related to 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
        })
    ]
})
See Q

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For this line of code

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

I'm pretty sure you cant do that because scss and sass need to have sass or scss loader so it cant process sass or scss if you using css-loader

Here is how I config

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

You can view my full config here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...