likes
comments
collection
share

有了这些方法,webpack你也可以自己配

作者站长头像
站长
· 阅读数 28

前言

通过上篇文章——弄懂这几个概念后,我对webpack有了更新的理解 的讲解,我们大致了解了:

  • 使用webpack过程中出现的一些概念
  • 结合打包过程中出现的概念,浅析了webpack打包流程,让大家对打包流程有个大致的理解

我们都知道,我们在实际开发过程中,使用webpack无非就是为了最后输出浏览器能运行的cssimgjshtml等前端资源。

那么,为了更贴近实际,我们这篇文章,就以如何输出cssimgjshtml等前端资源为目的,学习一下如何配置webpack

学习大纲

这篇文章主要讲解以下基础配置:

  • 处理css、less文件
  • 处理图片(img)、字体(font)、音乐(audio)等前端资源文件
  • 编译es6+语法及API
  • 处理html文件

webpack文档对配置写的算挺详细了,所以这里我也不想复制粘贴又写一遍,这样不如大家直接看文档。

授人以鱼不如授人以渔,学习不能硬学,应该要有一些方法跟技巧。因此,我更想在讲解配置的过程中,总结一些方法,让我们更好的理解webpack的配置项。这样,一些类似的一些配置,我们照葫芦画瓢,看文档就可以配出来。

备注

文章涉及到的案例已经上传到 github

  • 为了阅读方便,文章只贴了相关代码,建议fork一下,看看完整代码;或者跟着文章一起边看边敲,这样印象会更深刻一些
  • 创作不易,如果觉得有帮助的话,欢迎star🌟

处理css、less文件

我们先用 learn-03 这个案例来看看webpack如何处理样式文件。

我们安装相应的loader解析:

  • less-loader:解析lesscss
  • css-loader:将css解析为webpack能识别的有效模块
  • style-loader:将解析出来的css插入到<header />
npm install less less-loader css-loader style-loader -D

然后配置一下:

// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
        ]
    }
}

loader的解析是逆序执行(或从右到左),因此这个配置会按照(less-loadercss-loaderstyle-loader)以下顺序执行:

  1. less解析成css
  2. 再将结果传给css-loader,解析成webpack认识的有效模块
  3. 再将结果传给style-loader,将解析出来的样式插入到<header />)的顺序执行。

lesscss、入口文件代码为:

// index.less
*{
    margin: 0;
    padding: 0;
}
h1{
    color: red;
    margin-top: 20px;
}

/* index.css */
h2{
    color: green;
}

// index.js
import './assets/index.less';
import './assets/index.css';

输出:

有了这些方法,webpack你也可以自己配

我们会发现我们写的样式处理成功,并且被插入到<head/>中。

总结

我们 上篇文章 说过:

  • 我们通过importrequire进来的资源文件,或我们项目中的每个文件,都可以看作为一个独立的模块
  • Loader的作用就是把这些模块(module)转换成webpack能够识别的有效模块

webpack人性化的暴露了module配置项,就是专门用来配置相关loader,以此解析相应的module。因此,如果我们想解析我们源码中使用的某些模块,我们就应该:

  • 先下载相应的loader
  • 直接找到module配置项,根据loader使用方法直接配置

所以,我们按照上面总结的方法跟思想,可以试试自己配置处理一下.scss或者.txt文件


ok,我们成功得到了我们项目需要的样式(css),接下来我们再看看如何处理图片(img)等前端资源文件

处理前端资源文件

前端资源文件很多,在这里,我们粗略的把它们先分成两类:

  • 常用类:一般就是imgfontvideo等文件
  • 特殊类:.csv.xml等文件

这些资源只要import或者require进我们的源码,那么它一样也是模块。既然是模块,我们就需要安装相应的loader进行解析,然后在module配置项配置。

wepack5之前,对于常用类的资源,我们一般需要安装以下loader来解析:

  • raw-loader:将文件解析成字符串
  • file-loader:将import/require()进来的文件,解析为一个完整引用的url,并将文件发送到输出目录中
  • url-loader:可以把文件转成base64

我们经常用到的是file-loaderurl-loader这两个。因为常用类资源,经常以url形式引入到我们项目中;或者为了减少http请求,直接转换成base64

