Nodejs-包

包的类型

  • 项目包:用于编写项目和和业务逻辑
  • 软件包:封装工具和方法进行使用
    • 本地软件包:当前项目内使用,封装属性和方法,存在于 node_modules中。
    • 全局软件包:本机所有项目使用,封装命令和工具,存在于系统设置的位置。

软件包的结构

如下图所示。整个util包由三部分组成,libs、index.js、package.json。

  • libs中,存放工具包的源代码 js 文件。
  • index.js文件作为入口文件,通过这个文件统一暴露对外工具方法等。
  • package.json文件,描述包的一些信息。

包的结构图

libs示例

1
2
3
4
5
6
7
8
9
10
11
//printHello.js
function printHello() {
console.log("Hello,Adong. It's your first tools package.")
}

const words = "How old are you?"

module.exports = {
printHello,
words
}

index.js示例

1
2
3
4
5
6
7
8
9
10
11
//下面这用法叫做解析重构
let { printHello, words } = require("./libs/printHello")

let resHeaderUtil = require("./libs/resHeaderUtil-commonjs")

//对libs中的工具,统一作模块暴露
module.exports = {
printHello,
words,
resHeaderUtil
}

package.json示例

1
2
3
4
5
6
7
8
{
"name": "kahvia_tools",
"author": "Kahvia",
"description": "包含了设置http请求的响应头的工具和输出你好的工具函数",
"main": "index.js",
"version": "1.0.0",
"license": "MIT"
}

其中,main表示工具包的入口文件,version代表版本,license表示许可证。

软件包的使用

在使用软件包时,路径只需要到软件包的根目录即可。无需指定更详细的路径。它会自动寻找index.js,若无则查找package.json中的main入口。

1
2
3
let kahvia_utils = require("./util")

kahvia_utils.printHello()

结果如下所示。

工具包使用结果

NPM

npm是nodejs的包管理器。

若项目中没有package.json,可以通过以下命令执行初始化。

1
npm init -y

若我们需要安装某个软件包,则通过以下命令执行安装,软件包会存放在node_modules目录下,软件包的版本则会保存在package-lock.json文件中,用作固化版本。

1
npm i package-name

我们使用下载的软件包时,可以直接通过包名引入,而不用通过路径。

当我们协同开发时,git不会同步我们的node_modules文件夹。可能别人使用了某个包,但是我们自己没有使用,所以本地没有这个包。我们可以通过以下命令,根据package.json文件,安装本地缺少的包。

1
npm i

常用的软件包

nodemon

一个全局软件包,需要全局安装。通过这个nodemon启动 js 文件,可以检测代码更改,自动重启程序。

1
npm i nodemon -g

webpack

一个常用的打包工具,安装在项目的dev环境中。

1
npm i webpack webpack-cli --save-dev

在项目的package.json中添加自定义脚本命令。其中,build是自定义的名称,什么都可以,其后面的值即webpack才是真正执行的命令。

1
2
3
"scripts":{
"build":"webpack"
}

将要打包的文件放在根目录的src目录中,通过npm run build,实现项目打包。不过这里的打包只能实现部分 js 文件的打包,至于为什么是部分,因为打包那种nodejs写的后端项目,会报很多错误,而我暂时还不太懂问题出在哪里。目前打包给前端页面引用的js文件是没有问题的。

通过配置项目根目录的webpack.config.js文件,可以配置打包的参数,比如入口、出口、插件等。其中,entry是入口,output是出口,path是输出路径,filename是打包后的文件名。

1
2
3
4
5
6
7
8
9
10
import path from 'path'
import { getRecentDir } from './utils/recentPath.js'

export default {
entry: './src/hello.js',
output: {
path: path.resolve(getRecentDir(import.meta.url), 'dist'),
filename: 'testPack.js'
}
}
HtmlWebpackPlugin(根据自动生成目标页面并连接打包压缩的JS文件)

webpack通过上述方式打包的话,只能打包普通的静态js文件。也就是说,打包完成后,我们需要手动为页面引入打包后的js文件,这无疑的麻烦的。通过HtmlWebpackPlugin,我们可以将页面一起打包,自动为页面引入打包好的js文件,一起输出到目标目录。

​ 详细的使用可以参考官方文档

通过如下命令安装插件。

1
npm install --save-dev html-webpack-plugin

