从零学习webpack5(上)

311 阅读10分钟

相关阅读:webpack5高级配置
案例代码仓库:Github地址

一、基本概念

1、概念

webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容

2、核心概念

(1)entry:入口配置
(2)output:输出配置
(3)module(loader):加载器配置
(4)plugin:插件配置
(5)mode:模式配置 ,分为开发模式(development),生产模式(production)

二、初始化项目

1、初始化项目,创建基本项目结构

(1)初始化项目

由于web是运行在node环境中的,因此我们需要先使用npm init -y命令初始化一个项目,然后创建最基本的目录结构如下:
image.png

(2)项目结构分析

config/webpack.dev.js:配置开发环境的配置文件
config/webpack.prod.js:配置生产环境的配置文件
public/index.html:项目代码运行的页面
src/index.js:打包的入口文件
package.json:包管理文件

2、安装运行webpack

(1)安装webpack

npm i webpack webpack-cli --save-dev

(2)运行webpack

当我们在项目中局部安装webpack后,运行webpack需要使用npx来运行webpack,npx可以自动帮我们找到webpack可运行的文件夹运行webpack,此时我们还未配置webpack的配置文件,我们使用命令启动打包程序,在根目录下运行以下代码,其中mode是指定开发环境还是生产环境

npx webpack ./src/index.js --mode=development

此时运行成功后根目录下会出现一个dist文件夹,里面有一个main.js文件,此时代表实现了第一步,webpack正常运行,第一次打包成功。

3、使用配置文件打包

(1)使用配置文件打包命令

如果执行npx webpack进行打包,webpack默认识别的配置文件是根目录下的webpack.config.js,如果我们想指定配置文件打包,需要使用以下命令,其中配置文件的相对路径是相对于当前项目的根目录

npx webpack --config 配置文件的相对路径

例如,我们当前项目的代码结构已经建好两个配置文件,在config文件夹中,所以如果我们想要根据配置文件打包,我们可以执行以下代码,当然我们现在配置文件中还没有任何内容,执行此命令会报错,后续我们会继续介绍配置文件具体配置内容。

// 打包开发环境
npx webpack --config ./config/webpack.dev.js

// 打包生产环境
npx webpack --config ./config/webpack.prod.js

(2)配置打包命令的快捷命令

通过配置package.json中的script属性可以简化打包命令,简化后我们运行npm run serve就可以打包开发环境代码,运行npm run build就可以打包生产环境代码

{
  "name": "webpack_001",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "serve": "npx webpack --config ./config/webpack.dev.js",
    "build": "npx webpack --config ./config/webpack.prod.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.88.1",
    "webpack-cli": "^5.1.4"
  }
}

三、常用基础配置

1、入口(entry)、出口(output),模式(mode)配置

(1)入口配置

入口配置开发环境和生产环境配置相同,分为单入口打包和多入口打包
单入口打包

module.exports = {
    // 入口配置
    entry: './src/index.js'
}

多入口打包

module.exports = {
    // 多入口入口配置,index和app是自定义的名称
    entry: {
        index: './src/index.js',
        app: './src/app.js'
    }
}

(2)出口配置

出口配置开发环境和生产环境略有不同,开发环境后续我们会使用webpack-dev-server进行运行,因此不会产生具体文件,不用配置输出路径和清空打包文件夹,只需要指定文件名即可(注:[name]是webpack的命名方式,默认是main,当入口为多文件入口时,可用于区分打包后文件,此时打包后的文件名就是多入口时配置的自定义名称)
开发环境

module.exports = {
    // 入口配置
    entry: './src/index.js',
    // 出口配置
    output: {
        // 输出路径
        path: undefined,
        // 输出文件名
        filename: 'js/[name].js',
    }
}

生产环境,clean: true的配置,可以使每次打包前清空上次打包内容

const path = require('path')

module.exports = {
    // 单入口配置
    entry: './src/index.js',
    // 出口配置
    output: {
        // 输出路径
        path: path.resolve(__dirname, '../dist'),
        // 输出文件名
        filename: 'js/[name].js',
        // 清空输出目录
        clean: true
    }
}

(3)模式配置