但是webpack5后,webpack已经内置上述几个loader的功能,所以我们可以不用再安装以上的loader了;我们可以直接使用webpack自带的 asset module

webpack5之后内置的资源模块:

  • asset/source:等同于raw-loader
  • asset/resource: 等同于file-loader
  • asset/inline:等同于url-loader
  • asset:比较灵活,同时拥有asset/resourceasset/inline的功能。如果设置了文件大小限制,文件没有超出这个大小的话,会转为base64;如果没设置大小限制,则功能跟file-loader一样

这是我十分爱webpack5的原因,因为我们不要安装那么多乱七八糟的loader

我们用 learn-04 这个案例,看看怎么使用资源模块来解析我们的前端资源。

我们把上一章解析样式的配置一起加进来,在lessjs中分别使用图片资源。

我们有两个图片:

  • preview.gif:大小为349kb
  • ecj-cli.png:大小为4kb
// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                      maxSize: 1024 * 10 // 当图片 < 10kb 转成base64
                    }
                },
                generator: {
                    filename: '[name][ext]' // 设置输出的文件名字
                }
            }
        ]
    }
}

入口文件:

// index.js
import './assets/index.less';

const img = new Image();
img.src = require('./assets/ecj-cli.png');
img.width = 500;
document.querySelector('#js_logo').append(img);

样式:

.bg_logo{
    width: (1434/3px);
    height: (1212/3px);
    background-image: url('./preview.gif');
    background-size: 100%;
}

输出结果:

有了这些方法,webpack你也可以自己配

我们会发现样式跟js都处理图片成功:

  • preview.gif大于10kb,所以没有被转为base64,而是返回了一个完整的引用路径(相当于file-loader的功能)
  • ejc-cli.png小于10kb的则被转为了base64(相当于url-loader的功能)。

上面的gif图,是我开发的一个在日常项目中十分实用的命令行工具 ejc-cli 。它可以将对接人员收集的Excel数据,按一定格式转成我们代码所需要的json数据。它十分方便我们开发维护数据,并且还有跟其他人员对接数据。

感兴趣的朋友可以看看 👉🏻 了解 ejc-cli

总结

通过import或者require进我们源码的资源,一样是一种模块。所以需要下载相应的loader,然后到module配置项进行配置。

对于常用类资源(imgfontvideoaudio等等):

  • 因为常用,所以webpack5把处理它们的功能内置了,这样我们不用额外安装loader,我们直接使用asset module来管理
  • 我们一般都使用asset/resourceasset/inlineasset这几个模块来管理常用类资源。因为我们常用类的资源,经常会在我们项目中引入使用,我们需要把它们解析成引入完整的url,或者为了减少http请求,直接转换成base64

对于特殊类资源(.csv.xml等等):

  • 我们可以理解为,因为不常用,所以webpack没有把它们的功能内置
  • 因此,我们需要安装相应的loader来解析。例如我们想解析.csv文件,我们需要安装csv-loader来解析

按照上面总结的方法,可以试试自己配置处理一下video或者font等文件


好,到目前,我们已经得到了cssimg。我们接下来看看,如何通过webpack处理得到我们的js

编译es6+

时至今日,js发展迅速,为了提高开发效率和代码质量,每年都会有一些新的语法或者新的API出现。

例如,在语法方面出现了:

  • 箭头函数:()=>
  • 类语法糖:class People {}
  • 解构赋值:const [x, y] = [1, 2];
  • ...

API方面又有:

  • Promise
  • Array.prototype.includes()
  • Object.keys()
  • ...

但是这些新的内容在一些低版本浏览器上是不支持的,所以我们需要通过webpack来将我们的es6+编译成这些低版本浏览器能支持的版本。

我们先用 learn-05 这个案例,看看我们怎么配置webpack编译es6+

我们安装相关依赖:

...
"devDependencies": {
    "@babel/core": "^7.22.8",
    "@babel/plugin-transform-runtime": "^7.22.7",
    "@babel/preset-env": "^7.22.7",
    "babel-loader": "^9.1.3",
    "webpack": "^5.88.1",
    "webpack-cli": "^5.1.4"
},
"dependencies": {
    "core-js": "^3.31.1"
},

入口文件。使用了classPromise()=>{}es6+语法及API

