webpack基础配置及常用loader

webpack基础

环境要求

  • webpack版本:5.1.4
  • node版本:20.15.1
  • 因版本差异,相关配置会有一定出入

安装本地的webpack

npm i webpack webpack-cli -D

webpack默认配置

  • 默认可以不用配置,在src下新建一个index.js文件(默认),执行npx webpack即可打包
  • 支持我们的js模块化-CommonJS和ES Module规范
// a.js
export default 'webpack'

// index.js
import str from './a.js'
console.log(str)

// 验证打包,创建index.html文件,引入打包后的js文件,即可验证

webpack手动配置

  • 默认配置文件的名字是webpack.config.js
  • 自定义配置文件webpack.config.customer.js
const path = require('path')

module.exports = {
    mode: 'production',
    performance: {
        maxEntrypointSize: 50000000, // 打包体积限制,若hints打开,超出有警告或报错
        maxAssetSize: 30000000, // 打包体积限制,若hints打开,超出有警告或报错
        hints: false // warning、error、false(boolean),打开/关闭提示
    },
    entry: {    // 配置多入口
        'home': './src/index.js',
        'other': './src/other.js'
    },
    output: {
        filename: 'js/[name].[contenthash:8].js',  // webpack5以下版本用[hash]
        path: path.resolve(__dirname, 'dist'), //路径必须是一个绝对路径
        publicPath: '',  // 会在路径前面添加上相应的字符串
        clean: true, // 在生成文件之前清空 output 目录,webpack5以下需要使用clean-webpack-plugin插件
    },
}
  • 通过配置脚本运行(package.json)
# package.json配置
"build":"webpack --config webpack.config.customer.js"
# 运行
npm run build

# package.json配置
"build":"webpack"
npm run build -- --config webpack.config.customer.js

webpack-dev-server

  • 将文件写到内存中,提高打包速度

  • 安装及使用

# 安装
npm install webpack-dev-server -D
# 使用
npx webpack-dev-server
  • 通过配置脚本运行(package.json)
# 配置
"dev": "webpack-dev-server"
# 使用
npm run dev
  • webpack.config.js配置
devServer: {
    port: 3001, // 服务端口
    host: '0.0.0.0', // 服务器可以被外部访问
    client: {
        progress: true, // 在浏览器中以百分比显示编译进度
    },
    static: './dist/', // 从目录提供静态文件的选项(默认是 'public' 文件夹)
    compress: true, // 是否启用gzip压缩
    hot: true,
    proxy: [{
        context: ['/api'],
        target: 'http://localhost:3000',
    }],
},
devtool:'source-map'
  • 源码报错映射-devtool,开发环境推荐使用eval-source-map, 生产环境推荐使用source-map
  1. devtool:‘source-map’ 源码映射,会单独生成一个sourcemap文件,出错了,会标识当前错误的列和行;

  2. devtool:‘eval-source’ 不会产生单独的文件,但是可以显示行和列

  3. devtool:‘cheap-module-source-map’ 不会产生列,但是是一个单独的映射文件产生后你可以保留起来

  4. devtool:‘cheap-module-eval-source-map’ 不会产生文件,集成在打包后的文件中,也不会产生列

html-webpack-plugin

  • 安装方式
npm i html-webpack-plugin -D
  • webpack.config.js配置
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');

plugins: [
    //放着所有的webpack插件
    new HtmlWebpackPlugin({
        template: './src/index.html',
        filename: 'index.html',
        //对打包的html页面进行最小化操作
        minify: {
            removeAttributeQuotes: true, //删除属性的双引号
            collapseWhitespace: true //所有代码一行显示,折叠空行
        },
        hash: true //在引入js文件时,在路径后面添加hash戳
    }),
]

webpack常用loader

webpack样式处理

  • 处理css相关的loader及规则
#    css-loader,处理@import这种语法
#    style-loader 他是把css插入到head的标签中
#    loader的特点,希望单一
#    loader的用法,字符串只用一个loader,多个loader需要[]
#    loader的顺序,默认时从右向左执行,从下往上执行
#    loader还可以写成对象的方式

# 处理less文件
npm i less less-loader -D
# 处理sass文件
npm i node-sass sass-loader -D
# 处理stylus文件
npm i stylus stylus-loader -D
  • (style-loader)将打包后的css内容添加到head头部,以style标签的形式包裹(不推荐)
