type
Post
status
Published
date
May 1, 2023
slug
webpack-playground-01
summary
本文首先从Webpack开始,再认识一下这个前端程序员的老朋友。今天几乎所有前端项目都会采用TypeScript开发,采用模块化的代码组织方式,使用React这样的单页应用框架。在工作中我接触到的几乎所有项目都选择Webpack作为构建工具。Webpack本身也有着优秀的设计思想,抛开工具用途外,也很值得我们每一个程序员学习。
tags
开发
前端
category
学习思考
icon
password
Property
May 21, 2023 09:11 AM
笔者毕业快两年了,一直从事前端开发的工作。说来惭愧,前端领域内的知识到现在也不能算成体系地学过,大都是结合工作需要进行自学。转码以来一直在车企工作,前端算是较为边缘的岗位,可以说是其他业务的工具角色,在技术精进这块确实感到有点原地踏步了。
前端技术迭代很快,新的框架和工具不断出现,也就更需要前端工程师掌握体系化的知识,掌握系统性解决前端问题的思想。只有成体系地掌握最基本的东西,才能适应不断发展的新技术,保持职业生涯可持续发展。笔者是非科班自学从业至今,深知保持自学的重要性。因此,从本文开始,笔者会开启一系列文章,着重记录工作中的一些问题和有趣的知识、学习并回顾前端知识体系内的核心技术。
本文首先从Webpack开始,再认识一下这个前端程序员的老朋友。今天几乎所有前端项目都会采用TypeScript开发,采用模块化的代码组织方式,使用React这样的单页应用框架。在工作中我接触到的几乎所有项目都选择Webpack作为构建工具。Webpack本身也有着优秀的设计思想,抛开工具用途外,也很值得我们每一个程序员学习。
本篇将参考https://webpack.wuhaolin.cn/1入门/教程,给出一个使用webpack从0搭建一个可用前端项目的例子。

Webpack简介

以下是Webpack官方文档的描述:
Webpack是一个用户现代JavaScript应用程序的静态模块打包工具。当webpack处理应用程序时,它会在内部从一个或者多个入口点(entry point)构建一个依赖图,然后将项目中所需的每一个模块组合成一个或者多个bundles,它们均为静态资源,用于展示你的内容。
这个描述给出了webpack作为工具的用途,同时阐述了它的工作原理。其实我们可以从另一个角度来理解Webpack是什么,即如果我们项目中不用它(也不用其他类似的构建工具),那么会发生什么?第一,产生目标代码会需要问题。我们的代码是使用TypeScript或者EcmaScript较新版本来编写的,浏览器直接运行会出问题,那么我们需要借助编译工具来编译成较低的EcmaScript版本,这个编译器还需要准确识别我们开发时组织代码采用的模块系统(例如是CommonJS还是ES模块),编译器还需要对最终目标代码进行优化,例如去掉那些没有真正用到的模块,混淆代码,减少体积等。我们知道TSC编译器帮助我们编译TypeScript代码为JavaScript,Babel帮助我们将更新的JavaScript编译为兼容性更好的旧版本JavaScript。但是它们直接拿来晚上上面的任务,可能还是不够的。另外,项目中使用React或者Vue,都会引入新的语法或者扩展的语法,这都需要引入新的编译任务,整合这些编译工具,最终达成生成尽可能小的JavaScript代码文件的目标,就是Webpack要做的事情之一。当然前端代码库中,除了JavaScript文件及其超集或拓展外,还有样式文件(部分css扩展语法,如SCSS也支持模块),例如图片等其他静态资源文件,这就带来了更多的复杂性,这部分代码如何产生最终的文件,也是一个麻烦事儿。第二,站在软件工程的角度,需要一个插件化的工具帮助我们完成自动化事务。在开发过程中,我们可能需要编写大量的测试、针对项目测试、部署等阶段都会有一些自定义程序需要注入,如果工具可以自动化帮助我们处理这部分工作那该多好?所以Webpack就是用来解决上述问题的强大工具。了解webpack的朋友知道,上面两个问题就是webpack的核心,一个通过loader解决了,一个通过plugin解决了。
webpack只能理解JavaScript和JSON文件,这是它开箱可用的自带能力。loader让webpack能够处理其他类型的文件,并将它们转化为有效模块,以供程序员使用,以及被添加到依赖图中。
插件plugin可以用来执行范围更广的任务,包括:打包优化,资源管理,注入环境变量等。

上手Webpack

为了直观表现Webpack的用法,我们建立一个示例项目。首先,建立一个目录my-project,在目录下执行npm init。会产生一个package.json文件,我们可以安装本地依赖了。
这里我使用yarn作为包管理工具,安装webpack的依赖
yarn add --dev webpack webpack-cli
安装完成后,在package.json中添加script
"build": "webpack --mode production --config webpack.config.js"
在项目根目录下新建文件webpack.config.js
const path = require("path"); module.exports = { entry: "./src/main.js", output: { filename: "bundle.js", path: path.resolve(__dirname, "./dist"), }, };
在根目录下新建src目录,创建main.js文件:
import { show } from "./util"; show("webpack");
util.js文件:
export function show(content) { document.getElementById("app").innerText = "Hello, " + content; }
新建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> <div id="app"></div> <script src="../dist/bundle.js"></script> </body> </html>
至此,我们给出了一个最基本的项目,包含了使用ES模块组织的JavaScript代码文件,指定了代码的入口和希望得到的打包文件的出口。
运行yarn build,我们就可以在dist目录下找到bundle.js了!这是很大的成果,意味着这些简单配置的引入就能让我们在webpack帮助下自由地开发按照ES模块组织的代码了。
接下来我们想引入css。
首先,在src目录下创建main.css文件:
#app { text-align: center; }
然后在main.js中使用ES模块引入的语法来引入这个css文件(以后我们会了解到,在Webpack中一切文件皆是模块)。
import { show } from "./util"; import "./main.css"; import "./component.css"; show("webpack");
如果这时我们直接尝试yarn build,控制台会输出错误日志,告诉我们缺少loader。
这其实是因为webpack并不对css文件提供开箱支持,我们需要安装loader并在webpack配置中引入它们。
yarn add --dev style-loader css-loader
安装好loader后,在webpack.config.js文件中使用它们:
const path = require("path"); module.exports = { entry: "./src/main.js", output: { filename: "bundle.js", path: path.resolve(__dirname, "./dist"), }, module: { rules: [ { // parse CSS files test: /\.css$/, use: [ "style-loader", "css-loader" ], }, ], }, };
至此,我们可以正确打包css文件了。执行yarn build,在浏览器中打开index.html文件,就能看到样式生效了。
 
手写一个PromiseCSS选择器优先级