Webpack笔记
作者:互联网
Webpack笔记
模块化
模块化是指把一个复杂的系统分解到多个模块以方便编码。
当项目变大时这种方式将变得难以维护,需要用模块化的思想来组织代码。
CommonJS
CommonJS 是一种使用广泛的 JavaScript 模块化规范
核心思想:
- 是通过
require
方法来同步地加载依赖的其他模块 - 通过
module.exports
导出需要暴露的接口。
/ 导入
const moduleA = require('./moduleA');
// 导出
module.exports = moduleA.someFunc;
CommonJS 的缺点在于这样的代码无法直接运行在浏览器环境下,必须通过工具转换成标准的 ES5。
AMD
AMD 也是一种 JavaScript 模块化规范,与 CommonJS 最大的不同在于它采用异步的方式去加载依赖的模块。 AMD 规范主要是为了解决针对浏览器环境的模块化问题,最具代表性的实现是 requirejs。
// 定义一个模块
define('module', ['dep'], function(dep) {
return exports;
});
// 导入和使用
require(['module'], function(module) {
});
AMD 的优点在于:
- 可在不转换代码的情况下直接在浏览器中运行;
- 可异步加载依赖;
- 可并行加载多个依赖;
- 代码可运行在浏览器环境和 Node.js 环境下。
AMD 的缺点在于JavaScript 运行环境没有原生支持 AMD,需要先导入实现了 AMD 的库后才能正常使用。
ES6 模块化
它将逐渐取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
// 导入
import { readFile } from 'fs';
import React from 'react';
// 导出
export function hello() {};
export default {
// ...
};
ES6模块虽然是终极模块化方案,但它的缺点在于目前无法直接运行在大部分 JavaScript 运行环境下,必须通过工具转换成标准的 ES5 后才能正常运行。
常见的构建工具及对比
构建就是做这件事情,把源代码转换成发布到线上的可执行 JavaScrip、CSS、HTML 代码,包括如下内容。
- 代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等。
- 文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。
- 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。
- 模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
- 自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器。
- 代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
- 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
构建其实是工程化、自动化思想在前端开发中的体现,把一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。 构建给前端开发注入了更大的活力,解放了我们的生产力。
Npm Script
Npm Script 是一个任务执行者。Npm 是在安装 Node.js 时附带的包管理器,Npm Script 则是 Npm 内置的一个功能,允许在 package.json
文件里面使用 scripts
字段定义任务:
{
"scripts": {
"dev": "node dev.js",
"pub": "node build.js"
}
}
里面的 scripts
字段是一个对象,每个属性对应一段 Shell 脚本,以上代码定义了两个任务 dev
和 pub
。 其底层实现原理是通过调用 Shell 去运行脚本命令,例如执行 npm run pub
命令等同于执行命令 node build.js
。
Npm Script的优点是内置,无须安装其他依赖。其缺点是功能太简单,虽然提供了 pre
和 post
两个钩子,但不能方便地管理多个任务之间的依赖。
Gulp
Gulp 是一个基于流的自动化构建工具。 除了可以管理和执行任务,还支持监听文件、读写文件。Gulp 被设计得非常简单,只通过下面5个方法就可以胜任几乎所有构建场景:
- 通过
gulp.task
注册一个任务; - 通过
gulp.run
执行任务; - 通过
gulp.watch
监听文件变化; - 通过
gulp.src
读取文件; - 通过
gulp.dest
写文件。
Gulp 的最大特点是引入了流的概念,同时提供了一系列常用的插件去处理流,流可以在插件之间传递,大致使用如下:
// 引入 Gulp
var gulp = require('gulp');
// 引入插件
var jshint = require('gulp-jshint');
var sass = require('gulp-sass');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
// 编译 SCSS 任务
gulp.task('sass', function() {
// 读取文件通过管道喂给插件
gulp.src('./scss/*.scss')
// SCSS 插件把 scss 文件编译成 CSS 文件
.pipe(sass())
// 输出文件
.pipe(gulp.dest('./css'));
});
// 合并压缩 JS
gulp.task('scripts', function() {
gulp.src('./js/*.js')
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
// 监听文件变化
gulp.task('watch', function(){
// 当 scss 文件被编辑时执行 SCSS 任务
gulp.watch('./scss/*.scss', ['sass']);
gulp.watch('./js/*.js', ['scripts']);
});
Gulp 的优点是好用又不失灵活,既可以单独完成构建也可以和其它工具搭配使用。其缺点是和 Grunt 类似,集成度不高,要写很多配置后才可以用,无法做到开箱即用。
Webpack
Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一切文件皆模块,通过 Loader 转换文件,通过 Plugin 注入钩子,最后输出由多个模块组合成的文件。Webpack 专注于构建模块化项目。
一切文件:JavaScript、CSS、SCSS、图片、模板,在 Webpack 眼中都是一个个模块,这样的好处是能清晰的描述出各个模块之间的依赖关系,以方便 Webpack 对模块进行组合和打包。 经过 Webpack 的处理,最终会输出浏览器能使用的静态资源。
Rollup
Rollup 是一个和 Webpack 很类似但专注于 ES6 的模块打包工具。 Rollup 的亮点在于能针对 ES6 源码进行 Tree Shaking 以去除那些已被定义但没被使用的代码,以及 Scope Hoisting 以减小输出文件大小提升运行性能。 然而 Rollup 的这些亮点随后就被 Webpack 模仿和实现。 由于 Rollup 的使用和 Webpack 差不多,这里就不详细介绍如何使用了,而是详细说明它们的差别:
- Rollup 是在 Webpack 流行后出现的替代品;
- Rollup 生态链还不完善,体验不如 Webpack;
- Rollup 功能不如 Webpack 完善,但其配置和使用更加简单;
- Rollup 不支持 Code Spliting,但好处是打包出来的代码中没有 Webpack 那段模块的加载、执行和缓存的代码。
Rollup 在用于打包 JavaScript 库时比 Webpack 更加有优势,因为其打包出来的代码更小更快。 但功能不够完善,很多场景都找不到现成的解决方案。
安装 Webpack
在用 Webpack 执行构建任务时需要通过 webpack
可执行文件去启动构建任务,所以需要安装 webpack
可执行文件。
在开始给项目加入构建前,你需要先新建一个 Web 项目,方式包括:
- 新建一个目录,再进入项目根目录执行
npm init
来初始化最简单的采用了模块化开发的项目;
推荐安装到本项目,原因是可防止不同项目依赖不同版本的 Webpack 而导致冲突。
要安装 Webpack 到本项目,可按照你的需要选择以下任意命令运行:
# npm i -D 是 npm install --save-dev 的简写,是指安装模块并保存到 package.json 的 devDependencies
# 安装最新稳定版
npm i -D webpack
# 安装指定版本
npm i -D webpack@<version>
# 安装最新体验版本
npm i -D webpack@beta
或者
yarn add webpack --dev
安装完后你可以通过这些途径运行安装到本项目的 Webpack:
-
在项目根目录下对应的命令行里通过
node_modules/.bin/webpack
运行 Webpack 可执行文件。 -
在 Npm Script 里定义的任务会优先使用本项目下的 Webpack,代码如下:
"scripts": { "start": "webpack --config webpack.config.js" }
Webpack 在执行构建时默认会从项目根目录下的 webpack.config.js
文件读取配置,所以你需要新建它
const path = require('path');
module.exports = {
// JavaScript 执行入口文件
entry: './main.js',
output: {
// 把所有依赖的模块合并输出到一个 bundle.js 文件
filename: 'bundle.js',
// 输出文件都放到 dist 目录下
path: path.resolve(__dirname, './dist'),
}
};
在项目根目录下执行 webpack
命令运行 Webpack 构建,你会发现目录下多出一个 dist
目录,里面有个 bundle.js
文件, bundle.js
文件是一个可执行的 JavaScript 文件
核心概念
- Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
- Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
- Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
- Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
- Plugin:扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
- Output:输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果。
ebpack 启动后会从 Entry 里配置的 Module 开始递归解析 Entry 依赖的所有 Module。 每找到一个 Module, 就会根据配置的 Loader 去找出对应的转换规则,对 Module 进行转换后,再解析出当前 Module 依赖的 Module。 这些模块会以 Entry 为单位进行分组,一个 Entry 和其所有依赖的 Module 被分到一个组也就是一个 Chunk。最后 Webpack 会把所有 Chunk 转换成文件输出。 在整个流程中 Webpack 会在恰当的时机执行 Plugin 里定义的逻辑。
Webpack 构建过程
首先先简单了解下 Webpack 构建过程:
-
根据配置,识别入口文件;
-
逐层识别模块依赖(包括 Commonjs、AMD、或 ES6 的 import 等,都会被识别和分析);
-
Webpack 主要工作内容就是分析代码,转换代码,编译代码,最后输出代码;
-
输出最后打包后的代码。
Webpack 构建原理
(1)初始化参数
解析 Webpack 配置参数,合并 Shell 传入和
webpack.config.js
文件配置的参数,形成最后的配置结果。(2)开始编译
上一步得到的参数初始化
compiler
对象,注册所有配置的插件,插件监听 Webpack 构建生命周期的事件节点,做出相应的反应,执行对象的run
方法开始执行编译。(3)确定入口
从配置文件(
webpack.config.js
)中指定的entry
入口,开始解析文件构建 AST 语法树,找出依赖,递归下去。(4)编译模块
递归中根据文件类型和 loader 配置,调用所有配置的 loader 对文件进行转换,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。
(5)完成模块编译并输出
递归完后,得到每个文件结果,包含每个模块以及他们之间的依赖关系,根据
entry
配置生成代码块chunk
。(6)输出完成
输出所有的
chunk
到文件系统。注意:在构建生命周期中有一系列插件在做合适的时机做合适事情,比如
UglifyPlugin
会在 loader 转换递归完对结果使用UglifyJs
压缩覆盖之前的结果。
Webpack 的核心是实现以下三个方法:
createAssets
: 收集和处理文件的代码;createGraph
:根据入口文件,返回所有文件依赖图;bundle
: 根据依赖图整个代码并输出;
标签:文件,代码,笔记,js,gulp,Webpack,模块 来源: https://www.cnblogs.com/yxyc/p/16504211.html