npm 默认使用的是国外的源对软件包进行安装,我们可以通过将网页链接修改为国内镜像源提升软件包的安装速度。
使用如下修改 npm 镜像源(淘宝镜像源):
npm config set registry https://registry.npm.taobao.org
使用如下命令观察 npm 程序目前所使用的镜像源:
npm config get registry
在创建空白项目目录后,在该目录下运行如下命令以初始话配置文件:
npm init -y
# 若你希望可以初始话配置文件中的某些信息,可以使用如下命令
npm init
在使用 npm init -y 命令后,你能够在项目文件中观察到新增文件 package.json。
里面的内容如下(可能与你的略有不同):
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
使用如下命令通过 npm 安装 jquery:
npm install -S jquery
# 或
npm install --save jquery
# 或
npm install jquery
在项目根目录下创建 src 文件夹,并在其中放置你的网页文件。
为实现列表隔行变色效果,我们将创建包含如下内容的 index.html 文件:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表隔行变色效果title>
head>
<body>
<ul>
<li>这是第 1 个 lili>
<li>这是第 2 个 lili>
<li>这是第 3 个 lili>
<li>这是第 4 个 lili>
<li>这是第 5 个 lili>
<li>这是第 6 个 lili>
<li>这是第 7 个 lili>
<li>这是第 8 个 lili>
<li>这是第 9 个 lili>
ul>
<script src="./index.js">script>
body>
html>
对于上述代码中的九个列表,在 VScode 中可以通过输入如下命令并敲击回车键(Enter)快速生成:
ul>li{这是第 $ 个 li}*9
在此我们将使用 ES6 的模块化导入方式来导入 jquery,来验证 webpack 是否具有解决兼容性问题的能力。
import $ from 'jquery'
// 使用 $ 来接受导入的 jquery 模块
// li:add 选中排位位于奇数位次的 li 标签
// li:even 选中排位位于偶数次的 li 标签
$(function(){
$('li:odd').css('background-color', 'red')
$('li:even').css('background-color', 'pink')
})
将 index.html 在浏览器中打开,可以看到希望产生的效果并没有实现。
让我们打开控制台(快捷键 F12),可以观察到报错信息:
Uncaught SyntaxError: Cannot use import statement outside a module (at index.js:1:1)
大意是我们无法在模块外部使用 import 语句,也就是不支持该语法。
在终端中输入如下命令以进行 webpack 的安装:
npm install webpack webpack-cli -D
npm install [email protected] -D
在安装完成 webpack 及 webpack-cli 后,让我们把目光望向 package.json 文件。
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.6.3"
},
"devDependencies": {
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
}
}
可以看到 jquety 被存放到 dependencies 下,而 webpack 及 webpack-cli 都被存放到 devDependencies 中。照成这种现象的原因与我们两次安装软件包使用的命令参数存在不同。
在使用 npm 安装软件包时,默认使用的参数就是 -S 或 –save,使用该参数对包进行安装后,软件包的名称都将出现在 dependencies 中。
使用 -D 或 –save-dev 参数对包进行安装后,软件包的名称都将出现在 devDependencies 中。
对软件包进行 dependencies 及 devDependencies 进行区分,可以减少在发布阶段所需要打包的内容,减少网站成品所占用的服务器资源。
在开发过程中,我们往往会需要用到很多的软件包,安装这些软件包究竟是使用命令参数 -S 好,还是使用命令参数 -D 好呢?
在安装一个包时如果存在上述疑惑,推荐各位可以使用 npm 官网,里面有许多软件包的具体信息。当然,查看该网站,你还可以收获上述问题的解决之道。
比如,对于 webpack,该网站中存在着如下建议:
在对 webpack 进行配置之前,需要在项目根目录下新建 webpack 配置文件,该文件的名称为 webpack.config.js。
在创建该配置文件后,请向该配置文件中输入如下内容:
module.exports = {
mode: "development"
}
其中:
mode 用来指定模式,其取值有两种,development 用来指定当前项目的模式为 开发模式;production 用来指定当前项目的模式为 发布模式。
在配置完成 webpack.config.js 配置文件后,我们需要在 package.json 文件中的 script 节点中添加内容:
"script": {
"dev": "webpack"
}
修改完成后, package.json 文件大概长这样:
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.6.3"
},
"devDependencies": {
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
}
}
在终端中使用如下命令使用 webpack 对网页源代码文件进行打包:
npm run dev
在使用该命令后,可以观察到项目文件中多出了一个文件夹 dist,dist 文件夹中的 main.js 文件便是此次 webpack 对文件打包的结果。
由于 main.js 文件是文件打包的结果,所以我们需要对 index.html 进行修改,引入 main.js 文件。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表隔行变色效果title>
head>
<body>
<ul>
<li>这是第 1 个 lili>
<li>这是第 2 个 lili>
<li>这是第 3 个 lili>
<li>这是第 4 个 lili>
<li>这是第 5 个 lili>
<li>这是第 6 个 lili>
<li>这是第 7 个 lili>
<li>这是第 8 个 lili>
<li>这是第 9 个 lili>
ul>
<script src="../dist/main.js">script>
body>
html>
将 index.html 在浏览器中打开,可以发现该网页已经可以正常运行,webpack 成功的解决了依赖问题。
webpack 能够对被打包文件进行压缩混淆,但当我们打开文件 main.js 可以观察到该文件并没有被压缩混淆。但其中的确有部分代码被压缩了,但那是 jquery。我们的 webpack 并没有对打包文件进行压缩混淆。
原因是:
压缩混淆所需要的时间往往都比较长,在开发阶段每次打包都需要耗费较多的时间用于打包是得不偿失的。如果需要对被打包文件进行压缩混淆,就需要我们对 webpack.config.js 文件进行配置,将模式设置为 发布模式(production) 即可。
为使用 webpack 的压缩混淆功能,我们将 webpack.config.js 中的内容修改为如下结果:
module.exports = {
mode: "production"
}
修改完成后,我们再次运行如下命令:
npm run dev
由程序打印的消息,我们可以观察到,本次打包程序所耗费的时间是使用开发模式打包所耗费时间的近 七倍,所耗费的空间是使用开发模式进行打包所耗费空间的近 四倍。
在 webpack 4.x 及 5.x 的版本中,默认存在如下约定:
我们可以通过修改 webpack.config.js 来对入口文件及导出文件进行修改。
将导出文件设置为 项目文件根目录下的 result 文件夹中的 bundle.js 文件;将输入文件显式设置为 webpack 的默认输入文件。
为达成上述目的,我们将 webpack.config.js 做出如下修改:
const path = require("path");
module.exports = {
mode: "development",
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, './result'),
filename: 'bundle.js'
}
}
其中:
在配置完成配置文件 webpack.config.js 后,我们使用命令 npm run dev,可以发现导出文件已在指定路径下成功显示,这表明我们对导入导出文件的设置是正确的。
在日常开发过程中,如果每次查看网页的效果都需要先执行命令 npm run dev 后再刷新页面,会大大影响各位码农的工作心情。
我们可以通过 webpack-dev-server 及 html-webapck-plugin 这两款插件来帮助我们解决这个问题。
在终端中输入如下命令以安装所需的插件:
npm install webpack-dev-server html-webpack-plugin -D
对 package.json 文件中的 script 节点进行如下更改:
"script": {
"dev": "webpack serve" //将此项由 webpack 修改为 webpack serve
}
修改完成后的 package.json 文件大概长这样:
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack serve",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.6.3"
},
"devDependencies": {
"html-webpack-plugin": "^5.5.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1"
}
}
在配置 webpack-dev-server 后,我们再执行命令:
npm run dev
可以发现,在使用该命令完成打包后,程序并没有立即退出。并且此时,如果我们对 index.js 文件(即入口文件)进行保存,webpack 也会自动对其进行打包。
在使用 webpack-dev-server 对入口文件进行自动打包的结果并不会直接存储到物理磁盘中,而是会直接存储到内存中。你可以在项目文件的根目录下访问到该文件虽然你看不到它。
还记得使用 webpack-dev-server 后使用命令 npm run dev 后打印的前几行消息吗?
这段打印信息告诉我们,我们可以通过访问链接 http://localhost:8080/ 或 http://192.168.0.105:8080/ 来对项目根目录进行访问。
虽然我的网页好像发生了错误,但还是可以访问那个看不到的导出文件 main.js。
访问链接 http://localhost:8080/main.js 来对 main.js 进行访问。
可以看到被打包后的 main.js 文件:
在 webpack 结束运行前,打包后的文件都将存储在内存中,可以在项目文件根目录中访问到该文件。
html-webpack-plugin 插件可以自动地将某个路径下的文件复制到其他路径下,该文件并不会存在于物理磁盘中,在 webpack 运行过程中,该文件都将暂存于内存中,在 webpack 停止运行时,并不会将该文件写入物理磁盘中。
在 webpack.config.js 文件添加如下内容对该插件进行配置:
const HtmlPlugin = require('html-webpack-plugin);
const htmlPlugin = new HtmlPlugin({
template: './src/index.html',
filename: './index.html'
)}
module.exports = {
plugins: [htmlPlugin]
}
其中:
webpack 文件修改后大概长这样:
const path = require("path");
const HtmlPlugin = require('html-webpack-plugin');
const htmlPlugin = new HtmlPlugin({
template: './src/index.html',
filename: './index.html'
})
module.exports = {
mode: "development",
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, './dist'),
filename: 'main.js'
},
plugins: [htmlPlugin]
}
修改配置后,每当我们使用命令 npm run dev 后,index.html 都将移动到项目文件的根目录中。此时我们只需要访问 http://localhost:8080/ 即可直接访问 index.html 文件。并且我们对 index.js 的修改在对 index.js 文件保存后都将反映到页面中。
其实,html-webpack-plugin 并不只有复制文件这一个功能。该插件还可以帮助我们在 index.js 导入入口文件。我们可以通过如下方式对其进行验证。
首先,将 index.html 中的导入 JavaScript 文件的代码删去,删除后的 index.html 文件:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表隔行变色效果title>
head>
<body>
<ul>
<li>这是第 1 个 lili>
<li>这是第 2 个 lili>
<li>这是第 3 个 lili>
<li>这是第 4 个 lili>
<li>这是第 5 个 lili>
<li>这是第 6 个 lili>
<li>这是第 7 个 lili>
<li>这是第 8 个 lili>
<li>这是第 9 个 lili>
ul>
body>
html>
然后执行命令 npm run dev,打开链接 http://localhost:8080/ 对 index.html 进行访问,可以发现我们即使没有在 index.html 文件中导入 index.js 文件,该文件也依旧在发挥功能。
在配置文件 webpack.config.js 文件中的 devServer 节点下,我们还可以对 webpack-dev-server 插件进行更多的配置。
devServer: {
open: true,
host: '127.0.0.1',
port: 80
}
其中:
在对配置文件进行如上添加后,在使用命令 npm run dev 后将会自动使用浏览器打开指定页面。
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或 “load(加载)” 模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript 或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS 文件!
上述内容引用自 webpack 官网
除了官方对 loader 的描述外,我想我们还可以通过上面的这张图来了解 loader 的功能。
默认情况下,webpack 仅能打包 js 文件。如果我们打包 css 文件,会发生什么呢?让我们拭目以待。
在项目文件根目录下的 src 文件夹中创建 css 文件夹并在其中创建 index.css 文件。
我们向 index.css 文件中写入如下内容:
*{
padding: 0px;
margin: 0px;
}
li{
list-style: none;
}
并在 index.js 文件中导入 index.css 文件:
在 index.js 中导入 css 文件并保存后,弹出如下错误信息:
在终端中输入如下命令以安装打包 css 需要用到的 loader:
npm install css-loader style-loader -D
在安装 loader 后,我们需要修改 webpack 的配置文件 webpack.config.js 文件以使用 loader,在 webpack 中添加如下内容:
module: {
rules: [
{test: /\.css$/, use:['style-loader', 'css-loader']}
]
}
注:
use 中 style-loader 与 css-loader 的顺序是固定的,不要颠倒了顺序。如果顺序发生颠倒,webpack 将会抛出错误信息。
多个 loader 的调用顺序是从后往前依次调用的。
在修改完配置文件后,重新运行 npm run dev 命令,可以发现 webpack 已经成功的打包 CSS 文件。
首先,我们在项目文件的根目录下的 src 文件夹中创建文件夹 images,并在 images 文件夹中存放几张稍后将导入到网页的图片文件。
在目标路径中存放图片完成后,我们将在 index.js 文件中导入图片文件。
import $ from 'jquery'
// 使用 $ 来接受导入的 jquery 模块
import './css/index.css'
// 导入 CSS 文件
import './images/beauty.png'
// 导入图片文件
// li:add 选中排位位于奇数位次的 li 标签
// li:even 选中排位位于偶数次的 li 标签
$(function(){
$('li:odd').css('background-color', 'red')
$('li:even').css('background-color', 'pink')
})
在导入图片文件并保存 index.js 文件后,webpack 程序立即抛出了错误:
为了使得 webpack 能够打包常见(文件类型)的图片文件,我们需要使用 npm 来安装 url-loader 及 file-loader:
npm install url-loader file-loader -D
在安装 url-loader 及 file-loader 后,我们需要对 webpack 的配置文件 webpack.config.js 文件进行修改,向该文件添加如下内容以使相应 loader 生效:
module: {
rules: [
{test: /\.png|jpg|gif/, use: 'url-loader'}
]
}
其中:
module: {
rules: [
{test: /\.png|jpg|gif/, use: 'url-loader?limit=400'}
]
}
webpack 仅能打包处理一部分高级的 JavaScript 语法。对于那些 webpack 无法处理的高级 JS 语法,需要借助于 babel-loader 进行打包处理。例如 webpack 无法处理下面的 JavaScript 代码:
// 定义了名为 info 的装饰器
function info(target){
// 为目标添加静态属性 info
target.info = 'Person info'
}
// 3. 为 Person 类应用 info 装饰器
@info
class Person{}
//4. 打印 Person 的静态属性 info
console.log(Person.info)
将该文件添加到文件 index.js 的末尾。可以看到 Person 下方出现了红色的波浪线,这是 VScode 给出的警告信息,并不是我们的代码写错了。
尝试保存该文件是,终端抛出了错误信息:
使用 npm 对 babel-loader 进行安装:
npm install babel-loader @babel/core @babel/plugin-proposal-decorators -D
其中:
babel-loader 的正常运行依赖于 @babel/core 及 @babel/plugin-proposal-decorators。
在安装 babel-loader 等包后,我们需要对 webpack 的配置文件 webpack.config.js 文件进行修改,向该文件添加如下内容以使相应 loader 生效:
module: {
rules: [
{test: /\.js$/, use: 'babel-loader', exclude: /node_modules/}
]
}
其中:
exclude 用于排除一些目录,这些目录将不在 babel-loader 的作用范围内。node_modules 目录中存放了第三方的软件包,对这些包使用 babel-loader 进行处理可能会产生问题(并且 node_modules 中通常含有较多的第三方包,如果使用 babel-loader 对这些软件包进行处理,会耗费更多的时间进行转换),因此我们将排除这一目录。
为使 babel-loader 正常运行,我们还需要在项目文件根目录下创建配置文件 babel.config.js,该文件中的内容应为:
module.exports = {
// 声明 babel 可用的插件
plugins: [['@babel/plugin-proposal-decorators', {legacy: true}]]
}
npm run dev 使用的是开发模式,且使用了 webpack-dev-server 等插件,不会将网页文件打包到物理磁盘中。这些特性有利于开发阶段中对网页的开发,但不利于网页的发布。我们可以构造一个命令专门用于发布,而这个命令可以为 build。
在 webpack.config.js 文件中的 script 节点中添加如下内容:
"script": {
"build": "webpack --mode production"
}
其中:
我们通过使用 –mode 参数来为 webpack 指定了使用的模式为发布模式(production),该参数指定的值将覆盖 webpack.config.js 中指定的模式。
在 webpack.config.js 配置文件的 output 节点下,进行如下配置:
output: {
path: path.join(__dirname, './dist/js'),
filename: 'main.js'
}
使用上述配置文件后,webpack 生成的 JS 文件都将存放在项目文件根目录下的 dist 文件夹下的 js 文件夹中。
修改 webpack.config.js 中的 url-loader 配置项,新增 outputPath 选项即可指定图片文件的输出路径:
{
test: /\.jpg|png|gif/,
use: {
loader: 'url-loader',
options: {
limit: 2333,
outputPath: 'images'
}
}
}
或
{test: /\.jpg|png|gif/, use: 'url-loader?limit=2333&outputPath=images'}
使用上述配置文件后,webpack 将打包图片到文件到项目文件根目录下的 dist 文件夹(导出目录)下的 images 文件夹中。
在进行上述优化后,使用 npm run build 即可看到效果。
在使用 npm run build 对网页文件进行打包时,往往需要先将导出目录删除,这是因为 npm run build 打包的文件会将导出目录中同名文件进行覆盖,而没有同名的多余文件将保留在导出文件夹中,这不利于项目的发布。因此在发布时往往需要先将导出目录进行删除后才开始使用 webpack 对项目进行打包。
而使用 clean-webpack-plugin 插件后则可以自动在使用 webpack 对项目进行打包前先将导出文件夹进行删除。
使用如下命令来安装 claean-webpack-plugin 插件:
npm install clean-webpack-plugin -D
为正常使用 clean-webpack-plugin 插件,我们需要在 webpack.config.js 配置文件中做出如下修改:
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const cleanPlugin = new CleanWebpackPlugin()
moudle.exports = {
plugins: [cleanPlugin]
}