模式配置就是生产环境和开发环境的配置,只需要在module.exports添加mode属性就好
开发模式

module.exports = {
    // 入口配置
    entry: './src/index.js',
    // 出口配置
    output: {
        // 输出路径
        path: undefined,
        // 输出文件名
        filename: 'js/[name].js',
    },
  	// 模式
    mode: 'development'
}

生产模式

const path = require('path')

module.exports = {
    // 单入口配置
    entry: './src/index.js',
    // 出口配置
    output: {
        // 输出路径
        path: path.resolve(__dirname, '../dist'),
        // 输出文件名
        filename: 'js/[name].js',
        // 清空输出目录
        clean: true
    },
  	// 模式
    mode: 'production'
}

以上这些就是最基本的配置,如果是单入口配置,运行npm run build之后,将在根目录下输出dist/js文件夹,内部输出main.js。如果是多入口配置,则在dist/js文件夹下输出index.js和app.js。

2、加载器(loader)配置

加载器配置是在module.exports中配置module属性,下面我们都以单入口为例

(1)webpack5资源处理介绍

资源模块(asset module)是webpack5新增的一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。加载器的配置无法绕过对项目中资源文件的处理,因此也无法绕过对该模块的了解,下面我们介绍以下资源模块的具体模块类型,一共分成四种。

  1. asset/resource:发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
  2. asset/inline:导出一个资源的 data URI。之前通过使用 url-loader 实现。
  3. asset/source:导出资源的源代码。之前通过使用 raw-loader 实现。
  4. asset:在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。

(2)处理样式文件加载器

webpack无法处理css,less,sass,scss这样的样式文件,因此想要打包处理这些文件就需要配置其他的loader去处理,这里我们已处理css,less文件为例,配置相关loader。首先我们要安装对应loader,需要安装的包有less,less-loader,css-loader,style-loader。(:这样处理的样式文件将会被输出为html中的style标签中,要想生成单独文件还需要配置css插件,详情见插件配置)
安装包

npm i less less-loader css-loader style-loader --save-dev

配置

module.exports = {
    // 模块配置
    module: {
        // 规则
        rules: [
            // 处理css,less文件
            {
                // 匹配文件
                test: /\.(css|less)$/,
                // 使用的loader
                use: [
                    // 将js的样式内容插入到style标签中
                    'style-loader',
                    // 将css转换为js
                    'css-loader',
                    // 将less转换为css
                    'less-loader'
                ]
            }
        ]
    }
}

(3)处理图片加载器

配置图片加载器,我们将用到asset模块的默认模块类型,即asset类型,并且我们配置当图片大小小于8kb时,将图片转为base64格式。图片文件将输出在dist/image文件夹中,生成的文件名将已配置格式输出,其中[name]是原文件名,[hash:8]是随机生成的8位哈希值,[ext]是文件扩展名,保持原文件不变

module.exports = {
    // 模块配置
    module: {
        // 规则
        rules: [
            // 处理图片,小于8kb的图片转为base64格式
            {
                test: /\.(png|jpe?g|gif|webp|svg)$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024
                    }
                },
              	// 生成文件名
                generator: {
                    filename: 'image/[name].[hash:8][ext]'
                }
            }
        ]
    }
}

(4)处理字体文件及其他媒体文件

配置字体文件及其他媒体文件时,我们将用到asset模块的asset/resource模块类型

module.exports = {
    // 模块配置
    module: {
        // 规则
        rules: [
            // 处理字体文件及其他媒体文件
            {
                test: /\.(woff2?|eot|ttf|otf|mp3|mp4|avi)$/,
                type: 'asset/resource',
                // 生成文件名
                generator: {
                    filename: 'media/[name].[hash:8][ext]'
                }
            }
        ]
    }
}

(5)处理js兼容性问题

一些低版本浏览器不兼容es6语法,因此需要配置将es6转成es5的加载器,不过当前加载器只能转一般的es6语法,像promise,await、asyn,这些高级语法无法转换,需要额外配置(详情见另一篇文章:《webpack5高级配置》)。
安装babel-loader @babel/core @babel/preset-env

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

配置babel-loader

