webpack v3 学习笔记(三) 打包css代码 和 Tree Shaking

285 阅读3分钟

打包 css

打包 css 主要用到的 loader 是 style-loader 和 css-loader。css-loader 的作用是处理在 js 中引入的css。另外如果我们用到了 css 预编译,如 sass,则我们还需要 sass-loader 和 node-sass(node环境下运行的sass)。同时我们还可以在 loader 的过程中借助 postcss-loader 使用很多有用的 css 插件,如 autoprefixer,pxtorem。

在打包的结果中其实是没有 css 文件的,如打包出的 app.bundle.js,打包进去的 css 代码都是在浏览器中运行 js 后添加的,如果要把 css 单独打包成文件,还需要 webpack 的插件 extract-text-webpack-plugin(v3,已被废弃),v4 中使用 mini-css-extract-plugin

npm install webpack@^3.0.0 style-loader css-loader sass-loader@^7.0.0 node-sass // sass-loader v8 在 v3 中报错
npm install postcss postcss-loader autoprefixer cssnano
npm install extract-text-webpack-plugin
touch webpack.config.js
mkdir src
mkdir src/css
touch src/app.js
touch src/css/base.scss
touch src/css/common.scss

base.scss

$color: red;
html {
  background-color: $color;
}

ul {
  li {
    list-style: none;
  }
}

common.scss

body {
  div {
    width: 100px;
    height: 100px;
    background-color: blue;
    display: flex;
  }
}

.big {
  width: 200px;
  height: 200px;
}

app.js

import './css/base.scss'
import common from './css/common.scss'

const div = document.createElement('div')
// 使用css-module
div.className = common.big
document.body.append(div)

webpack.config.js

var path = require('path')
var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

module.exports = {
  entry: {
    app: './src/app'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, './dist'),
    publicPath: './dist/',
    chunkFilename: '[name].chunk.js'
  },
  module: {
    rules: [
      {
        test: /\.scss$/,
        // 使用插件,将 css 提取成单独的文件
        use: ExtractTextWebpackPlugin.extract({
          fallback: {
            loader: 'style-loader',
            // 提取 css 成单独文件时下面的设置其实是没有效果的
            options: {
              /*
              * styleTag: style 标签插入
              * linkTag:link 标签插入
              * singletonStyleTag:单 style 标签插入
              * lazyStyleTag:附加原来的 usable 的功能,可以使用 use() 和 unuse()
              * lazySingletonStyleTag: 同上,单 style 标签
              * */
              injectType: 'singletonStyleTag',
              // 插入的位置
              insert: 'head'
            }
          },
          use: [
            {
              loader: 'css-loader',
              options: {
                // 启用css-module
                modules: true
                // 压缩代码的选项被移除,可以转而使用 postcss 或者 UglifyjsWebpackPlugin
              }
            },
            {
              loader: 'postcss-loader',
              options: {
                ident: 'postcss',
                plugins: [
                  // css 浏览器前缀插件
                  require('autoprefixer')(),
                  // 压缩 css 插件
                  require('cssnano')()
                ]
              }
            },
            {
              loader: 'sass-loader'
            }
          ]
        })
      }
    ]
  },
  plugins: [
    // 配置提取 css 的插件,v4 中使用 mini-css-extract-plugin
    new ExtractTextWebpackPlugin({
      filename: '[name].min.css',
      allChunks: true
    })
  ]
}

打包效果如下:

Tree Shaking

tree shaking 可以帮助我们去除项目中没有用到的代码,虽然在 v3 版本中有缺陷没什么用处,但是在 v4 中修复了缺陷,下面的是 v3 的 Tree Shaking:

在上面打包 css 的目录文件的基础上:

mkdir src/utils
touch src/utils/util.js

util.js

export function a () {
  return 'this is a'
}

export function b () {
  return 'this is b'
}

export function c () {
  return 'this is c'
}

在 app.js 下面新加:

import { a } from './utils/util'

console.log(a())

原来设置下的打包结果下,util 下的三个函数都会打包进去:

然后我们使用插件,在设置中require webpack并在 plugins 下新加插件:

var webpack  = require('webpack')

plugins: [
    // 配置提取 css 的插件,v4 中使用 mini-css-extract-plugin
    new ExtractTextWebpackPlugin({
      filename: '[name].min.css',
      allChunks: true
    }),
    // js tree shaking
    new webpack.optimize.UglifyJsPlugin()
  ]

在打包结果中,就只剩下了 a 方法:

如果还要对 css 进行 tree shaking,则要借助 purifycss-webpack 和 glob-all,这里要注意和 css-module 是冲突的,要把 css-loader 里的 modules 设为 false。!

npm install purify-css purifycss-webpack glob-all

我们给 common.scss 新加几个不用的 css:

.small-box {
    width: 50px;
    height: 50px;
}
.mini-box {
    width: 50px;
    height: 50px
}

app.js下我们使用了 .small-box

import './css/base.scss'
import common from './css/common.scss'

const div = document.createElement('div')
div.className = 'small-box'
document.body.append(div)

import { a } from './utils/util'

console.log(a())

在webpack.config.js 下设置插件

var PurifyCSS = require('purifycss-webpack')
var glob = require('glob-all')

plugins: [
    // 配置提取 css 的插件,v4 中使用 mini-css-extract-plugin
    new ExtractTextWebpackPlugin({
      filename: '[name].min.css',
      allChunks: true
    }),
    // css tree shaking, 插件放在 ExtractTextWebpackPlugin 之后
    new PurifyCSS({
      // 原来的压缩会失效,在这里重新设置
      minimize: true,
      paths: glob.sync([
        // 使用到 css 的所有文件的路径,没配置对的话用到的 css 也可能被删掉
        path.join(__dirname, './src/*.js')
      ])
    }),
    // js tree shaking
    new webpack.optimize.UglifyJsPlugin()
  ]

打包后 css 文件:

没用到的类成功去除。