美文网首页
2020-12-02 CSS 文件的代码分割(4.92)

2020-12-02 CSS 文件的代码分割(4.92)

作者: 夏天的风2020 | 来源:发表于2020-12-03 09:55 被阅读0次

    之前总结的代码分割都是针对JS代码的,
    如果要对CSS代码进行代码分割,要怎么办呢?
    借助MiniCssExtractPlugin插件

    image
    • 在我们没有配置这个插件的时候,webpack是怎么对css代码进行打包的呢?我们来试一下

      image
    image
    • 然后运行打包命令npm run dev-build
      1.png
    
    然后运行代码会发现,样式生效了。
    由此可以得知,`webpack`在打包的时候,它会把CSS文件直接打包到JS文件里。
    这也就是我们常听说的`CSS IN JS`这样一个概念
    
    但是这并不是我们希望的,
    我们希望的是,在打包生成代码的时候,
    如果我们引入的是CSS文件,那么把CSS文件单独打包到`dist`目录下,生成一个CSS文件,
    而不是打包到`js文件里`,
    这个时候,我们就要借助`MiniCssExtractPlugin`插件了;
    具体的使用步骤如下:
    
    
    • 先安装
      npm install --save-dev mini-css-extract-plugin
    
    
    此版本官方文档显示这个插件有个缺陷,
    TODO:
    HMR support
    也就是现在这个模块是不支持模块热更新的,
    
    这就意味着在开发环境使用这个插件,
    改变了css的样式,这个样式不会及时的更新到我们的项目中,
    我们需要手动刷新页面,
    开发效率低
    
    
    所以我们一般在线上环境的打包过程中使用,
    
      
    
    • 安装好以后,要配置一下webpack.prod.js
    //dist目录下 webpack.prod.js配置如下
    
    const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //引入这个插件
    const merge = require('webpack-merge');
    const commonConfig = require('./webpack.common.js');
    
    const prodConfig = {
        mode: "production",
        devtool:'cheap-module-source-map',
        plugins: [           //使用这个插件,还需要对loader进行一些配置
          new MiniCssExtractPlugin({
            filename: '[name].css',
            chunkFilename: '[id].css',
          }),
    }
    
    module.exports = merge(commonConfig,prodConfig)
    
    
    之前我们最终会通过style-loader把css样式挂载到页面上,
    module: {
       rules: [
            {
                test: /\.scss$/,
                    use: [
                        'style-loader',
                        {
                            loader: 'css-loader',
                            options: {
                                importLoaders: 2
                            }
                        },
                        'sass-loader',
                        'postcss-loader'
                    ]
            },{
                test: /\.css$/,
                    use: [
                        'style-loader',
                        'css-loader',
                        'postcss-loader'
                    ]
            }]
        },
    
    module: {
        rules: [
          {
            test: /\.css$/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader,
                options: {
                  publicPath: (resourcePath, context) => {
           
                  },
                },
              },
              'css-loader',
            ],
          },
        ],
      },
    

    src目录下,webpack.common.js文件中,
    rules中对应的css文件,scss文件这部分代码剪切下

    
    const path = require('path')   
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const CleanWebpackPlugin  = require('clean-webpack-plugin')
    
    module.exports = {
        entry: {
            main: "./src/index.js"
        },  
        module: {
            rules: [
            {
                test: /\.js$/, 
                exclude: /node_modules/,  
                loader: 'babel-loader'
            },
            {
                test: /\.(jpg|png|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        name: '[name]_[hash].[ext]',
                        outputPath: 'images/',
                        limit: 10240
                    }
                }
            },
            {
                test: /\.(eot|ttf|svg|woff)$/,
                use: {
                    loader: 'file-loader'
                }
            },
    //剪切到,分别放入webpack.dev.js和webpack.config.js中
          //  {
         //       test: /\.scss$/,
         //           use: [
          //              'style-loader',
           //             {
          //                  loader: 'css-loader',
         //                   options: {
         //                       importLoaders: 2
         //                   }
        / /               },
        //                'sass-loader',
        //                'postcss-loader'
        //            ]
       //     },{
      //          test: /\.css$/,
       //             use: [
       //                 'style-loader',
        //                'css-loader',
         //               'postcss-loader'
       //             ]
      //      }]
        },
        plugins: [
            new HtmlWebpackPlugin({
                template:'./src/index.html'
            }),
            new CleanWebpackPlugin()
        ],
        output: {
            path:path.resolve(__dirname,'dist'),   
            filename: '[name].js'   
        }
    }
    
    

    webpack.dev.js中关于css文件,scss文件如下配置:

    
    //webpack.dev.js
    const webpack = require('webpack');
    const merge = require('webpack-merge');
    const commonConfig = require('./webpack.common.js');
    
    const devConfig = {
        mode: "development",
        devtool:'cheap-module-eval-source-map',
        devServer: {
            contentBase: './dist',
            open: true,
            port: 8080,
            hot: true,  //让webpack开启  Hot Module Replace 的功能
        },
    module: {
    //在开发环境中还是使用style-loader
          rules:[
            {
              test: /\.scss$/,
              use:[
                'style-loader',
                {
                  loader: 'css-loader',
                  options: {
                                importLoaders: 2
                            }
                },            
                'sass-loader',
                'postcss-loader'
              ]
            },
            {
              test: /\.css$/,
              use: [
                  'style-loader',
                  'css-loader',
                  'postcss-loader'
              ]
            }
          ]
        },
        plugins: [
            new webpack.HotModuleReplacementPlugin()
        ],
        optimization: {
            usedExports: true  
        }
    }
    
    module.exports = merge(commonConfig,devConfig)
    

    webpack.prod.js还剩下如下配置

    //webpack.prod.js
    const merge = require('webpack-merge');
    const merge = require('webpack-merge');
    const commonConfig = require('./webpack.common.js');
    
    const prodConfig = {
        mode: "production",
        devtool:'cheap-module-source-map',
        module: {
      //在线上环境中
          rules:[
            {
              test: /\.scss$/,
              use:[
               MiniCssExtractPlugin.loader, //使用这个插件提供给我们的loader替换掉style-loader
                {
                  loader: 'css-loader',
                  options: {
                                importLoaders: 2
                            }
                },            
                'sass-loader',
                'postcss-loader'
              ]
            },
            {
              test: /\.css$/,
              use: [
                 MiniCssExtractPlugin.loader,
                  'css-loader',
                  'postcss-loader'
              ]
            }
          ]
        },
    plugins: [
            new MiniCssExtractPlugin({})
        ],
    }
    
    //最终导出的是 prodConfig 和 commonConfig 结合的配置
    module.exports = merge(commonConfig,prodConfig)
    
    • 然后打包生成·线上·的代码
      npm run build,
      发现仍然没于对CSS做单独的打包
    image
    • 分析下原因,可能是下边几个因素造成的,之前我们在webpack.dev.js里做了下边的配置

      image
      • 这个参数是给tree shaking使用的。
        在做tree shaking的时候,webpack会对所有的模块都去tree shaking
        但是有些模块我们不希望进行tree shaking
        所以我们配置了usedExports: true
        然后在package.json里,我们就可以在sideEffects去写一些内容来代替false值。
      image
      • 之前tree shaking对我们引入的style.css起了作用,
        发现我们虽然引入了文件,但是并没于使用它,
        所以直接就把style.css给干掉了,
        所以要解决这个问题,我们要对tree shaking做一下修改。
      image
      • 还有就是,之前我们把tree shaking的配置写在了dev开发环境里,
        实际上我们应该写在common这里,
        因为不管是线上代码,还是本地测试代码,
        我们都需要,使用这个参数来告诉我们的webpack
        有一些css文件不要去做tree shaking的处理,
        所以,我们需要把usedExports: truedev里剪切到common
      image
      • 然后我们再运行打包npm run build,发现可以单独对CSS进行打包了,
        dist目录下main.css就是我们这个页面上的 css文件对应的内容,
        main.css.map是一个sourceMap,里面存储了一些映射关系,
        可以方便我们对代码的调试
    image
    还可以对MiniCssExtractPlugin插件进行更详细的配置
    image
    • 然后运行打包命令,发现打包生成的CSS文件的文件名,还是走的filename这个配置,
      而不是chunkFilename这个配置。
      也就是说,打包生成的CSS文件,如果是直接被页面引用,
      那么在使用这个插件的时候,就会走filename这个配置。
      如果是间接要被引用的CSS文件,就会走chunkFilename这个配置

      image
    • 如果我们再增加一个CSS文件,并引入到index.js文件里,进行打包,
      那么webpack会把这两个CSS文件的内容合并到一起。

      image image image
    虽然我们实现了打包单独生成CSS文件,

    但是我们可以看到,生成的文件代码并不是压缩状态的。
    如果我们希望单独生成CSS文件是压缩状态的,可以用`optimize-css-assets-webpack-plugin这个插件

    • 先安装
    npm install --save-dev optimize-css-assets-webpack-plugin
    
    
    • 然后引入和配置
    //dist目录下的webpack.prod.js
    
    const merge = require('webpack-merge');
    const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); //引入这个插件
    const merge = require('webpack-merge');
    const commonConfig = require('./webpack.common.js');
    
    const prodConfig = {
        mode: "production",
        devtool:'cheap-module-source-map',
        module: {
      //在线上环境中
          rules:[
            {
              test: /\.scss$/,
              use:[
               MiniCssExtractPlugin.loader, //使用这个插件提供给我们的loader替换掉style-loader
                {
                  loader: 'css-loader',
                  options: {
                                importLoaders: 2
                            }
                },            
                'sass-loader',
                'postcss-loader'
              ]
            },
            {
              test: /\.css$/,
              use: [
                 MiniCssExtractPlugin.loader,
                  'css-loader',
                  'postcss-loader'
              ]
            }
          ]
        },
    optimization: {
        minimizer: [new OptimizeCSSAssetsPlugin({})], //创建的时候,参数为空,空对象
      },
    plugins: [
            new MiniCssExtractPlugin({})
        ],
    }
    
    //最终导出的是 prodConfig 和 commonConfig 结合的配置
    module.exports = merge(commonConfig,prodConfig)
    

    然后我们再运行打包npm run build,
    发现它不单单帮我们把样式做了合并,
    还把代码做了压缩显示在了一行

    image
    更高级的用法
    • 之前我们是在只有一个入口文件的情况下,对CSS文件进行单独的打包和压缩。如果我们现在有多个入口文件,并且我们希望所有的入口文件引入的CSS文件都能够打包生成到一个CSS样式文件里。该怎么做呢?

      image
    • 看官方文档可以知道,我们现在使用的MiniCssExtractPlugin这个插件,它的底层也是借助了splitChunks这个插件的。我们可以在cacheGroups组里额外增加一个组叫做styles,只要发现打包的文件是CSS为后缀的文件,那么不管它是同步加载的还是异步加载的文件,统一的都把它打包到名字叫做styles的文件里去。
      enforce:true的意思是,忽略掉默认的一些参数,比如说minSize,maxSize等。这些参数都不管,只要是一个CSS文件,就会做代码的拆分,把代码分割到名字叫做styles的文件里去。

      image
    如果我们想根据入口文件的不同,把CSS文件打包到不同的CSS文件里边去,该怎么办?
    image

    链接:https://www.jianshu.com/p/440b97da2262

    相关文章

      网友评论

          本文标题:2020-12-02 CSS 文件的代码分割(4.92)

          本文链接:https://www.haomeiwen.com/subject/ndcuwktx.html