一、前言
基础篇主要围绕以下几点展开:
- 为什么会使用 Webpack?
- Webpack 打包流程
- Webpack 的本源
- Webpack 的配置文件
- 简化 Webpack 打包流程
1. 简单案例
在前端开发中,如果一个页面的逻辑非常多,那么我们就有必要做业务逻辑的划分。
例如,一个网页包含三个部分,分别是:Header、Sidebar、Content,这些全都通过 JavaScript 来编写,并加入到页面中。
文件结构如下:
my-webpack-demo-1/
|- index.html
|- index.js
index.html
<body>
<div id="root"></div>
<script src="./index.js"></script>
</body>
index.js
const dom = document.getElementById('root');
// header
const header = document.createElement('div');
header.innerText = 'header';
dom.appendChild(header);
// sidebar
const siderBar = document.createElement('div');
siderBar.innerText = 'siderBar';
dom.appendChild(siderBar);
// content
const content = document.createElement('div');
content.innerText = 'content';
dom.appendChild(content);
2. 面向对象
a) 封装
在上面的案例中,实际上 Header、Sidebar、Content 各自的业务逻辑如果很多的话,就可以单独封装到一个构造函数(类)中。
文件结构如下:
my-webpack-demo-1/
|- content.js
|- header.js
|- index.html
|- index.js
|- sidebar.js
header.js:
function Header(dom) {
const header = document.createElement('div');
header.innerText = 'header';
dom.appendChild(header);
}
sidebar.js
function Sidebar(dom) {
const siderBar = document.createElement('div');
siderBar.innerText = 'siderBar';
dom.appendChild(siderBar);
}
content.js
function Content(dom) {
const content = document.createElement('div');
content.innerText = 'content';
dom.appendChild(content);
}
b) 引入
封装完毕后,引入到 index.html 中,并在 <script src="./index.js"></script>
前导入三个 js 文件。
index.html
<body>
<div id="root"></div>
<script src="./header.js"></script>
<script src="./sidebar.js"></script>
<script src="./content.js"></script>
<script src="./index.js"></script>
</body>
index.js
const dom = document.getElementById('root');
// header
new Header(dom);
// side-bar
new Sidebar(dom);
// content
new Content(dom);
3. 模块化
使用面向对象的方式改进了代码,但是出现了新的问题。什么问题呢?
问题往往发生在 index.html 中引入 js 的先后顺序出现错误。例如,如果先引入 index.js ,之后再引入其他 js 文件,这样顺序不对而导致解析顺序出错,那么必然报错。实际上,我们希望将所有的文件都引入到 index.js 中,然后只引入这个主文件 ( index.js ) 就好。
所以,我们不妨使用 ES6 的模块语法(Module)。
于是,我们需要对代码做一个修改:
- 通过 export 语法导出模块;
- 通过 import 语法引入模块。
a) 功能代码编写与导出
header.js
function Header(dom) {
const header = document.createElement('div');
header.innerText = 'header';
dom.appendChild(header);
}
export default Header;
sidebar.js
function Sidebar(dom) {
const siderBar = document.createElement('div');
siderBar.innerText = 'siderBar';
dom.appendChild(siderBar);
}
export default Sidebar;
content.js
function Content(dom) {
const content = document.createElement('div');
content.innerText = 'content';
dom.appendChild(content);
}
export default Content;
b) 功能代码引入到主文件
导出后,将所有的功能代码统一在 index.js 中引入:
// index.js
// ES Module
import Header from './components/header.js';
import Sidebar from './components/sidebar.js';
import Content from './components/content.js';
const dom = document.getElementById('root');
// header
new Header(dom);
// side-bar
new Sidebar(dom);
// content
new Content(dom);
而 index.html 中只引入 index.js:
<body>
<div id="root"></div>
<script src="./index.js"></script>
</body>
然而,浏览器暂不支持模块语法,会报错。
于是,Webpack 就应运而生了~
二、初识 Webpack
1. 介绍
a) webpack
Webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
https://www.npmjs.com/package/webpack
- 打包 ES Modules,CommonJS 以及 AMD Modules(甚至是组合)。
- 可以在运行时对异步加载的单文件或多个块进行打包(减少初始加载时间)。
- 在编译期间解析依赖项,从而减少运行时大小。
- 加载器(Loaders) 可以在编译时对文件进行预处理。比如,TypeScript to JavaScript, Handlebars strings to compiled functions, images to Base64, etc.
- 高度模块化的 插件(Plugin) 系统。(Highly modular plugin system)
b) webpack-cli
webpack 官方的 CLI (Command Line Interface) 工具。
webpack CLI provides a flexible set of commands for developers to increase speed when setting up a custom webpack project. As of webpack v4, webpack is not expecting a configuration file, but often developers want to create a more custom webpack configuration based on their use-cases and needs. webpack CLI addresses these needs by providing a set of tools to improve the setup of custom webpack configuration.
2. 安装
mkdir webpack-demo
cd webpack-demo
npm init -y
npm i webpack webpack-cli --save-dev
webpack 和 webpack-cli 是两个不同的包,--save-dev 可以简写为 -D,表示保存并写进开发依赖中。
注意:webpack-cli 必须安装,否则运行不了 webpack!
查看版本:
npx webpack -v
npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装!
3. 文件结构
将文件按照如下位置安放:
webpack/
|- /src
|- /components
|- content.js
|- header.js
|- sidebar.js
|- index.js
|- index.html
|- package.json
4. 打包
执行打包命令:
npx webpack-cli
运行结果如下:
打包完成后,就会出现一个 dist 目录,里面有一个 main.js 文件,这就是打包完成的 js 文件。
或者通过:npx webpack 也可以。
5. 效果
在打包结束后,需要修改 index.html 中脚本的引用位置:
<body>
<div id="root"></div>
<script src="./dist/main.js"></script>
</body>
页面效果如下:
网页正常显示。
那么,webpack 做了什么事情?它将原来的文件翻译打包成了浏览器看得懂的 js 文件 ( main.js )。
6. 本源
在某种程度上,我们可以将 webpack 理解为 js 代码翻译器吗?其实不然!
它只是可以识别 js 的模块语法而已,例如,上面的 import、export 语法 ( Header、Sidebar、Content 就是模块。),然而对于其他的 js 语法它是不认识的!
正如它的官方文档所说,Webpack is a module bundler. webpack 是一个模块打包工具!它可以将多个模块打包到一起。另外,对于 CommonJS(Node.js 用)、CMD、AMD 这些模块规范,webpack 也可以识别并打包。
除了 js 文件以外,webpack 还可以打包其他模块文件,例如, ts 文件,css/sass/less/stylus 文件,图片文件等等。
阅读参考:
三、Webpack 配置文件
在第二部分中,我们通过 npx webpack
的形式进行打包,实际上我们用的是 webpack 默认的配置来打包的。
那么如何自定义打包配置呢?
- 在根目录下创建配置文件 ( 默认是:webpack.coonfig.js )
- 编写打包配置项
注意,此时的文件结构如下:
webpack/
|- /src
|- /components
|- content.js
|- header.js
|- sidebar.js
|- index.js
|- index.html
|- package.json
1. 默认的配置文件
在文件根目录下创建:
touch webpack.config.js
webpack.config.js
// webpack 配置文件
const path = require('path'); // node.js 的路径模块
module.exports = {
// entry: './src/index.js', // 入口文件(简写形式)
entry: {
main: './src/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'), // 打包后的路径
filename: 'bundle.js', // 打包后的文件名
}
}
以上是简单的打包配置,配置项包括入口文件、打包路径、打包文件名。
其中,入口文件是指一个项目的主文件,一般来说,所有的模块都会被加入到这个文件中,类似于 vue-cli 中的 main.js 文件。
之后,运行 npx webpack,即可按照此配置文件进行打包。
2. 自定义的配置文件
现在,如果我们并没有将配置文件设置为默认的 webpack.config.js,
而是使用了其他的名字,例如:my-webpack-config.js,
在这种情况下,我们该如何以这个自定义的配置文件作为配置的标准来打包呢?
通过以下命令即可:
npx webpack --config my-webpack-config.js
运行结果如下:
3. 简化打包流程
以上,我们都是通过手动的 npx webpack
来打包的!
实际上,还可以利用 package.json 中的 scripts 字段来编写运行脚本,通过脚本进行打包。
// ...
"scripts": {
"bundle": "webpack"
},
// ...
之后,通过 npm run bundle
就可以打包了。
疑惑:为什么 "bundle" 后面不写成:"npx webpack" 呢?
原因在于,当你运行 npm run bundle 时,它会先去 node_modules 文件夹中去找是否安装了 webpack 这个指令,如果有就会执行了,相当于被翻译成了 webpack 这个命令。这个与 npx webpack 是类似的,但并不是相等的,本文前面有叙述过,请自行查找~
(也就是看 node_modules 中的 webpack 下的 bin 中是否有对应的可执行指令文件,这块需要了解 Node.js 的内容,此篇不论。)
参考:https://webpack.js.org/guides/getting-started/
4. 打包模式
每次打包完,打包内容中总有一段 WARNING 警告,提醒我们设置打包模式(mode)。
默认情况下,它被设置为 'production',我们也可以自行配置:
// webpack.config.js
const path = require('path');
module.exports = {
mode: 'development', // 'development' | 'production'
// entry: './src/index.js',
entry: {
main: './src/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
}
可以配置为开发模式或者生产模式:
- 开发模式:本地环境
- 生产模式:线上环境(代码是压缩的)
具体有何不同,在打包后,打开 dist 文件夹下的 main.js,便可一目了然,此处不再赘述。
小结
以上,是本篇的所有内容。
最后回答一下前言部分的问题:
- 为什么会使用 Webpack?模块化、预处理。
- Webpack 打包流程:确保存在 package.json 的情况下去打包,注意配置项的设置。
- Webpack 的本源:模块打包器,记住是模块。
- Webpack 的配置文件:webpack.config.js,配置项:mode/entry/output
- 简化 Webpack 打包流程:设置 package.json 中的 scripts 字段。
以上,感谢您的阅读~
网友评论