包的类型
- 项目包:用于编写项目和和业务逻辑
- 软件包:封装工具和方法进行使用
- 本地软件包:当前项目内使用,封装属性和方法,存在于 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
| 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")
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,可以通过以下命令执行初始化。
若我们需要安装某个软件包,则通过以下命令执行安装,软件包会存放在node_modules目录下,软件包的版本则会保存在package-lock.json文件中,用作固化版本。
我们使用下载的软件包时,可以直接通过包名引入,而不用通过路径。
当我们协同开发时,git不会同步我们的node_modules文件夹。可能别人使用了某个包,但是我们自己没有使用,所以本地没有这个包。我们可以通过以下命令,根据package.json文件,安装本地缺少的包。
常用的软件包
nodemon
一个全局软件包,需要全局安装。通过这个nodemon启动 js 文件,可以检测代码更改,自动重启程序。
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
| import '../Login/login.css'
console.log("hello, kahvia !")
console.log("what's up ?")
|
以上都完成后,即可打包。
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'
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'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
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: { 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'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
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: { minimizer: [ new CssMinimizerPlugin() ] } }
|
在asset类型下,大于8kb的图片会直接作拷贝处理,小于8kb的会转为base64,通过uri的方式替换项目中的src引用。
类似于css打包,我们将要打包的图片也引入入口JS文件即可。
1 2 3 4 5 6 7 8 9
| 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'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
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({ }), 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: { 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" } }
|
通过自定义命令启动。
这种情况下,会自动创建一个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
| <!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" } }
|
这样一来,开发的时候就使用热更新开发模式,打包的时候就使用生产模式,两不误。