module.exports = {
    // 模块配置
    module: {
        // 规则
        rules: [
            // 配置babel,将ES6+转换为ES5
            {
                test: /\.js$/,
                // 排除node_modules目录下的文件
                exclude: /node_modules/,
                use: [
                    {
                        // 使用babel-loader
                        loader: 'babel-loader',
                        // 配置babel
                        options: {
                            // 预设
                            presets: [
                                // 预设包含了ES6、7、8的语法转换规则
                                '@babel/preset-env'
                            ]
                        }
                    }
                ]
            }
        ]
    }
}

(6)配置html-loader

html-loader可以对html中引用的资源进行打包
安装

npm install html-loader --save-dev

配置

module.exports = {
    // 模块配置
    module: {
        // 规则
        rules: [
            // 处理html中的资源引用
            {
                test: /\.html$/,
                // 使用html-loader
                loader: 'html-loader'
            }
        ]
    }
}

3、插件(plugin)配置

Webpack 拥有丰富的插件接口。webpack 自身的大部分功能都使用这些插件接口,这使得 webpack 很灵活。插件配置需要配置module.exports中的plugin属性

(1)配置html插件

html-webpack-plugin插件将为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的js文件,如果你有多个 webpack 入口,他们都会在已生成 HTML 文件中的

npm install html-webpack-plugin --save-dev

配置插件

// 引入html-webpack-plugin插件
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    // 配置插件
    plugins: [
        // 生成html文件插件
        new HtmlWebpackPlugin({
            // 模板文件
            template: './public/index.html',
            // 输出文件名
            filename: 'index.html',
        })
    ]
}

(2)配置css插件

之前配置css加载器之后,会将样式直接以style的方式放入html中,现在我们需要将css文件生成一个单独的文件并用link的方式引入,则需要配置mini-css-extract-plugin插件。我们当前的许多css3的新样式属性,一些老的浏览器并不支持,因此我们需要使用postcss-preset-env插件将其转成可兼容的样式
安装相应的包

npm i postcss-loader postcss postcss-preset-env mini-css-extract-plugin --save-dev

配置mini-css-extract-plugin插件

// 引入mini-css-extract-plugin插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    // 配置插件
    plugins: [
        // 提取css文件插件
        new MiniCssExtractPlugin({
            // 输出文件名
            filename: 'style/[name].css'
        })
    ]
}

修改less,css加载器

module.exports = {
    // 模块配置
    module: {
        // 规则
        rules: [
            // 处理css,less文件
            {
                // 匹配文件
                test: /\.(css|less)$/,
                // 使用的loader
                use: [
                    // 将css提取为单独的文件
                    MiniCssExtractPlugin.loader,
                    // 将css转换为js
                    'css-loader',
                    // 使用postcss-loader
                    {
                        loader: 'postcss-loader',
                        // 配置postcss
                        options: {
                            // 使用插件
                            postcssOptions: {
                                // 使用预设包
                                plugins: ['postcss-preset-env']
                            }
                        }
                    },
                    // 将less转换为css
                    'less-loader'
                ]
            }
        ]
    }
}

(3)配置eslint插件

该插件使用 eslint 来查找和修复 JavaScript 代码中的问题,配置该插件后我们需要在项目根目录中新建.eslintrc.js和.eslintignore两个文件,.eslintrc.js用于配置eslint规则,.eslintignore用于忽略eslint需要检查的文件,eslint具体配置请参考eslint中文官网 安装插件

npm install eslint eslint-webpack-plugin --save-dev

配置插件

// 引入eslint-webpack-plugin插件
const EslintWebpackPlugin = require('eslint-webpack-plugin')

module.exports = {
    // 配置插件
    plugins: [
        // eslint插件
        new EslintWebpackPlugin({
            // eslint检查的文件, 只检查src目录下的文件
            context: path.resolve(__dirname, '../src')
        })
    ]
}

4、开发环境,webpack-dev-server配置

webpack-dev-server 是一个用于开发环境的轻量级服务器,使用webpack-dev-server可以在本地启动一个本地服务,当我们修改代码时不需要重新打包,便可以自动更新修改内容,并展示在页面上。

(1)devServer基础配置