在webpack配置文件中,配置如下。其中,template作为模板,即以此模板在目标目录生成一份以filename为文件名的html文件,同时为其引入打包好的js文件。output中的clean属性可以清除上一次打包的东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import path from 'path'
import { getRecentDir } from './utils/recentPath.js'
//引入插件
import HtmlWebpackPlugin from 'html-webpack-plugin'

export default {
entry: './src/hello.js',
output: {
path: path.resolve(getRecentDir(import.meta.url), 'dist'),
filename: 'testPack.js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'test.html'
})
]
}
css-loader,style-loader(加载器,把css打包到js文件中)

这两个加载器的官方文档

  • css-loader:解析css代码。
  • style-loader:把解析后的css代码插入到DOM。最后css代码在打包后的js文件中,通过函数的方式保存。

按照下方命令安装加载器。

1
npm install --save-dev css-loader style-loader

在webpack配置文件中配置加载器。下方的module部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import path from 'path'
import { getRecentDir } from './utils/recentPath.js'
//引入插件
import HtmlWebpackPlugin from 'html-webpack-plugin'

export default {
entry: './src/hello.js',
output: {
path: path.resolve(getRecentDir(import.meta.url), 'dist'),
filename: 'testPack.js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({
template: './Login/login.html',
filename: 'login.html'
})
],
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
}

use数组中的元素顺序是有影响的。loader是从右到左应用的。在这种情况下,首先应用css-loader,然后应用style-loader。即先解析css引用,再绑定DOM元素。

配置好加载器以后,就可以把使用到的css文件引用到入口js文件中了。比如我这里的打包入口是hello.js文件,那我在文件内容开头import即可。

1
2
3
4
5
6
7
//hello.js
import '../Login/login.css'

//测试打包
console.log("hello, kahvia !")
//二次输出
console.log("what's up ?")

以上都完成后,即可打包。

1
npm run build
mini-css-extract-plugin(提取css文件)

MiniCssExtractPlugin | webpack 中文文档

我们在上面通过style-loader,是将css打包进js文件,这会导致js文件比平常更大。所以官方更推荐的一个做法是将css提取出来,而不是打包进js文件。通过mini-css-extract-plugin这个插件,配合css-loader我们可以做到提取css文件。

值得注意的是,mini-css-extract-plugin不能和style-loader一起使用,因为既要单独提取,又要打包进js文件,这不是相互矛盾了吗?

顺带一提,单独提取的css文件,是不会被压缩的。

通过以下命令安装插件。

1
npm install --save-dev mini-css-extract-plugin

再在webpack配置文件中引入该插件,为其配置plugin选项,并在rules-use中添加插件内置的loader。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import path from 'path'
import { getRecentDir } from './utils/recentPath.js'
//引入插件
import HtmlWebpackPlugin from 'html-webpack-plugin'
//引入css提取插件
import MiniCssExtractPlugin from 'mini-css-extract-plugin'

export default {
entry: './src/hello.js',
output: {
path: path.resolve(getRecentDir(import.meta.url), 'dist'),
filename: 'testPack.js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({
template: './Login/login.html',
filename: 'login.html'
}),
new MiniCssExtractPlugin()
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
}
CssMinimizerWebpackPlugin(压缩提取的css文件)

通过上述的mini-css-extract-plugin插件,只能做到提取,但是会发现提取出来的css文件并没有做到压缩。而CssMinimizerWebpackPlugin就是为了压缩而使用的。

通过命令安装插件。

1
npm install css-minimizer-webpack-plugin --save-dev

在webpack配置文件中引入并配置。其中optimization-minimizer是配置项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import path from 'path'
import { getRecentDir } from './utils/recentPath.js'
//引入插件
import HtmlWebpackPlugin from 'html-webpack-plugin'
//引入css提取插件
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
//引入css压缩插件
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'

export default {
entry: './src/hello.js',
output: {
path: path.resolve(getRecentDir(import.meta.url), 'dist'),
filename: 'testPack.js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({
template: './Login/login.html',
filename: 'login.html'
}),
new MiniCssExtractPlugin(),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
//优化
optimization: {
//minimize 减小
minimizer: [
new CssMinimizerPlugin()
]
}
}
打包图片

