本文将介绍webpack的作用、入门使用,以及webpack打包原理
模块开发
javascript诞生之初,就是服务于网页的脚本语言,相较于c++,java等缺少模块开发功能。在不使用webpack工具,javascript文件只能通过在html文件中使用script标签导入同时还要留意导入的顺序。当然在es6是支持使用原生模块开发,但不够完善
<!-- index.html -->
<script src="a.js"></script>
<script scr="b.js"></script>
<!-- es6原生导入 -->
<script type="module">
import 'a.js';
import 'b.js';
</script>
但我们注意到,这时javascript文件里的代码上下文是处于全局的,不同js文件的同名变量可能会造成冲突或覆盖
// a.js
var num = 114514;
const str = 'this is a.js';
// b.js
var num = 5211314;
const str = 'this is b.js';
// b.js 中的num覆盖 a.js 中的num,而 str 为常量,修改值会报错
此时我们想到使用函数闭包,但是问题在于手动使用函数闭包使得模块开发变得复杂且难以维护,这时使用webpack就可以解决这个问题------模块开发、构建打包,当然除了webpack构建工具外,还有gulp、vite、rollup等。就目前开发生态来说,webpack拥有大量的第三方插件支持和更好的js模块标准(AMD、CMS、ES6等)兼容,学习webpack之后再学习其他构建也能很快上手
简单打包一个应用
说明:使用 npm 还是 yarn 全靠个人喜好哈
-
初始化项目(项目名:webpack-demo)
npm init -y or yarn init -y
-
目录结构如下
. ├── package.json ├── public │ └── index.html # 模版文件 ├── src │ ├── a.js │ ├── b.js │ └── index.js # 入口js文件 └── webpack.config.js
-
下载 一些库
npm install -D html-webpack-pluigin webpack webpack-cli webpack-dev-server or yarn add -D html-webpack-pluigin webpack webpack-cli webpack-dev-server
-
所有文件内容
// package.json 文件内容如下 // 注意:json 不能使用注释,这里只是描述 { "name": "webpack-demo", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "build": "webpack", // 构建 npm run bulid or yarn build "dev": "webpack-dev-server" // 热部署 npm run dev or yarn dev }, "devDependencies": { "html-webpack-plugin": "^5.5.0", // 使用html模版文件,链接js和html模版 "webpack": "^5.74.0", // 核心库 "webpack-cli": "^4.10.0", // 使命令行使用 webpack 命令 "webpack-dev-server": "^4.11.0" // 热部署,适合开发时随时查看构建状态 } } // 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>webpack-demo</title> <style> body { width:100%; } div { width: 50%; margin: 20% auto; font-size:32px; color: red; text-align:center; } </style> </head> <body> <div>webpack-demo</div> </body> </html> // a.js 文件内容如下 var num = 114514; const str = 'this is a.js'; export { num, str }; // b.js 文件内容如下 var num = 5211314; const str = 'this is b.js'; export { num, str }; // index.js 文件内容如下 import { num as num_a, str as str_a } from './a.js'; import { num as num_b, str as str_b } from './b.js'; let a = `import a.js, and num_a is ${num_a}, str_a is '${str_a}' `; let b = `import b.js, and num_b is ${num_b}, str_b is '${str_b}' `; console.log(a); console.log(b); // webpack.config.js 文件内容如下 const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // entry 默认入口为src目录下的 index.js entry: './src/index.js', output: { filename: '[name].js', // 默认 构建到 dist 目录下 path: path.resolve(__dirname, 'dist'), }, mode: 'development', plugins: [ new HtmlWebpackPlugin({ template: path.join(__dirname, 'public', 'index.html'), filename: 'index.html', }), ], devServer: { hot: true, port: 8080, open: true, compress: true, }, };
-
热部署和构建
npm run dev or yarn dev # 在默认浏览器打开网页,控制台可以看到打印信息, npm run build or yarn build # 构建项目,在 dist 目录下
-
小结
查看 webpack.config.js 文件,可以大致了解 webpack 核心配置信息
entry:构建入口
output:构建出口
plugins:插件集,功能有构建优化、资源管理、环境注入,devServer 是官方提供的插件
还有 loader,让webpack处理其他类型文件,例如
module: { rules: [ // 处理图片文件 { test: /\.(jpe?g|png|gif|bmp)$/i, type: 'asset/resource', }, // 处理 css 样式文件 { test: /\.css$/, use: ['vue-style-loader', 'css-loader', 'postcss-loader'], }, // 处理 scss 样式文件 { test: /\.scss$/, use: ['vue-style-loader','css-loader','sass-loader','postcss-loader',], } ] }
-
更多
webpack更多配置知识请查看官网 或者 等我更新下一篇博客(很慢)
webpack 构建原理
构建完上面的项目后,查看 dist目录下的 main.js (bundle)文件(简略)
// 立即执行匿名函数
(() => {
// 开启 严格模式
'use strict';
// 以 key-value 形式存储 所有被打包的模块
var __webpack_modules__ = {
'./src/a.js': (__unused_webpack_module,__webpack_exports__,__webpack_require__) => {/* 省略 */},
'./src/b.js': (__unused_webpack_module,__webpack_exports__,__webpack_require__) => {/* 省略 */},
'./src/index.js': (__unused_webpack_module,__webpack_exports__,__webpack_require__) => {/* 省略 */},
};
// 模块缓存
var __webpack_module_cache__ = {};
// 实现 require
function __webpack_require__(moduleId) {
// 省略
}
// 执行入口模块的加载
var __webpack_exports__ = __webpack_require__('./src/index.js');
})();
内容可以分为以下几个部分:
- 最外层匿名函数,包裹整个bundle文件,形成自身的作用域
__webpack_modules__
项目产生依赖关系的模块都会以 key-value 形式放在这里。key就是模块id,value是由一个匿名函数包裹的模块实体,匿名函数的参数赋予里每个模块导出和导入能力__webpack_module_cache__
每个模块只在第一次被加载的时候执行,之后其导出值就被存储到这个对象里面,当再次被加载的时候webpack就会直接从这里取值,而不会重新执行该模块__webpack_require__
对模块加载的实现,在浏览器中可以调用__webpack_require__(moduleId)
完成模块导入
bundle在浏览器中执行步骤:
- 在最外层匿名函数中初始化浏览器执行环境,包括定义
__webpack_modules__
对象、__webpack_require__
函数等,为模块的加载和执行做一些准备工作 - 加载入口模块。每个bundle都仅有一个入口模块,上面例子中 index.js 就是入口模块,在浏览器中会从它开始执行
- 执行模块代码。如果执行到了module.exports则记录下模块的导出值;如果中间遇到require函数(
__webpack_require__
),则会暂时停止执行,进入__webpack_require__
函数内进行加载其他模块的逻辑 - 在
__webpack_require__
中判断即将加载的模块是否存在于__webpack_module_cache__
中,如果存在则直接取值,否值返回到第三步,执行该模块的代码来获取导出值 - 所有依赖的模块都执行完毕,最后的执行权又回到入口模块,当入口模块中的代码执行完毕后也就意味着整个bundle执行结束
我们可以看到第三步和第四步是一个递归过程。webpack为每个模块创造了一个可以导出和导入模块的环境,但本质并没有修改代码的执行逻辑,因此代码执行的顺序与模块加载的顺序是完全一致的,这也就是webpack模块打包的原理
标签:__,入门,require,js,webpack,num,模块,讲解 From: https://www.cnblogs.com/chenmijiang/p/16709800.html