# 处理样式文件
npm i style-loader -D
  • (style-loader)webpack.config.js增加文件处理规则
module: {
    rules: [{
        test: /\.css$/,
        use: [
            {
                loader: 'style-loader', options: {
                    insert: 'head',  // head body
                    injectType: "styleTag" // linkTag
                }
            }, 'css-loader']
    },
    {
        test: /\.less$/,
        use: [
            {
                loader: 'style-loader', options: {
                    insert: 'head',  // head body
                    injectType: "styleTag" // linkTag
                }
            },
            'css-loader',
            'less-loader'
        ]
    }]
}
  • (link标签引入)将css单独打包成一个文件
//使用link标签引入打包后的css文件
npm i mini-css-extract-plugin -D
  • (link标签引入)webpack.config.js增加文件处理规则修改
import MiniCssExtractPlugin from 'mini-css-extract-plugin'

module: {
    rules: [{
        test: /\.css$/,
        use: [
            MiniCssExtractPlugin.loader,
            'css-loader'
        ]
    },
    {
        test: /\.less$/,
        use: [
            MiniCssExtractPlugin.loader,
            'css-loader',
            'less-loader'
        ]
    }]
}
  • (postcss)CSS新特性、样式前缀等优雅降级(postcss-preset-env基于postcss框架,它的工作原理是对你的CSS源码进行解析,然后将尚未被所有浏览器广泛支持的新特性转换为已知的、安全的CSS代码片段。通过这种方式,你可以放心地使用如Grid布局、Flexbox、颜色空间等新功能,而不需要担心浏览器的差异化问题,postcss-preset-env已经内置了autoprefixer的特性)
npm i postcss postcss-loader postcss-preset-env -D
  • (postcss)webpack.config.js增加postcss-loader处理
rules: [{
    test: /\.css$/,
    use: [
        MiniCssExtractPlugin.loader,
        'css-loader',
        'postcss-loader',
    ]
},
{
    test: /\.less$/,
    use: [
        MiniCssExtractPlugin.loader,
        'css-loader',
        'postcss-loader',
        'less-loader'
    ]
}]
  • (postcss)在项目根目录新建一个postcss.config.js文件
module.exports = {
	plugins: [
		require('postcss-preset-env')({
			browsers: [	// 添加前缀的浏览器列表
				"> 1%",
				"Chrome > 31",
				"Firefox > 31",
				"ie >= 10",
				"last 10 versions"
			],
			autoprefixer: { grid: true },	// grid布局是否添加前缀
		}),
	],
};
  • 通过以上配置,打包出来的css文件并没有被压缩,如需压缩,则需要安装css-minimizer-webpack-plugin插件,使用该优化后,css文件内容可以压缩了,但是js文件并没有压缩,需手动压缩js
# css压缩,
npm install css-minimizer-webpack-plugin -D
# js压缩
npm i terser-webpack-plugin -D
  • webpack.config.js配置项添加
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');

optimization: {
    minimizer: [
        new CssMinimizerPlugin({    // 优化css
            parallel: true,         // 多进程并发执行,提升构建速度
        }),
        new TerserJSPlugin({        // 优化js
            parallel: true,
            terserOptions: {
                compress: {
                    drop_console: false,    // 移除console
                    drop_debugger: true,   // 移除debugger
                },
            },
        }),
    ],
},

webpack静态资源

  • 一般项目中url-loader和file-loader结合使用,url-loader可以转换为base64

  • url-loader可以处理我们的图片、音视频、字体等静态资源路径

  • 依赖包安装

npm i url-loader file-loader -D
  • 当在 webpack 5 中使用旧的 assets loader(如 file-loader/url-loader/raw-loader 等)和 asset 模块时,你可能想停止当前 asset 模块的处理,并再次启动处理,这可能会导致 asset 重复,你可以通过将 asset 模块的类型设置为 'javascript/auto' 来解决
  • webpack.config.js增加解析规则,分类打包静态资源
{
    test: /\.(png|jp?g|gif|svg)(\?.*)?$/,
    type: 'javascript/auto',
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: 10 * 1024,
                esModule: false,
                outputPath: "images"
            }
        }
    ],
},
{
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    type: 'javascript/auto',
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: 10 * 1024,
                esModule: false,
                outputPath: "fonts"
            }
        }
    ],
},
{
    test: /\.(mp4?|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
    type: 'javascript/auto',
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: 10 * 1024,
                esModule: false,
                outputPath: "medias"
            }
        }
    ],
}
  • 在js中使用(一)