在上述操作中,我们可以打包html,css,js了,但是图片该如何处理呢?如果项目中的图片,采用网络地址url访问,那么我们打包后自然可以正常使用。但如果采用的是本地的图片呢?我们就需要把图片也一起打包了。

资源模块 | webpack 中文文档

在webpack5中,我们无需使用外置loader,配置如下所示,在rule中配置图片打包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import path from 'path'
import { getRecentDir } from './utils/recentPath.js'
//引入插件
import HtmlWebpackPlugin from 'html-webpack-plugin'
//引入css提取插件
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
//引入css压缩插件
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'

export default {
entry: './src/hello.js',
output: {
path: path.resolve(getRecentDir(import.meta.url), 'dist'),
filename: 'testPack.js',
clean: true
},
plugins: [
new HtmlWebpackPlugin({
template: './Login/login.html',
filename: 'login.html'
}),
new MiniCssExtractPlugin(),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
//配置图片打包
{
test: /\.(png|jpg|gif)$/i,
type: 'asset'
},
],
},
//优化
optimization: {
//minimize 减小
minimizer: [
new CssMinimizerPlugin()
]
}
}

在asset类型下,大于8kb的图片会直接作拷贝处理,小于8kb的会转为base64,通过uri的方式替换项目中的src引用。

类似于css打包,我们将要打包的图片也引入入口JS文件即可。

1
2
3
4
5
6
7
8
9
//hello.js
import '../Login/login.css'
//导入需要打包的本地图片
import '../Login/ganda.jpg'

//测试打包
console.log("hello, kahvia !")
//二次输出
console.log("what's up ?")

正常打包即可。

搭建热更新开发环境

下载webpack-dev-server。

1
npm i webpack-dev-server --save-dev

在webpack配置文件中,设置模式(mode)为开发模式(development),并在package.json中配置自定义命令,即scripts中的选项,“dev”: “webpack serve --open”。

设置开发模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import path from 'path'
import { getRecentDir } from './utils/recentPath.js'
//引入插件
import HtmlWebpackPlugin from 'html-webpack-plugin'
//引入css提取插件
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
//引入css压缩插件
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'

export default {
//设置热更新开发模式
mode: "development",
//设置入口
entry: './src/hello.js',
//出口
output: {
path: path.resolve(getRecentDir(import.meta.url), 'dist'),
filename: 'testPack.js',
clean: true
},
//插件
plugins: [
new MiniCssExtractPlugin({
// filename: "login.css"
}),
new HtmlWebpackPlugin({
template: './Login/login.html',
filename: 'login.html'
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
//配置图片打包
{
test: /\.(png|jpg|gif)$/i,
type: 'asset'
},
],
},
//优化
optimization: {
//minimize 减小
minimizer: [
new CssMinimizerPlugin()
]
}
}

在package.json中,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"type": "module",
"devDependencies": {
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"html-webpack-plugin": "^5.5.3",
"mini-css-extract-plugin": "^2.7.6",
"style-loader": "^3.3.3",
"webpack": "^5.88.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"scripts": {
"build": "webpack",
"dev": "webpack serve --open"
}
}

通过自定义命令启动。

1
npm run dev

这种情况下,会自动创建一个8080端口的服务,服务器的根目录为项目的public目录和webpack配置文件中的出口目录。默认打开的是public目录下的index网页,而我们要查看的网页在出口目录,那么我们可以为public目录的index网页添加重定向,自动跳转到我们要查看的网页。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- public目录下的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>Document</title>
</head>

<body>
</body>

<script>
location.href = "/login.html"
</script>

</html>
生产模式

上面使用到了开发模式,配合webpack-dev-server可以热更新。与之相对的,还有生产模式(production),即打包模式。

我们开发模式用的更多,所以mode设置为development,那打包的时候怎么办呢?再去修改mode吗?这很显然不方便。所以我们可以通过自定义命令指定模式。命令的优先级>配置文件。

在package.json文件中,我们这样设置,在build和dev后面加上–mode=[mode]即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"type": "module",
"devDependencies": {
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"html-webpack-plugin": "^5.5.3",
"mini-css-extract-plugin": "^2.7.6",
"style-loader": "^3.3.3",
"webpack": "^5.88.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"scripts": {
"build": "webpack --mode=production",
"dev": "webpack serve --open --mode=development"
}
}

这样一来,开发的时候就使用热更新开发模式,打包的时候就使用生产模式,两不误。