什么是 Webpack
?为什么要用 Webpack
?估计很多小伙伴都知道,但是说不出来~~~记得以前看过一篇文章 愿未来没有 Webpack,里面有一段话:我明明只是想打印一个 Hello World
,却需要安装 1300
个不同的依赖包......当然,这是极端抬杠。不可否认,webpack
确实增加了不少学习成本,但是日常开发中,它也确实带给了我们很多便利。对于咱们苦逼的搬砖党来说,大家都在用它,并且它确实好用,也只能默默留着两行泪去学习~~~
本文综合整理来源:webpack 中文网 和 从基础到实战 手把手带你掌握新版Webpack4.0
在了解 webpack
的用途之前,我们先来看一段非常简单的代码
<div id="root"></div>
<script src="lesson/index.js"></script>
// lesson => index.js
const dom = document.getElementById('root')
// header 部分
const header = document.createElement('div')
header.innerText = "header"
dom.append(header)
// sidebar 部分
const sidebar = document.createElement('div')
sidebar.innerText = "sidebar"
dom.append(sidebar)
// content 部分
const content = document.createElement('div')
content.innerText = "content"
dom.append(content)
很简单的一段代码,就不解读了。这种面向过程的编写方式会导致所有代码都堆在一个文件中,过于冗余且不利于维护。这个时候我们就引入了面向对象编程的概念,那我们就重构一下上面的代码。
<body>
<div id="root"></div>
</body>
<script src="lesson/header.js"></script>
<script src="lesson/sidebar.js"></script>
<script src="lesson/content.js"></script>
<script src="lesson/index.js"></script>
// header.js
function Header() {
const header = document.createElement('div')
header.innerText = "header"
dom.append(header)
}
// sidebar.js
function Sidebar() {
const sidebar = document.createElement('div')
sidebar.innerText = "sidebar"
dom.append(sidebar)
}
// content.js
function Content() {
const content = document.createElement('div')
content.innerText = "content"
dom.append(content)
}
// index.js
const dom = document.getElementById('root')
new Header()
new Sidebar()
new Content()
我们将各个模块所负责的功能都单独放在对应的 js
文件里面,这样便于后期维护,但是这又延伸出了一些问题?
加载多个
js
文件,页面加载速度变慢从代码中看不出文件的相互关系,例如:如果打开
index.js
可能会一头雾水,又要去看html
中的引入文件才行html
中文件的引入顺序不能出错,否则报错之后很难进行排错处理
开发中所有问题的曝光都是为了更完美的解决,写过 Vue
或者 React
的小伙伴估计都清楚项目开发中我们引入文件的方式一般为 import xxx from './xxx'
,这样不仅解决了加载多个 js
运行变慢的问题,并且让文件之间的依赖关系更强,同时引入文件的顺序也不会影响代码的正确执行。我们通过这种方式继续改造一下代码:
<div id="root"></div>
<script src="lesson/index.js"></script>
import Header from './header'
import Sidebar from './sidebar'
import Content from './content'
const dom = document.getElementById('root')
new Header()
new Sidebar()
new Content()
相信大家都知道这么写肯定会报错,首先我们并没有导出就直接引入了,而且浏览器不认识 import
语法。所以这个时候我们就要借助 webpack
来让浏览器识别 import
这种语法结构。
- 首先我们在
lesson
文件夹中使用npm init -y
快速初始化项目。
// lesson
npm init -y
- 初始化
webpack
和webpck-cli
,这里限定了版本号~~~因为webpack
版本更新太快了,这里就先用这个版本,实际项目开发中会专门在webpack.config.js
进行配置。
npm install webpack@4.25.1 webpack-cli@3.1.2 -D
- 然后运行
npx webpack index.js
进行编译
npx webpack index.js
就这样,项目就被我们用 webpack
完成了打包和编译,给我们重新生成了一个 dist
目录,里面有一个 main.js
的文件就是打包所有代码之后生成的对应文件,默认会帮我们进行代码压缩。然后修改 index.html
中 script
的引入指向,综合汇总代码:
<body>
<div id="root"></div>
</body>
<script src="./lesson/dist/main.js"></script>
// index.js // 使用 npx webpack index.js 进行打包
import Header from './header'
import Sidebar from './sidebar'
import Content from './content'
new Header()
new Sidebar()
new Content()
// Header
function Header() {
const dom = document.getElementById('root')
const header = document.createElement('div')
header.innerText = "header"
dom.append(header)
}
// 请导出
export default Header
// Sidebar
function Sidebar() {
const dom = document.getElementById('root')
const sidebar = document.createElement('div')
sidebar.innerText = "sidebar"
dom.append(sidebar)
}
export default Sidebar
// Content
function Content() {
const dom = document.getElementById('root')
const content = document.createElement('div')
content.innerText = "content"
dom.append(content)
}
export default Content
一个小小的栗子下来,是不是对 webpack
能做什么有了一定的了解。有没有认为webpack
是 js
的一个翻译器,帮我们把 js
的高级语法转换为浏览器可以理解的语法~~~其实 webpack
远远没有我们想象的那么强大(当然还是很强大的),它只认识 import
这种语法,像 ES6
的一些新 API
其实 webpack
并不能认识,需要借助 bable
帮我们处理(这是后话~~)。webpack
的核心定义是:模块打包工具。
我们日常开发中通过 import
其实引入的就是我们自己写入的模块,而 webpack
做的事情就是把这些模块进行整合打包处理。当然模块的引入方式不仅仅只有 import
,像我们在 node
中使用的 require
也可以通过 webpack
进行打包。其实 webpack
刚开始的时候只支持 js
模块打包,但是随着技术的迭代更新和发展,现在 webpack
同时支持 img
、css
、字体
等不同种类的模块打包。
此处延伸扩展学习文档:webpack 模块、模块方法、模块变量
搭建 Webpack 环境
Webpack
是基于 node.js
开发的模块打包工具,它本质上是由 node
实现的。所以搭建 Webpack
环境首先要安装 node
的环境,这里就不累赘介绍 node
的安装了~~~首先我们创建了一个 webpack-demo
的文件夹,然后命令行进入到这个文件夹,老规矩先来个 npm init -y
,它的含义是可以快速帮我们以 node
规范的形式创建一个项目或者创建一个 node
的包文件。此时即帮我们生成了一个 packge.json
的文件,接下来就是安装 webpack
。
- 全局安装
Webpack
(不推荐)
npm install webpack webpack-cli -g
如果全局安装成功,此时运行 webpack-v
就可以打印出对应的版本号。当然这种全局安装的方式非常不推荐,因为 webpack
现在的版本更新太快了,很多以前老版本的配置在新版本中可能就被移除了~~~举个栗子:如果我们两个项目都用 webpack
进行打包,一个项目当初是通过 webpack 3.0
进行配置的,而另一个项目是通过 webpack 4.0
进行配置的,此时用我们全局安装的 webpack
进行打包,就会因为版本不同出现问题。所以就引入了另一种安装 webpack
的方法,当然在这之前我们要卸掉刚刚全局安装的 webpack
。
npm uninstall webpack webpack-cli -g
- 在项目内安装
webpack
(推荐)
进入我们的 webpack-demo
文件夹,在项目内进行安装:
npm install webpack webpack-cli --save -dev
// --save -dev === -D 所以也可以写成下面这样:
// npm install webpack webpack-cli -D
安装完成之后,文件夹中就会多出一个 node_modules
的文件夹,当然此时如果我们输入 webpack -v
是无法查看对应版本信息的,因为 node
在全局中无法找到 webpack
指令,所以此时可以借助 npx webpack -v
来查看我们项目中 webpack
的版本,因为 npx
会帮助我们在项目的 node_modules
文件夹中去找 webpack
。当然日常开发中我们一般会锁定一个 webpack
的稳定版本,所以此时我们在安装的时候可以指定对应的版本号:
npm install webpack@4.25.1 webpack-cli@3.1.2 -D
如果我们不知道 webpack
有哪些版本,可以直接通过如下命令查看它的所有版本信息:
npm info webpack
- 对
webpack.config.js
进行基础配置
前面打包都是通过 npx webpack index.js
来进行的,这是因为我们指定了打包的文件为 index.js
。日常开发中,我们会对 webpack
进行相关配置,里面可以指定打包的入口文件,打包输出的地址等等......此时就我们可以新建一个配置文件 webpack.config.js
:
// webpack.config.js
const path = require('path')
module.exports = {
entry: './index.js', // 项目打包的入口文件
output: { // 打包的最终文件放在哪里
filename: 'bundle.js', // 打包生成的文件名
path: path.resolve(__dirname, 'dist') // 打包生成文件的文件夹名称
}
}
上述代码就是 webpack
最基础的配置文件,它规定了打包的入口文件为 index.js
,打包完成后生成的文件名为 bundle.js
,同时 bundle.js
会放置在你规定的 dist
文件夹下。此时我们运行 npx webpack
即可按照我们制定的规则进行打包。
同 vue.config.js
的设置规则一样,webpack.config.js
的名称也是官方规定好的,不能随意更改这个名字。如果此时我们将 webpack.config.js
改为 webpackconfig.js
,那我们要怎么样才能正常运行代码呢?此时需要手动指定 webpackconfig.js
作为我们的配置文件,可以使用如下方法:
npx webpack --config webpackconfig.js
- 结构优化
了解了所有的基础打包步骤之后,我们可以对代码整体的结构进行优化。新建一个 src
目录用于放置我们代码中的源代码部分(index.js、header.js、sidebar.js、content.js
),然后将 index.html
移入到 dist
目录下,记得修改 index.html
引入打包后的脚本文件的地址,因为我们改动了打包的入口文件 index.js
的地址,所以 webpack.config.js
中也要进行修改:
const path = require('path')
module.exports = {
entry: './src/index.js', // 项目打包的入口文件
output: { // 打包的最终文件放在哪里
filename: 'bundle.js', // 打包生成的文件名
path: path.resolve(__dirname, 'dist') // 打包目录
}
}
我们知道,在 vue
项目的构建中,我们通常的打包命令为 npm run build
,虽然我们这个项目只是一个入门基础学习项目,但是我们也想用 vue
的项目解构和打包指令进行打包,此时就可以配置 npm scripts
,即修改 package.json
文件中的 scripts
:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"keywords": [],
"scripts": {
"build": "webpack" // 使用 bulid 映射 webpack 指令
},
"author": "Chen",
"license": "ISC",
"devDependencies": {
"webpack": "^4.25.0",
"webpack-cli": "^4.1.0"
},
"dependencies": {
"file-loader": "^6.1.1"
}
此时我们就可以通过 npm run build
对我们的项目进行整体打包了,最终我们得到一个类似 vue
项目的结构,具体结构图如下:
- 综合小结
经过上述一系列操作,我们也算是完成了一个初步的打包 demo
,同时我们也总结一下 webpack
的三种打包方式:
global
即全局安装webpack
webpack index.js
local
项目中局部安装webpack
npx webpack index.js
npm scripts
修改scripts
配置
npm run build => webpack
最终我们也算是得到了一个类似 vue-cli
脚手架帮我们搭建的项目结构,那么回过头来,我们在安装 webpack
的时候同时安装了 webpack-cli
这个东西,那么 webpack-cli
有什么用呢?
webpack-cli
的作用就是可以使我们在命令行里正确运行webpack
这个命令,如果我们不安装这个包,那么就无法在命令行里运行webpack
或者npx webpack
这样的命令。
此处可以延伸扩展学习:webpack 起步
- 查漏补缺
我们通过 npm run build
打包之后,命令行也给我们输出了如下信息:
这些信息都是什么意识呢?我们一个一个来瞅一瞅:
Hash
:本次打包对应的唯一哈希值Version
:打包使用的webpack
版本Time
:当前打包的整体耗时是411ms
Asset
:打包出了一个bundle.js
文件Size
:bundle.js
的文件大小Chunks
:每一个js
文件对应的ID
Chunk Name
:每一个js
文件对应的名字
那么问题来了,这里为什么是 main
呢,我们好像全程都没有用到过 main
这个词,其实这个 main
来源于 webpack.config.js
,如下栗子:
// webpack.config.js
const path = require('path')
module.exports = {
mode: 'production',
entry: {
main: './src/index.js'
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
我们前面对 entry
的配置其实是一种简写模式,其实真正在打包过程中 entry
的配置应该如上代码,main
指向的就是打包的入口文件。上述代码中我们还设置了一个 mode
,webpack
打包时如果我们没有填写该项,即会默认使用 production
模式,即打包出来的 bundle.js
文件会被压缩。mode
还可选值为 development
,此时打包生成的 bundle.js
文件就不会被压缩。
webpack
入门基础配置基本就是以上这些内容,什么是 loader
?什么是 plugins
? 什么是 babel
?就让我们一点一滴在后续剥开它们神秘的面纱。再次强烈推荐大家学习慕课网 Dell Lin
老师的 从基础到实战 手把手带你掌握新版Webpack4.0 课程,老师所有的课程说实话都非常棒,大家该剁手时一定要毫不留情啊!!!
此整理仅供记录学习,如果文中有不对的地方或者理解有误的地方欢迎大家提出并指正。每一天都要相对前一天进步一点,加油!!!