import webpackLogo from './assets/images/logo.png'
const img = document.createElement('img')
img.src = webpackLogo
document.body.appendChild(img)
  • 在css中使用(二)
@font-face {
  font-family: DIGITAL-Regular;
  src: url("./assets/fonts/DIGITAL-Regular.ttf");
}
.test-box {
  font-family: DIGITAL-Regular;
  background: url("./assets/images/logo.png") center bottom no-repeat;
}
  • 在html中使用,一般不使用(三)
# 在我们的模板html中使用,需再安装一个loader
npm i html-withimg-loader -D

增加配置项

{
	test: /\.html$/,
	use: 'html-withimg-loader'
}

在html中使用

<img src="./assets/images/logo.png" />

webpack转换es6语法

  • 相关包安装
npm i babel-loader @babel/core @babel/preset-env -D
  • webpack.config.js添加loader处理
{
    test: /\.m?js$/,
    include: path.resolve(__dirname, 'src'),
    exclude: /node_modules/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['@babel/preset-env'],
        },
    },
},
  • @babel/plugin-transform-runtime使用场景
  1. 避免全局污染:
    当使用 Babel 转译包含新特性的代码(如箭头函数、解构赋值、模板字符串等)时,Babel 通常会生成辅助函数(helper functions)以实现这些特性的向下兼容。如果不使用 @babel/plugin-transform-runtime,这些辅助函数会被直接注入到每个转译后的文件中,可能导致全局作用域被污染。而该插件会将这些辅助函数集中放在一个单独的运行时库(如 @babel/runtime)中,通过模块导入的方式使用,从而避免全局污染。
  2. 按需引入 polyfills:
    对于 ECMAScript 标准库中新增的 API(如 PromiseSetMapArray.from 等),@babel/plugin-transform-runtime 会自动识别并替换为运行时库提供的同名函数,而不是在全局范围内添加 polyfills。这样可以确保只对实际用到的 API 进行 polyfill,减小最终生成代码的体积,提高加载效率。
  3. 保持模块化:
    对于使用模块化(如 CommonJS 或 ES modules)的项目,@babel/plugin-transform-runtime 有助于保持模块化的语义。通过引入对应的运行时模块,而不是直接在全局添加 polyfills 或辅助函数,可以确保模块间的独立性和互不影响。
  • 依赖包安装(转换插件通常仅在开发中使用,但运行时是生产依赖)
npm i @babel/plugin-transform-runtime -D
npm install @babel/runtime -S

# es6 'abdc'.includes('a')之类的语法不会识别,如果需要兼容,安装以下包
npm i core-js -S
  • 增加polyfill,兼容ES6新增的对象原型上的属性
// webpack.config.js
presets: [
  ["@babel/preset-env", {
    useBuiltIns: "entry", // or "usage"
    corejs: 3,
  }]
]

// 在使用的地方引入
import "core-js/stable";
import "regenerator-runtime/runtime";
'abdc'.includes('a')

webpack插件及其它配置

copy-webpack-plugin

  • 是一个第三方的Webpack插件,它允许你在构建过程中复制文件和目录到输出目录。通常,这在构建项目时需要将一些不需要经过Webpack处理的文件(如静态资源、HTML文件、字体文件等)复制到输出目录,以便它们可以在部署后在浏览器中访问
  • 安装copy-webpack-plugin
npm i copy-webpack-plugin -D
  • 使用copy-webpack-plugin
new CopyWebpackPlugin({
    patterns: [
        { from: 'public', to: './' },	// 将public文件夹内的内容复制到打包后的根目录下
    ],
})

BannerPlugin

  • BannerPlugin是webpack内置的一个插件,用于在打包后的文件中添加自定义注释的插件。它可以创建单独的许可文件,将许可信息添加到打包后的文件中,以便其他开发者了解和遵守相关的许可要求
  • 使用BannerPlugin
//不需要安装包,只需要引入webpack即可
let webpack = require('webpack');

//配置文件配置
plugins: [
	new webpack.BannerPlugin('Copyright (c) 2024-present LiuSong')
]

resolve的使用方法