// index.js
class People {
    constructor(name) {
        this.name = name;
    }
    sayHi() {
        return Promise.resolve(this.name);
    }
}
const Lee = new People('Lee');
Lee.sayHi().then(name => console.log(`Hi, I am ${name}.`));

配置webpack

// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    }
}

配置Babel。在项目根目录新建babel.config.js文件:

// babel.config.js
const presets = [
    [
        '@babel/preset-env',
        {
            useBuiltIns: 'usage',
            corejs: {
                version: require('core-js/package.json').version,
                proposals: true
            }
        }
    ]
];
const plugins = [
    '@babel/plugin-transform-runtime',
];
module.exports = {presets, plugins}

设置要兼容的目标浏览器。在package.json添加browserslist字段:

"browserslist": [
    "ie 11"
]

ie 11运行的结果:

有了这些方法,webpack你也可以自己配

我们会发现:

  • 我们写的es6+ie 11运行成功
  • Promise这个es6+ API,也被添加到了ie 11

说明我们编译的es6+是成功的。

关于Babel

在上面配置中,大家会发现,如果我们想用webpack编译es6+,我们还需要在根目录添加babel.config.js文件,步骤比处理其他模块要复杂麻烦的多。这是因为,编译es6+的核心,是需要Babel来配合的Babel是编译es6+的一个工具。

由于本篇文章主要是讲解webpack,所以在这里,我们对Babel就大概提一下。以下是Babel常用的一些配置。

  • 如果我们开发的项目是应用程序大型的项目,我们可以这么配置:
    const presets = [
        [
            '@babel/preset-env',
            {
                modules: false,
                useBuiltIns: 'entry', // or useBuiltIns: 'usage',
                corejs: {
                    version: '3.27.2',
                    proposals: true
                }
            }
        ]
    ];
    const plugins = [
        '@babel/plugin-transform-runtime'
    ];
    module.exports = {plugins, presets};
    
    // index.js
    // If use useBuiltIns: 'entry'
    import 'core-js/stable'
    
  • 如果我们是想开发一个第三方库,我们可以这么配置:
    // Babel配置
    const presets = [
        [
            '@babel/preset-env',
            {
                modules: false
            }
        ]
    ];
    const plugins = [
        [
            '@babel/plugin-transform-runtime',
            {
                corejs: {
                    version: 3,
                    proposals: true
                }
            }
        ]
    ];
    module.exports = {plugins, presets};
    

如果你想对Babel已经有个了解,但处于懵懵懂懂的状态;又或者你想学习Babel,可以看看我之前写的关于Babel的专栏 👉🏻 Babel专栏

相信我,看完你一定会有所收获。

总结

  • js一样是import或者require进我们的源码,那么它也是模块。所以我们也要下载对应的loaderbabel-loader)并且在module配置项配置它。

  • 此外,我们除了配置babel-loader,最重要的是还需要配置Babelbabel.config.js)。

所以,如果想要“编译es6+”,我们除了要配置webapck,最重要的是我们还要配置babel.config.js如果你不想只是一味的复制粘贴Babel配置,你还必须得学习Babel相关知识。


还记得我们使用webpack的目的吗?输出浏览器能运行的cssimgjshtml等前端资源。

OK,到目前我们已经通过webpack处理了cssimgjs。我们再来看看如何通过webpack处理得到我们的html

处理html文件

在上面的例子中,我们想在浏览器看效果,我们需要:

  • 在根目录新建一个html文件
  • 在新建的html文件中,手动引入打包出来的资源文件

这个过程太麻烦了,有没有一种办法,我们只用提供一个html模板文件,然后通过webpack编译后,它自动帮我们把打包后的文件都引入好。这样,我们打包完直接运行html就能在浏览器看效果就好了呢?

webpack这么人性化的东西,当然是有的。

我们先用 learn-06 这里例子看看如何利用webpack达到我们上述的效果。

安装相关插件:

npm i html-webpack-plugin -D

这次webpack配置来点不一样的: 我们设置打包后的js储存目录为js文件夹;为打包后的js名字增加5个长度的hash值。

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: './js/[name]-[chunkhash:5].js',
        clean: true
    },
    
    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './index.html'),
            title: 'HtmlWebpackPlugin',
        })
    ],
}

打包后的文件结构为:

dist
├── index.html
└── js
    └── index-efbfd.js

