Webpack配置详解

一些简单的配置说明

Featured image

介绍

Webpack 是一个模块打包器。 在Webpack看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理

它可以做到:

  1. 捆绑 ES 模块、CommonJS 和 AMD 模块(甚至它们的组合)。
  2. 可以创建在运行时异步加载的单个包或多个块(以减少初始加载时间)。
  3. 在编译期间解决依赖关系,从而减少运行时大小。
  4. 加载器可以在编译时预处理文件,例如 TypeScript 到 JavaScript,Handlebars 字符串到编译函数,图像到 Base64 等。
  5. 高度模块化的插件系统,可以满足您的应用程序需要的任何其他需求。

Webpack 支持所有符合 ES5 的浏览器(不支持 IE8 及以下版本)

安装

用npm安装:

npm install webpack webpack-cli -D

或者用yarn安装:

yarn add webpack webpack-cli -D

这样就将 webpack 放入 devDependencies 依赖中。

入口起点(entry)

默认入口起点是 ./src/index.js,也可以在 webpack.config.js 中配置 entry 来指定一个或多个入口起点。

简单写法:

module.exports = {
    // 指定入口起点
    entry: './src/app.js',
};

完整写法:

module.exports = {
    entry: {
        main: './src/app.js'
    }
};

输出(output)

output属性指定 webpack 输出它创建的 bundle 的位置,以及如何命名。 输出文件的默认值是:./dist/main.js,生成的其他文件默认放置在 ./dist 文件夹中。 也可以在 webpack.config.js 中配置 output。

const path = require('path');

module.exports = {
    entry: './src/app.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-webpack.bundle.js',
    }
};

loader

webpack 默认只能识别 JavaScript 和 JSON 文件。 loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 module,以供应用程序使用,以及被添加到依赖图中。 通过 loader 能让你是用很多新的功能。

loader 的规则有两个属性:

webpack.config.js 中配置 loader。

const path = require('path');

module.exports = {
  output: {
    filename: 'my-webpack.bundle.js',
  },
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
};

以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:testuse

插件(plugin)

插件相比预设可以执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

如果插件和预设同时处理某段代码,会按这个规则:

想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。

webpack.config.js 中配置 plugin

module.exports = {
    plugins: [new PluginA()],
};

模式(mode)

可以将 mode 参数设为 development, productionnone 之中的一个,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production。

webpack.config.js 中配置 mode

module.exports = {
  mode: 'production',
};

应用

打包less资源

安装less相关库

npm install css-loader style-loader less-loader less -D

webpack.config.js 中配置 loader

const path = require('path');

module.exports = {
  module: {
    rules: [
        {
            // 检查文件是否以.less结尾(检查是否是less文件)
            test: /\.less$/, 
            use: [  
                // 创建style标签,添加上js中的css代码
                'style-loader', 
                 // 将css以commonjs方式整合到js文件中
                'css-loader',
                // 将less文件解析成css文件
                'less-loader'  
            ]
        }
    ],
  },
};

js转换:配置Babel

Babel 是一个Javascript编译器,可以让你不用考虑浏览器兼容问题,直接使用 ES6/7/8/9等 写代码。 babel可以做这些事:

使用babel一般会安装这几个库:

用npm安装:

npm i --save-dev babel-loader babel-core babel-preset-env

或者用yarn安装

yarn add -D babel-loader babel-core babel-preset-env

接下来更改 webpack-config.js 中的代码

module.exports = {
    module: {
        rules: [
            {
                // js 文件才使用 babel
                test: /\.js$/,
                // 使用哪个 loader
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
                // 不包括路径
                exclude: /node_modules/
            }
        ]
    }
}

配置 Babel 有很多方式,这里使用 .babelrc 文件管理, 放在项目根目录。

{
    // Babel 的预设(preset)可以被看作是一组 Babel 插件和/或 options 配置的可共享模块。
    // Preset数组 是逆序排列的(从后往前执行)
    "presets": ["babel-preset-env"]
}

js兼容性处理:配置polyfill

解决babel只能转换部分低级语法的问题(如:let/const/解构赋值…),引入polyfill可以转换高级语法(如:Promise…), 但是会转换全部的高级语法,可以通过cire-js实现按需引入来解决这个问题。

npm install @babel/polyfill
npm install core-js

webpack.config.js 中配置 loader


module.exports = {
  module: {
    rules: [
        {
            test: /\.js$/,
            exclude: /(node_modules)/,
            use: {
            loader: 'babel-loader',
            options: {
                presets: [
                    [
                        '@babel/preset-env',
                        {
                            // 按需引入需要使用polyfill
                            useBuiltIns: 'usage',  
                            // 解决warn
                            corejs: { version: 3 }, 
                            // 指定兼容性处理哪些浏览器
                            targets: { 
                                "chrome": "58",
                                "ie": "9",
                            }
                        }
                    ]
                ],
                // 开启babel缓存
                cacheDirectory: true, 
            }
            }
        },
    ],
  },
};

