一. 搭建开发环境
在此之前我们很多工作都是手工的,比如每次打开html文件都需要右键在浏览器打开,还有每次更新代码都需要重新编译,而且只能手动的去刷新浏览器才能看到新效果等等。下面我们通过搭建开发环境去解决这个问题。
1. mode选项
修改mode配置:
module.exports = {
... ...
mode: "development", //开发模式
... ...
};
2. 使用source map
使用source map进行代码调试,比如不小心将helloworld.js文件中的console写成了cnosole,执行打包命令之后,在代码里面不能直观的看出发生错误的位置:

那我们通过浏览器帮助我们检查,浏览器打开html之后发现错误是在hello-world.js的第六行:

点击之后发现,这个代码并不是我们源文件中的:

这时我们可以通过一种方式精准的锁定代码出错的位置。
修改webpack配置:
module.exports = {
... ...
//在浏览器运行编译后的代码时,可以对应到编译前也就是开发编写的代码。对调试非常有帮助。
devtool: "inline-source-map",
... ...
};
重新编译之后,打开bundle.js,发现代码能够正常显示了:

刷新浏览器,发现错误还在,但是hello-world.js的错误行数指向程序的第二行:

也就是我们真实的源代码的第二行:

3. 使用watch mode
每次编译代码时,手动运行 npx webpack 会显得很麻烦。我们可以在webpack启动时添加watch参数,如果其中一个文件被更新,代码将被重新编译,不必手动再去运行整个构建。
运行命令:
$ npx webpack --watch

这样就会实时监测我们文件的变化。修改hello-world.js,保存之后会发现程序自动执行了一次编译:

刷新浏览器,修改的地方更新过来了。
4. 使用webpack-dev-server
webpack-dev-server 提供了一个基本的web server ,并且具有 live reloading(实时重新加载)功能。
先安装:
$ npm install webpack-dev-server --save-dev
配置devServer服务:
module.exports = {
... ...
//本地服务配置
devServer: {
static: './dist', //devServer指向的物理路径 指定dist作为项目根目录
}
};
执行命令,启动服务:
$ npx webpack-dev-server

这样我们就会启动一个http://localhost:8080/的服务。浏览器打开服务,会发现服务根目录指向了dist文件夹里:

点击app.html,打开控制台发现程序正常运行,并且热模块更新替换,实时更新也生效了。

修改代码,不手动刷新浏览器,控制台上面也实时更新了打印结果,这样webpack-dev-server就完成了自动刷新页面的功能。
其实webpack-dev-server真正的没有输出任何物理文件,它把打包输出的bundle文件放到了内存里。比如删掉dist文件夹,重新在浏览器访问,结果并没有什么问题。关闭服务,再重新启动服务,浏览器打开,结果任然能够正常运行。修改文件,在浏览器照常能够自动刷新。
二. 资源模块
到目前为止,项目只能加载js,现在我们能不能尝试混合一些其他的资源呢,比如像images。在webpack出现之前,使用类似于Grunt或者Gulp等工具来处理资源,它们奖src里面的文件移动到dist或者build中。其实webpack最出色的功能之一就是除了引入js还可以使用内置的资源模块。我们叫asset modules来引入其他任何类型的资源。asset module即资源模块,是一种模块类型,它允许我们应用webpack来打包其他的资源文件,比如像字体文件,图标文件等等。资源模块的类型称之为 asset module type ,会通过四种新的类型模块来替换所有的loader。
四种类型模块:
- asset / resource 它会发送一个单独的文件并导出URL
- asset / inline 它会导出一个资源的data URL
- asset / source 会导出资源的源码
- asset 会在导出一个Data URL 和发送一个单独文件之间自动进行选择
1. Resource资源
修改webpack.config.js文件:
module.exports = {
... ...
... ...
//资源模块配置
module: {
// 规则配置,数组里面配置多个对象去加载不同类型的资源文件
rules: [
{
//test+正则表达式去定义加载的文件的类型
test: /\.png$/, // 表示以png作为扩展名的这样的类型文件
//定义资源类型
type: 'asset/resource',
},
],
},
};
src下新建assets文件夹,文件夹下放置.png / .svg /.jpg等不同类型文件。
在index.js里面引入文件:
import helloWorld from "./hello-world";
//资源加载进来以后,会生成一个URL,可以通过这个URL在页面上显示
import imgsrc from './assets/img01.png';
helloWorld();
const img = document.createElement('img');
img.src = imgsrc;
document.body.appendChild(img);
执行npx webpack命令,可以看到dist下面生成了一个打包的.png文件:

执行一下命令启动webpack服务,并帮我们自动打开浏览器:
$ npx webpack-dev-server --open

点击app.html,图片正常显示:

我们可以看到dist下的打包生成的图片名是webpack自动生成的,那么我们能不能自己定义图片的目录以及文件名呢?当然是可以的,有两种方法:
第一种:修改webpack.config.js文件的output,添加 assetModuleFilename 属性:
module.exports = {
entry: "./src/index.js", //入口文件配置
// 出口文件配置
output: {
filename: "bundle.js", // 指定输出文件的文件名
// path: './dist', //报错:必须为绝对路径
// 调用path模块的resolve方法
path: path.resolve(__dirname, "./dist"), //指定文件输入路径
// __dirname 表示获取到当前的webpack.config.js这个文件所在的物理路径
// "./dist" 表示基于前面的第一个路径去找到 dist文件夹
clean: true, //生成新文件之前,清空之前的文件
assetModuleFilename: 'images/test.png', //资源模块的文件名,不但可以设置文件名,还可以设置路径
}
}
执行npx webpack打包,文件生成成功:

只是,不可能我们所有的资源都叫test.png,所以我们还得去自动生成一个文件名。我们可以使用webpack自带的默认的生成文件名的方法:images/[ contenthash ][ ext ]
module.exports = {
entry: "./src/index.js", //入口文件配置
// 出口文件配置
output: {
filename: "bundle.js", // 指定输出文件的文件名
// path: './dist', //报错:必须为绝对路径
// 调用path模块的resolve方法
path: path.resolve(__dirname, "./dist"), //指定文件输入路径
// __dirname 表示获取到当前的webpack.config.js这个文件所在的物理路径
// "./dist" 表示基于前面的第一个路径去找到 dist文件夹
clean: true, //生成新文件之前,清空之前的文件
//资源模块的文件名,不但可以设置文件名,还可以设置路径
// [contenthash] 表示根据文件的内容去生成一个哈希的字符串,
assetModuleFilename: "images/[contenthash][ext]",//扩展名可以使用原资源的扩展名 [ext]
}
}
重新执行打包命令:

第二种:定义rules的时候添加属性 generator 。generator优先级高于output的优先级。
module.exports = {
... ...
... ...
//资源模块配置
module: {
// 规则配置,数组里面配置多个对象去加载不同类型的资源文件
rules: [
{
//test+正则表达式去定义加载的文件的类型
test: /\.png$/, // 表示以png作为扩展名的这样的类型文件
//定义资源类型
type: 'asset/resource',
// 定义文件的名字和路径
generator: {
filename: "images/[contenthash][ext]",
},
},
],
},
};
重新打包,资源成功被打包了。
2. inline资源
修改webpack.cong.js文件,新增rules配置:
module.exports = {
... ...
... ...
//资源模块配置
module: {
// 规则配置,数组里面配置多个对象去加载不同类型的资源文件
rules: [
{
//test+正则表达式去定义加载的文件的类型
test: /\.png$/, // 表示以png作为扩展名的这样的类型文件
//定义资源类型
type: 'asset/resource',
// 定义文件的名字和路径
generator: {
filename: "images/[contenthash][ext]",
},
},
{
test: /\.svg$/,
type: 'asset/inline'
}
],
},
};
引入svg资源:
import logoSvg from './assets/img02.svg';
... ...
const img2 = document.createElement("img");
img2.src = logoSvg;
document.body.appendChild(img2);
执行打包命令之后会发现,虽然我们打包成功了,但是dist下面并没有我们想要的文件:

因为我们使用的是asset inline,那么只能去浏览器去看效果了。启动服务,打开app.html:

svg图片正常加载出来了。检查第二个图片元素会发现它不是一个图片的URL,而是所谓的 Data URL base64的格式:

3. Source资源
修改webpack.config.js文件,新增rules配置:
module.exports = {
... ...
... ...
//资源模块配置
module: {
// 规则配置,数组里面配置多个对象去加载不同类型的资源文件
rules: [
{
//test+正则表达式去定义加载的文件的类型
test: /\.png$/, // 表示以png作为扩展名的这样的类型文件
//定义资源类型
type: 'asset/resource',
// 定义文件的名字和路径
generator: {
filename: "images/[contenthash][ext]",
},
},
{
test: /\.svg$/,
type: 'asset/inline'
},
{
test: /\.txt$/,
type: 'asset/source'
}
],
},
};
assets下新建example.txt文件。引入.txt文件。
import exampleTxt from './assets/example.txt';
... ...
const block = document.createElement("div");
block.textContent = exampleTxt;
document.body.appendChild(block);
执行打包命令之后。dist下仍旧没有生成任何文件:

启动服务在浏览器中查看,.txt文件内容显示成功:

4. 通用数据类型
修改webpack.config.js文件,新增一个资源类型:
module.exports = {
... ...
... ...
//资源模块配置
module: {
// 规则配置,数组里面配置多个对象去加载不同类型的资源文件
rules: [
{
//test+正则表达式去定义加载的文件的类型
test: /\.png$/, // 表示以png作为扩展名的这样的类型文件
//定义资源类型
type: 'asset/resource',
// 定义文件的名字和路径
generator: {
filename: "images/[contenthash][ext]",
},
},
{
test: /\.svg$/,
type: 'asset/inline'
},
{
test: /\.txt$/,
type: 'asset/source'
},
{
test: /\.jpg$/,
type: 'asset'
}
],
},
};
引入jpg文件。
import jpgMap from './assets/img03.jpg';
... ...
const img3 = document.createElement("img");
img3.src = jpgMap;
document.body.appendChild(img3);
执行打包命令之后发现dist下面的images下面多了一个文件:

这里有个问题,新打包生成的文件为什么在images里面,我们并没有设置generator。那他事实上是继承使用了我们在output里面指定的assetModuleFilename。
启动服务,在浏览器查看,打开app.html,图片正常显示:

检查元素,可以看到这个图片是一个实际上的本地的图片资源

我们说asset会在两种类型上做选择,很显然现在选择的是asset resource,那如何让他在asset inline上选择呢?默认情况下,webpack回去判断我们加载的资源的大小,当文件资源大于8k的时候,就会去创建一个资源了,如果小于8k,他就会作为一个inline 生成一个base64的链接。那我们能不能自己去调整一下这个临界值呢?
修改webpack.config.js 新增一个参数去调整这个临界值:
{
test: /\.jpg$/,
type: 'asset',
//解析器
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 * 1024, //默认情况下大小为 4 * 1024
},
}
}
重新执行打包命令,会发现刚生成的图片文件没了:

启动服务,在浏览器打开app.html,图片正常显示,检查元素,图片为base64格式。
