打个包试一试
先安装好环境
$ node -v
v12.14.0
$ npm init -y
$ npm install -D webpack@3.6.0
项目目录结构:
my-mall-admin-web
├── build -- 存储打包好的文件
├── node_modules -- 安装的node模块
├── src
| ├── greet.js
| ├── index.js -- 无用的文件,测试用
| └── main.js
├── index.html
└── package.json
再看各个文件中的内容。main.js,引用了greet.js中的内容,在html文件中添加东西:
const greeter = require('./greet.js');
document.querySelector('#root').appendChild(greeter());
greet.js生成一个html代码块:
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = "Hi there and greetings!";
return greet;
}
index.html,这里引用了build/bundle.js,但是我们根本没有写它:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<body>
<div id="root">xxx</div>
<script src="build/bundle.js"></script>
</body>
</html>
打包打包打包:
$ npx webpack src/main.js build/bundle.js
Hash: 798edb3b82b69716e2d1
Version: webpack 3.6.0
Time: 54ms
Asset Size Chunks Chunk Names
bundle.js 2.8 kB 0 [emitted] main
[0] ./src/main.js 95 bytes {0} [built]
[1] ./src/greet.js 151 bytes {0} [built]
指定把src/main.js打包成build/bundle.js,webpack识别出main.js引用了greet.js,就把这个也打包了。没有引用的index.js根本不会理他。
这时候在浏览器中,输入index.html的地址,就能看到显示了'Hi there and greetings!'。
这样,我们就把2个js文件打包成了一个js文件,它们之间的引用关系我们不用操心,webpack会自动处理。打包后的js文件功能和我们自己写的原始的两个js文件所实现的功能一样。这样,就能实现js文件的模块化,每个js文件写一个模块,整合到一起构成复杂的功能。和java类一样~
手写命令太麻烦
前面我们执行打包命令时,把需要打包的文件和目标文件都写到了命令行中,每次都写多麻烦,文件多了还不好用。所以需要配置文件。
在目录里新建一个webpack.config.js
文件,这就是webpack默认的配置文件:
module.exports = {
entry: __dirname + "/src/main.js", // __dirname是node全局变量,指向脚本执行时所在目录
output: {
path: __dirname + "/build",
filename: "bundle.js"
}
}
现在目录结构如下:
my-mall-admin-web
├── build -- 存储打包好的文件
├── node_modules -- 安装的node模块
├── src
| ├── greet.js
| ├── index.js -- 无用的文件,测试用
| └── main.js
├── index.html
├── package.json
└── webpack.config.js -- webpack默认配置文件
然后打包:
$ npx webpack # 注意这里什么参数都没有带
Hash: 798edb3b82b69716e2d1
Version: webpack 3.6.0
Time: 80ms
Asset Size Chunks Chunk Names
bundle.js 2.8 kB 0 [emitted] main
[0] ./src/main.js 95 bytes {0} [built]
[1] ./src/greet.js 151 bytes {0} [built]
打包结果一摸一样!
用node管理命令
node用package.json
文件管理这个项目,提供了统一设置脚本命令的地方。我们可以把命令放到package.json中,如果脚本变更也会更方便:
{
...
"scripts": {
"build": "webpack"
}
...
}
执行npm run dev
命令:
$ npm run build
> my-mall-admin-web@1.0.0 build E:\pro\web\231008-mall\dev\my-mall-admin-web
> webpack
Hash: 798edb3b82b69716e2d1
Version: webpack 3.6.0
Time: 48ms
Asset Size Chunks Chunk Names
bundle.js 2.8 kB 0 [emitted] main
[0] ./src/main.js 95 bytes {0} [built]
[1] ./src/greet.js 151 bytes {0} [built]
和直接执行webpack命令一摸一样!
上http服务器
之前我们测试都是直接在浏览器中输入index.html文件的位置,但真实环境下都是通过浏览器访问一个http服务器。我们能把http服务器和webpack打包整合到一起吗?
完全可以!webpack-dev-server
就是这样一个工具:
$ npm instalal -D webpack-dev-server@2.9.1 # 安装
$ npx --no-install webpack-dev-server -v # 不下载远程模块,只执行本地安装的webpack-dev-server
webpack-dev-server 2.9.1
webpack 3.6.0
webpack-dev-server也使用webpack.config.js
作为其默认配置文件,它有自己的配置参数:
module.exports = {
entry: __dirname + "/src/main.js", // __dirname是node全局变量,指向脚本执行时所在目录
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
// webpack-dev-server的配置参数
devServer: {
inline: true // 源文件变动时自动刷新页面
}
}
package.json中也修改一下,添加上webpack-dev-server的命令:
{
...
"scripts": {
"build": "webpack",
"server": "webpack-dev-server"
}
...
}
把build/bundle.js
删了,运行npm run server
,看看会不会自动打包并启动http服务:
$ npm run server
> my-mall-admin-web@1.0.0 server E:\pro\web\231008-mall\dev\my-mall-admin-web
> webpack-dev-server
Project is running at http://localhost:8080/
webpack output is served from /
Hash: 667b4715dc9202865caa
Version: webpack 3.6.0
Time: 641ms
Asset Size Chunks Chunk Names
bundle.js 416 kB 0 [emitted] [big] main
[41] multi (webpack)-dev-server/client?http://localhost:8080 ./src/main.js 40 bytes {0} [built]
[42] (webpack)-dev-server/client?http://localhost:8080 7.23 kB {0} [built]
[43] ./node_modules/url/url.js 23.5 kB {0} [built]
[44] ./node_modules/punycode/punycode.js 14.7 kB {0} [built]
[45] ./node_modules/qs/lib/index.js 211 bytes {0} [built]
[60] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]
[61] ./node_modules/ansi-regex/index.js 135 bytes {0} [built]
[62] ./node_modules/loglevel/lib/loglevel.js 9.56 kB {0} [built]
[63] (webpack)-dev-server/client/socket.js 1.04 kB {0} [built]
[64] ./node_modules/sockjs-client/lib/entry.js 244 bytes {0} [built]
[95] (webpack)-dev-server/client/overlay.js 3.73 kB {0} [built]
[101] (webpack)/hot nonrecursive ^\.\/log$ 170 bytes {0} [built]
[103] (webpack)/hot/emitter.js 77 bytes {0} [built]
[105] ./src/main.js 95 bytes {0} [built]
[106] ./src/greet.js 151 bytes {0} [built]
+ 92 hidden modules
webpack: Compiled successfully.
看日志,正常打包成功了,但是build目录下没有文件,浏览器中输入“http://localhost:8080”也没有正常显示。为什么?
原来webpack-dev-server打包好的bundle.js只在内存中,不会放到文件系统上,所以需要修改下index.html文件,直接从webpack-dev-server这个http服务器里取bundle.js。注意这里没有指定bundle.js的路径:
<script src="bundle.js"></script>
刷新浏览器,这次就好了。重启webpack-dev-server,也能正常显示。
总结:webpack-dev-server是一个http服务器,运行同时会使用webpack对项目进行打包。但是打包的东西只在内存中,不会存到磁盘。可以使用"http://localhost:8080/webpack-dev-server"查看内存中的文件。命令行支持--open
自动打开浏览器。
试试打包CSS
我想写一个css文件,webpack能给我打包吗?
能!现在我们就写一个src/main.css:
html {
box-sizing: border-box;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin: 0;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
h1, h2, h3, h4, h5, h6, p, ul {
margin: 0;
padding: 0;
}
div {
background-color: blue;
}
然后在main.js中引入这个css文件:
const greeter = require('./greet.js');
import './main.css'; // 引入css文件
document.querySelector('#root').appendChild(greeter());
webpack默认只认识javascript文件,要让它认识css文件,得加一些东西:
$ npm install -D style-loader@0.23.1 css-loader@0.28.0
把它们配置到webpack.config.js配置文件中,让webpack能识别它们。这里新增了一个module配置,表明webpack对css模块如何处理:
module.exports = {
entry: __dirname + "/src/main.js", // __dirname是node全局变量,指向脚本执行时所在目录
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
// webpack-dev-server的配置参数
devServer: {
inline: true // 源文件变动时自动刷新页面
},
// 处理模块
module: {
rules: [
{ // 对于css文件,使用style-loader和css-loader进行处理
test: /\.css$/i,
use: ['style-loader', 'css-loader'] // 注意顺序不能反
}
]
}
}
执行npm run server
,启动webpack-dev-server,这样就会自动识别出css文件了:
$ npm run server
> my-mall-admin-web@1.0.0 server E:\pro\web\231008-mall\dev\my-mall-admin-web
> webpack-dev-server
Project is running at http://localhost:8080/
webpack output is served from /
Hash: 4052c51c5b4600560383
Version: webpack 3.6.0
Time: 1081ms
Asset Size Chunks Chunk Names
bundle.js 489 kB 0 [emitted] [big] main
[41] multi (webpack)-dev-server/client?http://localhost:8080 ./src/main.js 40 bytes {0} [built]
[42] (webpack)-dev-server/client?http://localhost:8080 7.23 kB {0} [built]
[43] ./node_modules/url/url.js 23.5 kB {0} [built]
[44] ./node_modules/punycode/punycode.js 14.7 kB {0} [built]
[45] ./node_modules/qs/lib/index.js 211 bytes {0} [built]
[60] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]
[61] ./node_modules/ansi-regex/index.js 135 bytes {0} [built]
[62] ./node_modules/loglevel/lib/loglevel.js 9.56 kB {0} [built]
[63] (webpack)-dev-server/client/socket.js 1.04 kB {0} [built]
[95] (webpack)-dev-server/client/overlay.js 3.73 kB {0} [built]
[101] (webpack)/hot nonrecursive ^\.\/log$ 170 bytes {0} [built]
[103] (webpack)/hot/emitter.js 77 bytes {0} [built]
[105] ./src/main.js 139 bytes {0} [built]
[106] ./src/greet.js 151 bytes {0} [built]
[107] ./src/main.css 1.07 kB {0} [built]
+ 101 hidden modules
webpack: Compiled successfully.
输出日志中可以看到,最后增加了对./src/main.css的解析。打包好的文件统一放到了bundle.js文件中,也就是说我们的css文件被放到了js文件中。
打开浏览器,输入地址,可以看到div的背景变成了蓝色。
项目地址:E:\pro\web\231008-mall\dev\my-mall-admin-web,”打包css"标签。
总结:webpack使用loader来加载处理css、png等不同的模块:
- loader 本质上是一个函数,output=loader(input) // input可为工程源文件的字符串,也可是上一个loader转化后的结果;
- 第一个 loader 的传入参数只有一个:资源文件(resource file)的内容;
- loader支持链式调用,webpack打包时是按照数组从后往前的顺序将资源交给loader处理的。例如我们配置的
use: ['style-loader', 'css-loader']
,就先用css-loader加载css,然后用style-loader把css注入到js代码中
插件:扩展webpack功能
给所有打包的文件都标记上版权
webpack支持使用插件来进行功能扩展。我们来添加一个webpack自带的插件,如果使用其它插件,需要先使用npm install -D xxx
安装。
在webpack.config.js文件中添加插件:
const webpack = require('webpack')
module.exports = {
...
// 处理模块
module: {
...
},
plugins: [ // 注意这里是[]而不是{}
new webpack.BannerPlugin('这个东西是我的,你不要拿走')
]
}
这里我们使用webpack自带的一个插件,这个插件把打包之后的js文件,添加一些说明。
执行npm run server
,浏览器中输入"http://localhost:8080/webpack-dev-server",点击进入bundle.js,可以看到第一行有我们写的文字。
总结:插件就是用来实现一些特定的功能。
把CSS和JS分离
css和js放到了一起是不是感觉很奇怪?有没有办法把它们分开?
有!插件extract-text-webpack-plugin
就实现了这个功能。在生产环境上,我们一般把js和css分开,这样效率较高。
安装插件:
$ npm install --save-dev extract-text-webpack-plugin@3.0.0
新建一个webpack.prod.conf.js
,基本和之前的配置文件一样,只是增加了这个插件:
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); // 使用插件分离css和js
module.exports = {
entry: __dirname + "/src/main.js",
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
devServer: {
inline: true
},
module: {
rules: [
{
test: /\.css$/i,
use: ExtractTextPlugin.extract({ // 注意这里也使用了这个插件
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new webpack.BannerPlugin('这个东西是我的,你不要拿走'),
new ExtractTextPlugin("style.css") // 把插件添加进来
]
}
再修改一下package.json,增加两条脚本:
{
...
"scripts": {
"build": "webpack",
"server": "webpack-dev-server",
"prod-build": "webpack --config webpack.prod.conf.js",
"prod-server": "webpack-dev-server --config webpack.prod.conf.js"
},
...
}
执行npm run prod-server
:
$ npm run prod-server
> my-mall-admin-web@1.0.0 prod-server E:\pro\web\231008-mall\dev\my-mall-admin-web
> webpack-dev-server --config webpack.prod.conf.js
Project is running at http://localhost:8080/
webpack output is served from /
Hash: 508d5662a9c11d1808e2
Version: webpack 3.6.0
Time: 1141ms
Asset Size Chunks Chunk Names
bundle.js 416 kB 0 [emitted] [big] main
style.css 407 bytes 0 [emitted] main
[41] multi (webpack)-dev-server/client?http://localhost:8080 ./src/main.js 40 bytes {0} [built]
[42] (webpack)-dev-server/client?http://localhost:8080 7.23 kB {0} [built]
[43] ./node_modules/url/url.js 23.5 kB {0} [built]
[44] ./node_modules/punycode/punycode.js 14.7 kB {0} [built]
[45] ./node_modules/qs/lib/index.js 211 bytes {0} [built]
[60] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]
[61] ./node_modules/ansi-regex/index.js 135 bytes {0} [built]
[62] ./node_modules/loglevel/lib/loglevel.js 9.56 kB {0} [built]
[63] (webpack)-dev-server/client/socket.js 1.04 kB {0} [built]
[95] (webpack)-dev-server/client/overlay.js 3.73 kB {0} [built]
[101] (webpack)/hot nonrecursive ^\.\/log$ 170 bytes {0} [built]
[103] (webpack)/hot/emitter.js 77 bytes {0} [built]
[105] ./src/main.js 139 bytes {0} [built]
[106] ./src/greet.js 151 bytes {0} [built]
[107] ./src/main.css 41 bytes {0} [built]
+ 101 hidden modules
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/index.js!src/main.css:
[0] ./node_modules/css-loader!./src/main.css 595 bytes {0} [built]
[1] ./node_modules/css-loader/lib/css-base.js 2.19 kB {0} [built]
[2] ./node_modules/buffer/index.js 48.6 kB {0} [built]
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
[4] ./node_modules/base64-js/index.js 3.93 kB {0} [built]
[5] ./node_modules/ieee754/index.js 2.15 kB {0} [built]
[6] ./node_modules/isarray/index.js 132 bytes {0} [built]
webpack: Compiled successfully.
从日志中可以看到生成了bundle.js和style.css两个文件。浏览器中输入“http://localhost:8080/webpack-dev-server”,可以看到bundle.js和sytle.css两个文件存在于这个http服务器的内存中。
再修改下index.html,把style.css加上:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="root">xxx</div>
<script src="bundle.js"></script>
</body>
</html>
这样,浏览器中就能正常显示了。
自动生成index.html
刚才我们打包js和css时,都需要修改index.html文件,好让它引入我们打包的js和css文件。有办法让它自动生成吗?
有!使用插件html-webpack-plugin
。
安装插件:
$ npm install -D html-webpack-plugin@2.30.1
修改webpack.config.js和webpack.prod.conf.js,添加上这个插件:
...
const HtmlWebpackkPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [ // 注意这里是[]而不是{}
...
new HtmlWebpackkPlugin({
filename: "index.html",
template: "index.html"
})
]
}
执行npm run prod-server
:
$ npm run prod-server
> my-mall-admin-web@1.0.0 prod-server E:\pro\web\231008-mall\dev\my-mall-admin-web
> webpack-dev-server --config webpack.prod.conf.js
Project is running at http://localhost:8080/
webpack output is served from /
Hash: 452c0e7f4986ba1d6cb8
Version: webpack 3.6.0
Time: 1326ms
Asset Size Chunks Chunk Names
bundle.js 416 kB 0 [emitted] [big] main
style.css 407 bytes 0 [emitted] main
index.html 374 bytes [emitted]
[41] multi (webpack)-dev-server/client?http://localhost:8080 ./src/main.js 40 bytes {0} [built]
[42] (webpack)-dev-server/client?http://localhost:8080 7.23 kB {0} [built]
[43] ./node_modules/url/url.js 23.5 kB {0} [built]
[44] ./node_modules/punycode/punycode.js 14.7 kB {0} [built]
[45] ./node_modules/qs/lib/index.js 211 bytes {0} [built]
[60] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]
[61] ./node_modules/ansi-regex/index.js 135 bytes {0} [built]
[62] ./node_modules/loglevel/lib/loglevel.js 9.56 kB {0} [built]
[63] (webpack)-dev-server/client/socket.js 1.04 kB {0} [built]
[95] (webpack)-dev-server/client/overlay.js 3.73 kB {0} [built]
[101] (webpack)/hot nonrecursive ^\.\/log$ 170 bytes {0} [built]
[103] (webpack)/hot/emitter.js 77 bytes {0} [built]
[105] ./src/main.js 139 bytes {0} [built]
[106] ./src/greet.js 151 bytes {0} [built]
[107] ./src/main.css 41 bytes {0} [built]
+ 101 hidden modules
Child html-webpack-plugin for "index.html":
1 asset
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./index.html 655 bytes {0} [built]
[1] ./node_modules/lodash/lodash.js 544 kB {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/index.js!src/main.css:
[0] ./node_modules/css-loader!./src/main.css 595 bytes {0} [built]
[1] ./node_modules/css-loader/lib/css-base.js 2.19 kB {0} [built]
[2] ./node_modules/buffer/index.js 48.6 kB {0} [built]
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
[4] ./node_modules/base64-js/index.js 3.93 kB {0} [built]
[5] ./node_modules/ieee754/index.js 2.15 kB {0} [built]
[6] ./node_modules/isarray/index.js 132 bytes {0} [built]
webpack: Compiled successfully.
从日志中看出,打包生成了3个文件。从浏览器中看也正常。
总结
webpack是一个编译和打包工具,用来把具有相互引用关系的javascript文件编译打包成一个文件。
loader提高了webpack的打包范围,使其不仅可以处理javascript文件,还可以处理css、json、vue等各种各样的文件。
plugin提高了webpack的处理能力,使其不仅可以完成打包,还可以完成自定义写入、分离css和js、自动生成html文件等各种各样的能力。
webpack处理的所有文件,都是从“入口”处开始查找的,没有被入口文件及其相关依赖文件引用的文件,是不会被处理的。比如我们的src/index.js,就永远不会被webpack处理。webpack的入口在webpack.config.js中使用entry
指定。
webpack只是一个自动化工具,减轻了我们的工作。如果没有webpack,我们自己手工把各个javascript、css、json、vue文件之间的依赖关系分析出来,再整合成一个或一组文件,让浏览器去识别,也是可行的。不过估计没人这么做,机器能做的事,为什么要人去做。
参考资料
- 入门 Webpack,看这篇就够了 ,这个文档的主要参考资料
- npx 使用教程
- webpack-dev-server编译文件写入磁盘
- DevServer ,这是webpack-dev-server官方配置文档
- webpack-v3官网文档镜像 ,不要转成中文,中文就不是v3版本了
- 快速简明教程: webpack ,介绍了一些实用插件
- Webpack 教程 ,一个比较详细的教程,有介绍require和import
- webpack 入门教程 ,介绍了一些实用loader和插件
- 吐血整理的webpack入门知识及常用loader和plugin
- webpack 的 loader 和 plugin 你真的弄懂了吗 ,简要介绍了loader和plugin的原理和如何开发
- Webpack入门:常用loader和plugin配置 ,介绍了一些常用loader和plugin,不过不全
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。