安装webpack-dev-server包

npm i webpack-dev-server --save-dev

配置webpack.dev.js

module.exports = {
    // 开发服务器配置
    devServer: {
        // 服务器启动域名
        host: '127.0.0.1',
        // 端口号
        port: 3000
    }
}

修改package.json启动开发环境的命令

"scripts": {
    "serve": "npx webpack server --config ./config/webpack.dev.js",
    "build": "npx webpack --config ./config/webpack.prod.js"
  }

(2)devServer高级配置

配置服务器根目录

module.exports = {
    // 开发服务器配置
    devServer: {
        // 服务器根目录
        static: {
            directory: path.join(__dirname, '../dist'),
        }
    }
}

配置是否开启压缩,开启后可使资源传输更快

module.exports = {
    // 开发服务器配置
    devServer: {
        // 开启gzip压缩
        compress: true
    }
}

将host配置成0.0.0.0,此时同局域网内的其他用户可以通过你的ip地址+端口号访问你的服务

module.exports = {
    // 开发服务器配置
    devServer: {
        // 服务器启动域名,配置为0,0,0,0
      	// 相同局域网内所有人都可以通过你的当前ip访问你的服务
        host: '0.0.0.0'
    }
}

开启HMR功能,作用是当我们修改代码时会局部更新,不会刷新整个页面,提升开发效率

module.exports = {
    // 开发服务器配置
    devServer: {
        // 开启HMR功能, 作用是局部更新,不会刷新整个页面,提升开发效率
        hot: true
    }
}

开启historyApiFallback,true表示任意的404响应都可能需要被替代为index.html

module.exports = {
    // 开发服务器配置
    devServer: {
        // historyApiFallback: true表示任意的404响应都可能需要被替代为index.html
        historyApiFallback: true
    }
}

配置头部信息headers,给响应头配置一些自定义配置例如

module.exports = {
    // 开发服务器配置
    devServer: {
        // 配置headers
        headers: {
            'X-Access-Token': 'harbour-bro2'
        }
    }
}

配置proxy代理,解决跨域请求问题,例如:

module.exports = {
    // 开发服务器配置
    devServer: {
        // 配置代理
        proxy: {
            // 当请求路径以/api开头时,开发服务器会代理转发请求到目标服务器
            '/api': {
                // 目标服务器地址
                target: 'http://localhost:3000',
                // 开启代理服务器
                changeOrigin: true,
                // 重写路径
                pathRewrite: {
                    '^/api': '/app'
                },
                // 禁用对目标服务器的安全验证
                secure: false
            }
        }
    }
}

配置自动打开浏览器

module.exports = {
    // 开发服务器配置
    devServer: {
        // 配置是否自动打开浏览器
        open: false
    }
}

(3)devServer完整配置

// 引入path模块
const path = require('path')

module.exports = {
    // 开发服务器配置
    devServer: {
        // 服务器根目录
        static: {
            directory: path.join(__dirname, '../dist'),
        },
        // historyApiFallback: true表示任意的404响应都可能需要被替代为index.html
        historyApiFallback: true,
        // 开启gzip压缩
        compress: true,
        // 服务器启动域名,配置为0,0,0,0相同局域网内所有人都可以通过你的当前ip访问你的服务
        host: '0.0.0.0',
        // 端口号
        port: 8000,
        // 开启HMR功能, 作用是局部更新,不会刷新整个页面,提升开发效率
        hot: true,
        // 配置headers
        headers: {
            'X-Access-Token': 'harbour-bro2'
        },
        // 配置代理
        proxy: {
            // 当请求路径以/api开头时,开发服务器会代理转发请求到目标服务器
            '/api': {
                // 目标服务器地址
                target: 'http://localhost:3000',
                // 开启代理服务器
                changeOrigin: true,
                // 重写路径
                pathRewrite: {
                    '^/api': '/app'
                },
                // 禁用对目标服务器的安全验证
                secure: false
            }
        },
        // 配置是否自动打开浏览器
        open: false
    }
}

四、总结

本篇文章介绍了webpack5的基础常用配置,如需常用优化相关配置,请查阅《webpack5高级配置》一文。