文章目录

前言简单介绍1. webpack作用2. webpack语法规范

安装依赖及基本配置loader (加载器)1、处理 ts / js 文件1.1 babel配置文件1.2 browserslist配置文件

2、处理图片、字体、图标等资源文件3、处理**less、scss、css**文件3.1 css 文件分离3.2 处理 less / sass 文件3.3 css3 属性添加兼容前缀3.4 css 的压缩3.5 示例代码

4、处理html文件

总结

前言

此篇文章将简单介绍webpack的基本概念和使用方法,并通过实例演示如何使用webpack来构建一个不依赖前端框架的项目,同时也会介绍一些常用的webpack插件和优化技巧,希望本篇文章能够帮助大家更好地使用webpack进行项目开发。

简单介绍

常见打包工具有Grunt、Gulp、Parcel、Webpack、Rollup、Vite、ESBuild 等等,这篇文章只专注于webpack就不去对比其他打包工具了。webpack优点在于有着完善的基础建设,而且得益于webpack5的升级,对比以往版本也有了相当大的提升(极致编译速度,一文搞定webpack5升级),虽然它的保留率在逐年下降,但大概率还是目前使用率最多的构建工具(查看StateOfJS的调查结果)。

1. webpack作用

代码编译 如sass,TypeScript等代码虽然极大的提高了开发效率,但是本身并不被浏览器所识别,需要我们对其进行编译和打包,变成浏览器识别的代码模块化 使用高级语法 ES6 和 CommentJS,进行前端模块化开发,webpack 将高阶语法打包成浏览器识别的代码优化加载速度 压缩和合并代码来提高加载速度,压缩可以减少文件体积,代码合并可以减少http请求

2. webpack语法规范

webpack是用Node封装的,可以使用Node的语法,Node.js 的模块规范就是 CommonJS 模块规范,ES6模块化(ES Modules / ESM)是浏览器端和服务器端通用的规范,关于规范的区别这里也不展开了。

安装依赖及基本配置

下面正式进入webpack5的实战环节,我使用Node的版本为14.21.3,当然最好还是更新到比较新的Node版本进行webpack5的开发,不过Webpack 5 运行于 Node.js v10.13.0+ 的版本,我这里使用较低版本也是为了兼顾大多数的开发环境。首先创建基础的网页,html文件中放入图片及引用css、script等,目录结构如下:

├── webpack5 (项目根目录)

├── image (项目图片资源目录)

│ └── 略

├── favicon.ico(网页图标)

├── index.css

├── index.html

└── index.js

初始化一下项目:(会生成一个package.json文件)

npm init -y

安装webpack:

npm i webpack webpack-cli -D

创建运行指令:

在package.json中的scripts中创建build命令,webpack默认会找配置文件“webpack.config.js”

"scripts": {

"build": "webpack"

},

编写默认配置文件:webpack.config.js

const path = require('path'); //核心模块

module.exports = {

entry: 'index.js', //配置入口文件

output: {

filename: 'bundle.js', //打包出来的文件名称

path: path.resolve(__dirname, './dist'), //打包后的路径,必须是绝对路径

//path.resolve()拼接路径为绝对路径

//__dirname指当前文件根目录,dist是打包出来的目录名称

},

mode: 'production', //production生产模式(代码压缩),development开发模式(不压缩代码)

module: {}, //配置loader

plugins: [] //配置plugins

};

打包

运行了webpack打包命令后多了dist目录,类似下面这样子就证明成功使用webpack5打包了。

查看bundle.js文件会发现只有对index.js代码压缩后的内容,这是正常的,因为我们只是指定了“index.js”作为入口起点(entry point) ,让 webpack 使用其作为一个“模块”构建项目,其他资源文件(如html、css)要引入到 js 里面才能使用。 另外webpack本身就能打包 js 代码,但是其他类型的如css,图片等格式的文件没法打包,就需要在引入资源后利用第三方的模块进行打包,这就是loader(加载器) 的作用了,另外配置了多个loader,其按照从右到左(或从下到上)地取值(evaluate)/执行(execute)。

