Webpack从手把手配置到原理浅析(一):基础配置

997 阅读2分钟

本系列文章并不打算从Webpack的概念和原理开始和你娓娓道来,因为我知道,如果你有这个时间,你就不会搜到我这篇文章,而是会选择之间从官网的文档开始慢慢看起。 既然时间紧张,那么我直接从实战开始,从基础配置,到高级配置,再慢慢深入Webpack内部,不仅让你会用,还知道为什么这么用。

第一步:拆分配置

用过Vue脚手架的小伙伴应该会知道,刚创建的Vue项目会初始化一个build文件夹,里面包含了Webpack的一些配置,分为了webpack.base.conf.jswebpack.dev.conf.jswebpack.prod.conf.js3个配置文件。
为什么要分成3个配置文件?原因很简单,就是为了减少不必要的重复代码,而且可以区分开环环境和线上环境的配置。

  • dev文件是开发时的Webpack配置,主要关注的是开发效率
  • prod文件是生产环境的Webpack配置,主要关注的是产出代码的优化
  • base文件则是devprod都会使用到的公共配置 因此,如果你要从零开始配置,那么第一步就是要拆分公共配置、开发配置和生产配置。

第二步:公共配置

在公共配置文件里要配置些什么?

  1. 定义入口文件路径
  2. devprod都会使用的loaderplugin配置
    • 处理ES6:babel-loader
    • 处理CSS
    • 处理Vue或React代码 webpack.base.conf.js:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const srcPath = path.join(__dirname, '..', 'src')

module.exports = {
    // 入口文件
    entry: path.join(srcPath, 'index'),
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: ['babel-loader'],
                include: srcPath,
                exclude: /node_modules/
            },
            {
                test: /\.vue$/,
                loader: ['vue-loader'],
                include: srcPath
            },
            {
                test: /\.less$/,
                loader: ['style-loader', 'css-loader', 'less-loader']
            }
        ]
    },
    plugins: [
        // 生成最终的HTML文件,把打包后的bundle文件放在script标签内
        new HtmlWebpackPlugin({
            template: path.join(srcPath, 'index.html'),
            filename: 'index.html'
        })
    ]
}

注意:

  • loader的顺序是从后往前执行,所以像.less文件应该是先将.less文件解析成.css文件,再将.css文件解析成style注入到JS文件里,所以对于.less文件的loader顺序为:['style-loader', 'css-loader', 'less-loader']

第三步:开发环境配置

开发环境配置要点:

  1. 设置模式为开发模式
  2. 图片处理:url-loader
  3. 启动服务:webpack-dev-server webpack.dev.conf.js:
const webpack = require('webpack')
const webpackCommonConf = require('./webpack.common.js')
const { smart } = require('webpack-merge')

const distPath = path.join(__dirname, '..', 'dist')

module.exports = smart(webpackCommonConf, {
    mode: 'development',// 开发模式
    module: {
        rules: [
            {
                test: /\.(png|jpg|jpeg|gif)$/,
                use: 'file-loader'
            }
        ]
    },
    plugins: [
        new webpack.DefinePlugin({
            // window.ENV = 'development'
            ENV: JSON.stringify('development')
        })
    ],
    devServer: {
        port: 8080,
        progress: true,  // 显示打包的进度条
        contentBase: distPath,  // 根目录
        open: true,  // 自动打开浏览器
        compress: true,  // 启动 gzip 压缩

        // 设置代理
        proxy: {
            // 将本地 /api/xxx 代理到 localhost:3000/api/xxx
            '/api': 'http://localhost:3000',

            // 将本地 /api2/xxx 代理到 localhost:3000/xxx
            '/api2': {
                target: 'http://localhost:3000',
                pathRewrite: {
                    '/api2': ''
                }
            }
        }
    }
})

第四步:生产环境配置

生产环境的配置要点:

  1. 设置模式为生产模式
  2. 设置打包后的输出output。打包后的代码文件加上hash戳,是为了利用浏览器缓存,只要没有新的打包,那么文件名就不变,就能命中浏览器缓存,就无须再次加载代码,优化加载速度。 webpack.prod.conf.js:
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpackCommonConf = require('./webpack.common.js')
const { smart } = require('webpack-merge')
const { distPath } = require('./paths')

module.exports = smart(webpackCommonConf, {
    mode: "production",
    output: {
        filename: 'bundle.[contentHash:8].js',  // 打包代码时,加上 hash 戳
        path: distPath,
    },
    module: {
        rules: [
            // 图片 - 考虑 base64 编码的情况
            {
                test: /\.(png|jpg|jpeg|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        // 小于 5kb 的图片用 base64 格式产出
                        // 否则,依然延用 file-loader 的形式,产出 url 格式
                        limit: 5 * 1024,
                        // 打包到 img 目录下
                        outputPath: '/img1/',
                    }
                }
            },
        ]
    },
    plugins: [
        new CleanWebpackPlugin(), // 会默认清空 output.path 文件夹
        new webpack.DefinePlugin({
            // window.ENV = 'production'
            ENV: JSON.stringify('production')
        })
    ]
})