打包后的html如下:

有了这些方法,webpack你也可以自己配

我们会发现:

  • 我们的htmljs都被打包输出到dist文件夹下,这十分方便我们部署(之前我们是在根目录下新建index.html,因此打包后dist文件夹内只有imgjs等文件)
  • 打包后的html会帮我们自动引入好我们打包后的js文件

分析

从上面的例子我们可以看出,想要webpack处理html文件,我们是需要在webpack提供的plugins配置项来配置的。可能有些人会疑惑html也是一个模块,为什么是在plugins配置,而不是在module里面配置?我们来分析一下。

我们项目所有文件当然可以看作是一个模块,但是module里面配置还是在plugins里面配置,取决于我们对这些模块的使用目的。一般我们在自己的源码中使用到这个模块,则需要相应的Loader来解析

在上文讲解如何处理imgjs时,我们的目的是为了在源码中解析这些文件

  • img,我们需要将它转化成base64
  • js,我们需要将es6+的东西编译成es5及以下

并且,我们的文件都是通过import或是require()的方式,引入到我们的项目中,因此这时候当然需要相应的Loader来转换这些模块。

但是在处理html文件时,我们的目的并不是为了要解析html,我们只是想让打包出来的html自动引用我们的jsimg,这更像是使用自动引入的功能;而且,我们也没有把我们的html引入进我们的项目,因此我们当然不需要相应的Loader来解析。

还记得我们 上篇文章 我们讲解过:Loader用于转化模块,Plugin则用来加强webpack打包编译时的功能。

在此处我们处理html文件,目的更多侧重的是想要让打包出来的html自动引用我们的jsimg这个功能。因此我们需要在plugins配置项来配置,增强webpack打包编译时的功能。

同理,假设我们想要在项目中解析某个html文件(在我们项目中,import html from './x.html'),那我们就得安装相应的loaderhtml-loader),并且在module配置项目中配置。

总结

module还是plugins配置项里配置,取决于我们对这些模块的使用目的。


至此,我们已经成功通过配置webpack拿到了一个项目中需要的cssimgjshtml;这也相当于学会了webpack的一些基本配置。

大家可以通过上面总结的一些方法,自己完成对sassfontvideo等资源的处理,加深一下印象。

学习总结

通过上面对一些配置项的讲解,我们可以有以下总结:

  • 想要解析css,需要安装相应的loader,并且在module里配置
  • 想要解析imgfontvideo等常用类资源,我们不用安装loaderwebpack已经内置解析他们的功能)。我们一般在module配置项里,使用asset/resourceasset/inlineasset这三个内置模块来解析
  • 想要解析js,我们除了要安装相应的loaderbabel-loader),在module配置项里配置,最重要的是我们还要学习Babel的相关知识(感兴趣可以看看我的 👉 Babel专栏
  • 想要解析html文件,我们需要在plugins配置项里配置html-webpack-plugin插件
  • module还是plugins配置项里配置,取决于我们对这些模块的使用目的

通过上面的学习,我们整理一下,输出一个完整的webpack基础配置,让大家加深印象:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: './js/[name]-[chunkhash:5].js',
        clean: true
    },
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 1024 * 10 // When the image size is < 10kb it will be converted to base64
                    }
                },
                generator: {
                    filename: '[name]-[hash:5][ext]' // Set the name of the output file
                }
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './src/index.html'),
            title: 'Webpack Basic Configuration',
        })
    ],
}

完整的基础配置在 learn-07 ,建议大家看看完整版,这里只贴了webpack.config.js

最后

  • 希望这篇文章的一些方法总结,学习目的能让大家更好的学会如何配置webapck
  • 后面的文章将会深入配置。现实项目中,大多分开发环境、生产环境,因此我们将学习如何针对开发环境、生产环境不同的环境,进行不同webpack的配置,这更贴近我们现实项目。如果感兴趣的话可以关注一下这个 👉 专栏
  • 文章涉及到的Babel知识,如果你感兴趣,想学习,也可以看看 👉 Babel专栏
  • 文章涉及到的案例已经上传到 github,欢迎starfork学习

最后的最后,如果大家觉得文章有帮助到,创作不易,还请大家多点赞收藏评论,如果有异同点,欢迎评论讨论。