美文网首页构建工具:Webpack
Webpack(二十二):对第三方库css/项目全局css/vu

Webpack(二十二):对第三方库css/项目全局css/vu

作者: CodeMT | 来源:发表于2020-10-12 09:37 被阅读0次

    在讲解提取css之前,我们先看下项目的架构如下结构:

    ### 目录结构如下:
    demo1                                       # 工程名
    |   |--- dist                               # 打包后生成的目录文件             
    |   |--- node_modules                       # 所有的依赖包
    |   |--- app
    |   | |---index
    |   | | |-- views                           # 存放所有vue页面文件
    |   | | | |-- index.vue                    
    |   | | | |-- list.vue                     
    |   | | |-- components                      # 存放vue公用的组件
    |   | | |-- js                              # 存放js文件的
    |   | | |-- css
    |   | | | |-- base.css
    |   | | | |-- index.css
    |   | | |-- store                           # store仓库
    |   | | | |--- actions.js
    |   | | | |--- mutations.js
    |   | | | |--- state.js
    |   | | | |--- mutations-types.js
    |   | | | |--- index.js
    |   | | |-- app.js                          # vue入口配置文件
    |   | | |-- router.js                       # 路由配置文件
    |   |--- views
    |   | |-- index.html                        # html文件
    |   |--- webpack.config.js                  # webpack配置文件 
    |   |--- .gitignore  
    |   |--- README.md
    |   |--- package.json
    |   |--- .babelrc                           # babel转码文件
    

    我们都知道提取css的插件是使用 extract-text-webpack-plugin 这个插件,但是在webpack4中需要如下安装该插件:

    npm i extract-text-webpack-plugin@next -D
    

    首先想让项目里面的css打包生效的话,有二种方式,第一种是使用 style-loader自动将css代码插入到head标签style内,第二种方式是使用 extract-text-webpack-plugin 插件单独提取一个css文件,然后在页面上引入该css文件即可。

    下面我们分别来介绍 第三方库css文件,项目全局的css,及vue中内联的css或stylus样式是如何提取到单独的文件内的。

    首先在介绍之前,我们编写全局的css的话,需要抛弃掉stylus了,为什么要抛弃掉呢?因为styl文件和extract-text-webpack-plugin 插件一起使用的话会报错,比如如下配置代码:

    module.exports = {
      module: {
        rules: [
          {
            // 使用正则去匹配
            test: /\.styl$/,
            use: ExtractTextPlugin.extract({
              fallback: {
                loader: 'style-loader',
                options: {
                  singleton: true // 表示将页面上的所有css都放到一个style标签内
                }
              },
              use: [
                {
                  loader: 'style-loader',
                  options: {}
                },
                {
                  loader: 'css-loader',
                  options: {
                    minimize: true
                  }
                },
                {
                  loader: 'postcss-loader',
                  options: {
                    ident: 'postcss',
                    plugins: [
                      require('postcss-cssnext')(),
                      require('cssnano')(),
                      require('postcss-pxtorem')({
                        rootValue: 16,
                        unitPrecision: 5,
                        propWhiteList: []
                      }),
                      require('postcss-sprites')()
                    ]
                  }
                },
                {
                  loader: 'stylus-loader',
                  options: {}
                }
              ]
            })
          }
        ]
      }
    }
    

    报错信息内容如下:

    可以看这个文章(https://segmentfault.com/q/1010000009432668), 也是在讲webpack配置styl+postcss+ExtractTextPlugin错误的问题。

    因此对于项目全局的css文件建议直接使用css后缀即可,然后我就想在项目的入口文件app.js 这样引入css文件,如下:

    // 引入element组件化框架
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    
    // 引入样式文件
    import './css/index.css';
    

    如上代码,第三方库文件是饿了么vue组件的样式,项目全局的css文件是 css/index.css, 如上这样引入进来,index.css
    代码如下:

    @import './base.css';
    body {
      font-size: 18px;
      display: flex;
    }
    

    css/base.css 代码如下:

    body, p , div {
      margin: 0;
      padding: 0;
    }
    

    然后对于 vue 文件内部编写css的话,如下使用stylus编写的,代码如下:

    <style lang="stylus">
      #list-container 
        width 100%
    </style>
    
    <template>
      <div id="list-container">hello world</div>
    </template>
    <script type="text/javascript">
      export default {
        data() {
          return {
    
          }
        }
      }
    </script>
    

    因此webpack.config.js 部分代码如下配置:

    const ExtractTextPlugin = require("extract-text-webpack-plugin");
    const webpack = require('webpack');
    
    // 引入打包html文件
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
              fallback: {
                loader: 'style-loader',
                options: {
                  singleton: false // 为true表示将页面上的所有css都放到一个style标签内
                }
              },
              use: [
                {
                  loader: 'css-loader',
                  options: {
                    minimize: true
                  }
                },
                {
                  loader: 'postcss-loader',
                  options: {
                    ident: 'postcss',
                    plugins: [
                      require('postcss-cssnext')(),
                      require('cssnano')(),
                      require('postcss-pxtorem')({
                        rootValue: 16,
                        unitPrecision: 5,
                        propWhiteList: []
                      }),
                      require('postcss-sprites')()
                    ]
                  }
                }
              ]
            })
          },
          {
            test: /\.vue$/,
            loader: 'vue-loader',
            options: {
              // extractCSS: true,
              loaders: {
                css: ExtractTextPlugin.extract({
                  use: 'css-loader',
                  fallback: 'vue-style-loader'
                }),
                styl: ExtractTextPlugin.extract({
                  use: 'css-loader!stylus-loader',
                  fallback: 'vue-style-loader'
                })
              },
              postLoaders: {
                html: 'babel-loader'
              }
            }
          }
        ]
      },
      plugins: [
        new HtmlWebpackPlugin({
          hash: true, //为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。
          template: './views/index.html' // 模版文件
        }),
        new ClearWebpackPlugin(['dist']),
        new ExtractTextPlugin({
          filename: process.env.NODE_ENV === 'production' ? '[name].[contenthash:7].css' : 'bundle.css',
          allChunks: true
        })
      ]
    };
    

    然后在项目中运行 npm run dev 打包,可以看到打包后的bundle.css代码如下信息:

    如上打包会把 base.css 和 index.css 及 vue的样式文件都打包到 bundle.css文件内。

    但是vue内联样式会打包到 head内部的style标签中,如下截图所示:

    理解ExtractTextWebpackPlugin.extract()方法

    ExtractTextWebpackPlugin.extract({
      fallback:{
        loader: 'style-loader',
        options: {
          singleton: false // 为true表示将页面上的所有css都放到一个style标签内
        }
      },
      use:[]
    });
    

    fallback:指编译后用什么loader来提取css文件。例如使用style-loader, 然后上面的options是选项,设置singleton为false的话,可以把css文件单独提取出来,如果为true的话,会将页面上所有的css文件都放在一个style标签内。

    use:指需要什么样的loader去编译文件。 如.css文件使用css-loader,如下:

    {
      loader: 'css-loader',
      options: {
        minimize: true
      }
    }
    

    现在我们需要解决的是把所有的css文件打包到一个文件里面去。其实很简单只要把vue中的配置文件 extractCSS: true, 会把vue中的样式文件提取出来 打开就可以了,如下部分配置代码:

    {
      test: /\.vue$/,
      loader: 'vue-loader',
      options: {
        extractCSS: true, // 会把vue中的样式文件提取出来
        loaders: {
          css: ExtractTextPlugin.extract({
            use: 'css-loader',
            fallback: 'vue-style-loader'
          }),
          styl: ExtractTextPlugin.extract({
            use: 'css-loader!stylus-loader',
            fallback: 'vue-style-loader'
          })
        },
        postLoaders: {
          html: 'babel-loader'
        }
      }
    },
    

    然后执行打包命令,再看下效果如下所示:

    JS代码如下所示:

    因此所有的webpack.config.js 代码如下:

    const path = require('path');
    
    const ExtractTextPlugin = require("extract-text-webpack-plugin");
    
    // 清除dist目录下的文件
    const ClearWebpackPlugin = require('clean-webpack-plugin');
    
    const webpack = require('webpack');
    
    // 引入打包html文件
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    // 引入HappyPack插件 
    const HappyPack = require('happypack');
    
    // 引入 ParallelUglifyPlugin 插件
    const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
    
    // 引入 webpack-deep-scope-plugin 优化
    const WebpackDeepScopeAnalysisPlugin = require('webpack-deep-scope-plugin').default;
    
    // 引入 DllReferencePlugin
    const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
    
    module.exports = {
      // 入口文件
      entry: {
        main: './app/index/app.js'
      },
      output: {
        filename: process.env.NODE_ENV === 'production' ? '[name].[contenthash].js' : 'bundle.js',
        // 将输出的文件都放在dist目录下
        path: path.resolve(__dirname, 'dist')
      },
      module: {
        rules: [
          {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
              fallback: {
                loader: 'style-loader',
                options: {
                  singleton: false // 为true表示将页面上的所有css都放到一个style标签内
                }
              },
              use: [
                {
                  loader: 'css-loader',
                  options: {
                    minimize: true
                  }
                },
                {
                  loader: 'postcss-loader',
                  options: {
                    ident: 'postcss',
                    plugins: [
                      require('postcss-cssnext')(),
                      require('cssnano')(),
                      require('postcss-pxtorem')({
                        rootValue: 16,
                        unitPrecision: 5,
                        propWhiteList: []
                      }),
                      require('postcss-sprites')()
                    ]
                  }
                }
              ]
            })
          },
          {
            test: /\.(png|jpg)$/,
            use: ['happypack/loader?id=image']
          },
          {
            test: /\.js$/,
            // 将对.js文件的处理转交给id为babel的HappyPack的实列
            use: ['happypack/loader?id=babel'],
            // loader: 'babel-loader',
            exclude: path.resolve(__dirname, 'node_modules') // 排除文件
          },
          {
            test: /\.vue$/,
            loader: 'vue-loader',
            options: {
              extractCSS: true, // 会把vue中的样式文件提取出来
              loaders: {
                css: ExtractTextPlugin.extract({
                  use: 'css-loader',
                  fallback: 'vue-style-loader'
                }),
                styl: ExtractTextPlugin.extract({
                  use: 'css-loader!stylus-loader',
                  fallback: 'vue-style-loader'
                })
              },
              postLoaders: {
                html: 'babel-loader'
              }
            }
          },
          {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, // 处理图片
            use: {
              loader: 'url-loader', // 解决打包css文件中图片路径无法解析的问题
              options: {
                // 打包生成图片的名字
                name: 'img/[name].[contenthash:7].[ext]',
                limit: 1024
              }
            }
          },
          {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, // 处理字体
            use: {
              loader: 'file-loader'
            }
          },
          //媒体文件处理
          {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            loader: 'url-loader',
            options: {
              limit: 40000,
              name: 'media/[name].[hash:7].[ext]'
            }
          }
        ]
      },
      resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js'
        },
        modules: [
          path.join(__dirname, './app'),
          'node_modules'
        ],
        extensions: ['*', '.js', '.json', '.vue', '.styl']
      },
      devtool: 'cheap-module-eval-source-map',
      devServer: {
        port: 8081,
        host: '0.0.0.0',
        headers: {
          'X-foo': '112233'
        },
        inline: true,
        overlay: true,
        stats: 'errors-only'
      },
      mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
      plugins: [
        new HtmlWebpackPlugin({
          hash: true, //为了开发中js有缓存效果,所以加入hash,这样可以有效避免缓存JS。
          template: './views/index.html' // 模版文件
        }),
        new ClearWebpackPlugin(['dist']),
      
        new ExtractTextPlugin({
          filename: process.env.NODE_ENV === 'production' ? '[name].[contenthash:7].css' : 'bundle.css',
          allChunks: true
        }),
      
        /****   使用HappyPack实例化    *****/
        new HappyPack({
          // 用唯一的标识符id来代表当前的HappyPack 处理一类特定的文件
          id: 'babel',
          // 如何处理.js文件,用法和Loader配置是一样的
          loaders: ['babel-loader']
        }),
        new HappyPack({
          id: 'image',
          loaders: [{
            loader: require.resolve('url-loader'),
            options: {
              limit: 10000,
              name: '[name].[ext]'
            }
          }]
        }),
        // 使用 ParallelUglifyPlugin 并行压缩输出JS代码
        new ParallelUglifyPlugin({
          // 传递给 UglifyJS的参数如下:
          uglifyJS: {
            output: {
              /*
               是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,
               可以设置为false
              */
              beautify: false,
              /*
               是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为false
              */
              comments: false
            },
            compress: {
              /*
               是否在UglifyJS删除没有用到的代码时输出警告信息,默认为输出,可以设置为false关闭这些作用
               不大的警告
              */
              warnings: false,
    
              /*
               是否删除代码中所有的console语句,默认为不删除,开启后,会删除所有的console语句
              */
              drop_console: true,
    
              /*
               是否内嵌虽然已经定义了,但是只用到一次的变量,比如将 var x = 1; y = x, 转换成 y = 5, 默认为不
               转换,为了达到更好的压缩效果,可以设置为false
              */
              collapse_vars: true,
    
              /*
               是否提取出现了多次但是没有定义成变量去引用的静态值,比如将 x = 'xxx'; y = 'xxx'  转换成
               var a = 'xxxx'; x = a; y = a; 默认为不转换,为了达到更好的压缩效果,可以设置为false
              */
              reduce_vars: true
            }
          }
        }),
        new WebpackDeepScopeAnalysisPlugin(),
        // 设置环境变量信息
        new webpack.DefinePlugin({
          'process.env': {
            NODE_ENV: JSON.stringify(process.env.NODE_ENV)
          }
        })
      ]
    };
    

    相关文章

      网友评论

        本文标题:Webpack(二十二):对第三方库css/项目全局css/vu

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