loader (加载器)

1、处理 ts / js 文件

npm i babel-loader @babel/core @babel/preset-env core-js @babel/plugin-transform-runtime @babel/preset-typescript -D

babel-loader: 使用 babel 将ES6+语法转换为 ES5@babel/corer: babel 编译的核心包@babel/preset-env: babel 编译的预设(告诉babel使用那种转码规则进行文件处理)core-js(通过 Polyfill 方式在目标环境中添加缺失的特性,让低版本的浏览器也可以支持promise这些新的API)@babel/plugin-transform-runtime 将所有文件用到的公用辅助函数抽离出来形成一个第三方文件,自动引入辅助函数,减少包的体积@babel/preset-typescript(支持ts语法)

module: {

rules: [

{

test: /\.js|ts$/,

use: {

loader: 'babel-loader',

options: {

exclude: /node_modules/, //除了这个文件夹之外的文件

presets: [

[

'@babel/preset-env',

{

useBuiltIns: 'usage', //按需引入(根据配置的目标环境找出需要的polyfill进行部分引入)

corejs: 3,

// 设置兼容目标浏览器版本,这里可以不写,将使用 browserslist 配置文件

// targets: '> 1%, not dead',

},

],

'@babel/preset-typescript',

], //预设

// 插件比预设先执行

plugins: ['@babel/plugin-transform-runtime'],

cacheDirectory: true, //开启缓存,第二次编译时,没改的部分使用缓存

},

},

},

]

}

1.1 babel配置文件

可以把babel-loader的配置单独抽离出来,配置成一个全局配置文件babel.config.js,也可以使用**.babelrc**文件进行颗粒度更细的配置,这两者可以一起使用,也可以独立使用,当同级存在时后者优先级更高,详细可看babeljs官网,或者理解 babel.config.js 和 babelrc。

1.2 browserslist配置文件

在package.json中添加browserslist:

"browserslist": [

">1%",

"last 10 versions",

"not dead"

]

2、处理图片、字体、图标等资源文件

module: {

rules: [

{

test: /\.(png|jpe?g|gif|webp|svga)(\?.*)?$/,

type: 'asset',

generator: {

filename: 'imgs/[name].[contenthash:4][ext]',

},

parser: {

// 生成Data URI 的条件,视为 inline 模块类型,否则会被视为 resource 模块类型

dataUrlCondition: {

// 当资源模块不超过 4kb 时,生成 DataURI,超过 4kb 时,单独打包成文件

maxSize: 4 * 1024, // 4b

},

},

},

{

test: /\.(eot|ttf|otf|woff2?)$/,

type: 'asset/resource',

generator: {

filename: 'font/[name].[contenthash:4][ext]',

},

},

]

}

3、处理less、scss、css文件

3.1 css 文件分离

npm i style-loader mini-css-extract-plugin

3.2 处理 less / sass 文件

处理sass

npm i sass sass-loader -D

处理less

npm i less less-loader -D

3.3 css3 属性添加兼容前缀

npm i postcss-loader autoprefixer -D

另外还需要有一份要兼容浏览器的清单,让postcss-loader知道要加哪些浏览器的前缀,browserslist配置文件其实就是这份清单。

3.4 css 的压缩

npm i css-minimizer-webpack-plugin -D

3.5 示例代码

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const devMode = process.env.NODE_ENV !== 'production';