处理图片

通过 url-loader 处理图片 url-loader是对象file-loader的上层封装,使用时需配合file-loader使用。

npm install file-loader url-loader -D

webpack.config.js 中配置 loader


module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        // 8kb --> 8kb以下的图片会base64处理
                        limit: 8192, 
                        // 决定文件本地输出路径
                        outputPath: 'images', 
                        // 决定图片的url路径
                        publicPath: '../build/images',  
                        // 修改文件名称 [hash:8] hash值取8位. [ext] 文件扩展名
                        name: '[hash:8].[ext]' 
                    }
                }
            },
        ],
    },
};

打包html文件

需要用html-webpack-plugin这个库实现, 注意不要在html中引入任何css和js文件。

npm install html-webpack-plugin -D

webpack.config.js 中配置 plugin

const HtmlWebpackPlugin = require('html-webpack-plugin');
// 用于访问内置插件
const webpack = require('webpack'); 

module.exports = {
    module: {
        rules: [{ test: /\.txt$/, use: 'raw-loader' }],
    },
    plugins: [new HtmlWebpackPlugin(
        { 
            // 以当前文件为模板创建新的HtML(1. 结构和原来一样 2. 会自动引入打包的资源)
            template: './src/index.html' 
        }
    )],
};

在上面的示例中,html-webpack-plugin插件 为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中

要过还要处理打包html里的图片资源,加上这个:

npm install html-loader -D

webpack.config.js 中配置 loader

module.exports = {
    module: {
        rules: [
            {
                test: /\.(html)$/,
                use: {
                    loader: 'html-loader'
                }
            }
        ]
    }
}

打包其他资源(字体,音视频等)

webpack.config.js 中配置 loader

module.exports = {
    module: {
        rules: [
            {
                test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,  // 处理其他资源
                loader: 'file-loader',
                options: {
                    outputPath: 'media',
                    name: '[hash:8].[ext]'
                }
            }
        ]
    }
}

自动编译打包

dev安装依赖库:webpack-dev-server

npm install webpack-dev-server -D

webpack.config.js 中配置

module.exports = {
    devServer: {
        // 自动打开浏览器
        open: true, 
        // 启动gzip压缩
        compress: true, 
        // 端口号
        port: 3000, 
    }
}

因为构建工具以build为根目录,需要改下url-loader的配置: publicPath: '../build/images/' 改为 publicPath: 'images/'

示例如下

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        // 8kb --> 8kb以下的图片会base64处理
                        limit: 8192, 
                        // 决定文件本地输出路径
                        outputPath: 'images', 
                        // 决定图片的url路径
                        publicPath: 'images/',  
                        // 修改文件名称 [hash:8] hash值取8位. [ext] 文件扩展名
                        name: '[hash:8].[ext]' 
                    }
                }
            },
        ],
    },
    devServer: {
        // 自动打开浏览器
        open: true, 
        // 启动gzip压缩
        compress: true, 
        // 端口号
        port: 3000, 
    }
};

因为webpack-dev-server指令才能启动devServer配置, 因此修改package.json里的scripts:

"scripts": {
    "start": "webpack-dev-server"
}

热更新(HMR)

热更新是webpack提供的最有用的功能之一。它允许在运行时更新变化的所有类型的模块,而无需完全刷新。

示例如下

module.exports = {
    entry: ['./src/app.js', './src/index.html']
    devServer: {
        // 运行项目的目录
        contentBase: resolve(__dirname, 'build'), 
        // 自动打开浏览器
        open: true, 
        // 启动gzip压缩
        compress: true, 
        // 端口号
        port: 3000,
        // 开启热模替换功能 HMR,从 webpack-dev-server v4.0.0 开始,热模块替换是默认开启的。
        hot: true
    }
};

TypeScript

首先,执行以下命令安装 TypeScript compiler 和 loader:

npm install -D typescript ts-loader

在工程个目录加一个配置文件:tsconfig.json, 配置如下:

{
    "compilerOptions": {
        // 输出目录
        "outDir": "./dist/",
        // 没有任何隐含的。 打开后在Typescript无法推导类型时会提醒错误
        "noImplicitAny": true,
        // 模块。配置项有:CommonJS,UMD,AMD,System,ESNext,ES2020 ES2015/ES6,node16/ nodenext,None。
        "module": "es6",
        // 目标。和运行环境有关,如果在旧的环境,建议设置的低一点
        "target": "es5",
        // 声明导入jsx和jsxs工厂函数的模块说明符
        "jsx": "react",
        // 检查JS。打开后,将在 JavaScript 文件中报告错误
        "allowJs": true,
        // 模块分辨率。可选项有:'node','node12','classic'
        "moduleResolution": "node"
    }
}

完整的配置项可以参考:TSConfig参考

配置 webpack 处理 TypeScript: webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.ts',
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
};