resolve: {
    modules: [path.resolve('node_modules')], // 缩小查找范围
    extensions: ['.js', '.css', '.json', '.vue'], // 引入这些类型的文件,可以不用写后缀
    alias: {    // 别名
        '@': path.resolve(__dirname, 'src'),
        '@assets': path.resolve(__dirname, 'src/assets'),
    }
}

全局变量(webpack、node)

相关变量讲解

  • cross-envNODE_ENV还有webpack.config.js中设置的modeDefinePlugin
"scripts": {
    "dev": "cross-env NODE_ENV=development PROXY_ENV=test webpack-dev-server --config build/webpack.config.dev.js"
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.prod.js"
 },
  1. 编译环境(node环境),我们在终端执行:npm run dev 或打包 npm run build 都是在编译环境,也就是node环境。webpack.config.js是运行在编译环境中的。

  2. 运行环境(浏览器环境),我们写的业务代码等都是在浏览器中运行的,也就是打包之后我们的代码还在的。

  3. webpack.config.js中设置的mode值,只能在运行环境中通过process.env.NODE_ENV读取到,在编译环境,webpack配置文件中是读取不到的
    module.exports = { mode: 'development' }

  4. 在 webpack 4+ 中,不需要做任何设置(其实是webpack自动把变量添加到了DefinePlugin中)就可以在代码中读取process.env.NODE_ENV的值了,在 webpack3及其更低版本中,需要在webpack配置文件中使用 DefinePlugin设置成全局变量,才可以访问得到

  5. 在编译环境(webpack配置文件中使用)的环境变量,因windows和mac系统的差异,配置方式也就不同,这时就需要借助cross-env

  6. 总结:

    1. mode(值只能是none, developmentproduction)和DefinePlugin设置的变量只能在运行环境(业务代码)中使用

    2. package.json中设置的环境变量只能在编译环境中(node环境)中使用

    3. cross-env是用来解决跨环境的

  • 安装cross-env解决跨环境问题
npm install cross-env -D
  • DefinePlugin(webpack内置插件)定义运行环境全局变量
  1. 一般情况下,我们会将全局变量添加到配置文件中,在打包命令中增加编译环境全局变量,在打包时根据全局变量加载对应的配置文件,将配置文件中的变量注入到node进程中,然后在业务代码中使用

  2. 项目目录下新建config文件夹,依次增加dev.env.js、test.env.js、prod.env.js

  3. 在文件中增加变量

    1. dev.env.js module.exports = {ENV_CONFIG: '"dev"'}

    2. est.env.js module.exports = {ENV_CONFIG: '"test"'}

    3. prod.env.js module.exports = {ENV_CONFIG: '"prod"'}

  4. package.json修改运行脚本

    1. “dev”: “cross-env ENV_CONFIG=dev webpack-dev-server”,

    2. “build:test”: “cross-env ENV_CONFIG=test webpack”,

    3. “build:prod”: “cross-env ENV_CONFIG=prod webpack”

// webpack.config.js中增加插件配置
const webpack = require('webpack');
const env = require(`./config/${process.env.ENV_CONFIG}.env.js`)

new webpack.DefinePlugin({
  _WBPACK_ENV_VARIABLE: JSON.stringify(env)	// 变量名称随意起
});

// 业务代码中使用
if(_WBPACK_ENV_VARIABLE.ENV_CONFIG === 'dev') {  }
  • 经验总结
  1. 使用环境变量,能满足我们所有的开发需求,解决环境不一致而引发的问题

  2. 在实际的项目开发中,我们还可以拆分我们的打包配置文件,进行更细维度的优化整合

  3. 比如拆分配置文件为:webpack.base.js,webpack.dev.js,webpack.prod.js,依据不同的环境进行不同的打包方案

webpack整体配置项

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const env = require(`./config/${process.env.ENV_CONFIG}.env.js`)

module.exports = {
    mode: 'production',
    performance: {
        maxEntrypointSize: 50000000, // 打包体积限制,若hints打开,超出有警告或报错
        maxAssetSize: 30000000, // 打包体积限制,若hints打开,超出有警告或报错
        hints: false // warning、error、false(boolean),打开/关闭提示
    },
    devtool: 'source-map', //增加映射文件,可以帮我们调试源代码
    entry: {    // 配置多入口
        'home': './src/index.js',
        'other': './src/other.js'
    },
    output: {
        filename: 'js/[name].[contenthash:8].js',  // webpack5以下版本用[hash]
        path: path.resolve(__dirname, 'dist'), //路径必须是一个绝对路径
        publicPath: '',  // 会在路径前面添加上相应的字符串
        clean: true, // 在生成文件之前清空 output 目录,webpack5以下需要使用clean-webpack-plugin插件
    },
    devServer: {
        port: 3001, // 服务端口
        host: '0.0.0.0', // 服务器可以被外部访问
        client: {
            progress: true, // 在浏览器中以百分比显示编译进度
        },
        static: './dist/', // 从目录提供静态文件的选项(默认是 'public' 文件夹)
        compress: true, // 是否启用gzip压缩
        hot: true,
        proxy: [{
            context: ['/api'],
            target: 'http://localhost:3000',
        }],
    },
    plugins: [
        //放着所有的webpack插件
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            //对打包的html页面进行最小化操作
            minify: {
                removeAttributeQuotes: true, //删除属性的双引号
                collapseWhitespace: true //所有代码一行显示,折叠空行
            },
            chunks: ['home'],   // 将对应的打包文件对号入座
            hash: true //在引入js文件时,在路径后面添加hash戳
        }),
        new HtmlWebpackPlugin({ // 打包多个html页面
            template: './src/index.html',
            filename: 'main.html',
            chunks: ['other'],  // 将对应的打包文件对号入座
            hash: true //在引入js文件时,在路径后面添加hash戳
        }),
        new MiniCssExtractPlugin({
            // 此处写成'css/main.css',其它静态资源需根据需要添加publicPath: '../'等
            filename: '[name].[fullhash].css'  // 低版本使用[hash]
        }),
        new CopyWebpackPlugin({  // 拷贝静态文件
            patterns: [
                { from: 'public', to: './' },
            ],
        }),
        new webpack.BannerPlugin('Copyright (c) 2024-present LiuSong'),	// 添加版权或作者信息
        new webpack.DefinePlugin({	// 定义运行环境全局变量
            _WBPACK_ENV_VARIABLE: JSON.stringify(env)    // 或 '"production"' 写法
        })
    ],
    optimization: {
        minimizer: [
            new CssMinimizerPlugin({    // 优化css
                parallel: true,         // 多进程并发执行,提升构建速度
            }),
            new TerserJSPlugin({        // 优化js
                parallel: true,
                extractComments: false, //不将注释提取到单独的文件中
                terserOptions: {
                    compress: {
                        drop_console: false,    // 移除console
                        drop_debugger: true,   // 移除debugger
                    },
                },
            }),
        ],
    },
    module: {
        rules: [{
            test: /\.css$/,
            use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                'postcss-loader',
            ]
        },
        {
            test: /\.less$/,
            use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                'postcss-loader',
                'less-loader'
            ]
        },
        {
            test: /\.m?js$/,
            include: path.resolve(__dirname, 'src'),
            exclude: /node_modules/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: [['@babel/preset-env', {
                        useBuiltIns: "entry",
                        corejs: 3,
                        targets: {
                            chrome: "58",
                            ie: "11"
                        }
                    }]],
                    plugins: ["@babel/plugin-transform-runtime"]
                },
            },
        },
        {
            test: /\.(png|jp?g|gif|svg)(\?.*)?$/,
            type: 'javascript/auto',
            use: [
                {
                    loader: 'url-loader',
                    options: {
                        limit: 10 * 1024,
                        esModule: false,
                        outputPath: "images"
                    }
                }
            ],
        },
        {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            type: 'javascript/auto',
            use: [
                {
                    loader: 'url-loader',
                    options: {
                        limit: 10 * 1024,
                        esModule: false,
                        outputPath: "fonts",
                    }
                }
            ],
        },
        {
            test: /\.(mp4?|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            type: 'javascript/auto',
            use: [
                {
                    loader: 'url-loader',
                    options: {
                        limit: 10 * 1024,
                        esModule: false,
                        outputPath: "medias"
                    }
                }
            ],
        },
        {
            test: /\.html$/,
            use: 'html-withimg-loader'
        }
        ]
    },
    resolve: {
        modules: [path.resolve('node_modules')], // 缩小查找范围
        extensions: ['.js', '.css', '.json', '.vue'], // 引入这些类型的文件,可以不用写后缀
        alias: {    // 别名
            '@': path.resolve(__dirname, 'src'),
            '@assets': path.resolve(__dirname, 'src/assets'),
        }
    }
}

webpack常用优化项

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青春~不散

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值