module.exports = {

// ...

module: {

rules: [

{

test: /\.css$/,

//use里面执⾏顺序是从右往左的顺序,先模块化再引入

use: [

devMode ? 'style-loader' : MiniCssExtractPlugin.loader,

{

loader: 'css-loader',

options: {

url: true, //默认为true,可以处理css中的url图片路径

esModule: false,

},

},

{

loader: 'postcss-loader',

options: {

postcssOptions: {

plugins: ['autoprefixer'],

},

},

},

],

},

{

test: /\.scss$/,

use: [

devMode ? 'style-loader' : MiniCssExtractPlugin.loader,

'css-loader',

{

loader: 'postcss-loader',

options: {

postcssOptions: {

plugins: ['autoprefixer'],

},

},

},

'sass-loader',

],

},

{

test: /\.(png|jpe?g|gif|webp|svga)(\?.*)?$/,

type: 'asset',

generator: {

filename: 'imgs/[name].[contenthash:4][ext]',

},

parser: {

// 生成Data URI 的条件

dataUrlCondition: {

// 当资源模块不超过 4kb 时,生成 DataURI,超过 4kb 时,单独打包成文件

maxSize: 4 * 1024, // 4b

},

},

},

{

test: /\.(eot|ttf|otf|woff2?)$/,

type: 'asset/resource',

generator: {

filename: 'font/[name].[contenthash:4][ext]',

},

},

// ...

],

},

plugins: [

new MiniCssExtractPlugin({

// 长期缓存:使用 filename: "[contenthash].css" 启动长期缓存

filename: devMode ? 'css/[name].css' : 'css/[name].[contenthash].css',

}),

],

};

这里其实会有个问题,当我们指定mode的模式为“production”后,在index.js文件中打印process.env.NODE_ENV的值确实是“production”,然而在webpack.config.js文件中打印process.env.NODE_ENV的值会发现值是’undefined’,这里先卖个关子,解决办法留到后面的环境变量章节讲述。

4、处理html文件

webpack需要把最终构建好的静态资源都引入到一个html文件中,这样才能在浏览器中运行

npm i html-webpack-plugin html-loader@0.5.5 -D

html-webpack-plugin 插件的作用 以自己的index.html为模板生成一个 HTML 文件,并且引入所有webpack生成的资源链接

const path = require('path')

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

module.exports = {

// ...

plugins: [

new HtmlWebpackPlugin({

template: template: path.resolve(__dirname, './index.html'), //模板

filename: 'index.html', //打包的 HTML 文件名字

favicon: path.resolve(__dirname, './favicon.ico'), //网页图标

}),

]

}

html-loader的作用 由于webpack需要解析html模板,所以需要html-loader解析html文件。这里是目前唯一一个需要指定安装版本的包,因为其最新的v5.0.0的包支持的最低 Node.js 版本为18.12.0,查看各种版本的下载数量可以到npm官网查看。

module: {

rules: [

//...

{

test: /\.html$/i,

use: [

{

loader: 'html-loader',

options: {

esModule: false,

},

},

],

},

//...

]

}

因为webpack配置的打包入口只有index.js一个,记得在index.js文件中引入需要的资源,如

import './index.scss';

import './index.ts';

再次运行webpack打包,就可以打包出来如下图所示的目录文件了,本地运行这个index.html文件,能正常访问图片、应用样式以及控制台成功执行输出等就证明成功打包了。

然而其实这里有点小问题,一是资源报错找不到,二是重复加载资源。

针对其一,原因是原来的html页面引入了这些资源,现在将其去掉即可。 针对其二,由于在HtmlWebpackPlugin插件中配置了favicon选项,虽然将favicon.ico文件从根目录拷贝到打包目录下了,但是这个插件并没有智能地将原本html里引用的favicon.ico去掉,导致重复加载了,有两个办法:一是直接删掉html里引入的favicon.ico,二是使用copy-webpack-plugin这个插件,webpack只会将里面的资源复制到打包目录下,不会对其进行压缩编译等处理。

npm i copy-webpack-plugin -D

const CopyPlugin = require('copy-webpack-plugin');

module.exports = {

plugins: [

// ...

// public目录被webpack打包,一开始是什么样子,打包后还是什么样子

new CopyPlugin({

patterns: [

{

from: 'public', //拷贝的目录

},

],

}),

],

};

将favicon.ico从根目录移动到新创建的public文件夹中,再次运行打包命令即可。

总结

写到这里这篇文章篇幅实在是太长了,所以还有几章关于webpack的环境变量、插件、优化等内容我还是另开一篇文章讲述,后续文章请点击查看。 欢迎各位看官【点赞】、【收藏】,多多支持!也欢迎您【评论】留下宝贵意见,共同探讨一起学习~。

参考链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: