1、webpack是什么
webpack 是前端的一个项目构建工具,它是基于Node.js开发出来的一个前端工具。WebPack可以看做是模块打包机(bundler),通过分析项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。
2、为什么要使用webpack
2.1、js和css依赖问题(作用域问题)
JavaScript和CSS的依赖问题。开发过程中,JavaScript和CSS的在页面中的顺序问题,经常会造成CSS没起作用,JavaScript的某个变量和方法找不到。
比如之前 Grunt 和 Glup 有的就是利用立即调用的函数表达式(IIFE) 来实现作用域问题,但是这种会造成存在无用代码,文件体积过大等问题。
2.2、实现模块的开发和加载(模块化开发)
在没有各个 webpack 搭建的脚手架(create-react-app、vue-cli 等等)之前,我们通过在 HTML5 文件里引入一个个 Javascript 文件来进行开发,这就可能导致并行请求数量过多、存在重复代码(或者可能发生2.1那样的问题)等问题。
而通过 webpack,我们可以使用import 、require 来进行模块化开发。 在 webpack 中一切皆模块,js、css、图片、字体都是模块,而且支持静态解析、按需打包、动态加载、代码分离等功能,帮助我们优化代码,提升性能。
import { Hello } from './hello.js'
import './assets/style.css'
import MyImage './assets/img.jpg'
2.2、性能优化
一般浏览器请求的文件越多越耗时,请求的文件越大越耗时,尤其是为了前端项目的代码更清晰,结构更合理,我们采用了MVC,MVVM等很多架构分解出了很多JS文件,无疑又拖慢了网页的速度。为了解决这个问题,一般会采用以下两个方案:
文件合并 :浏览器需要下载多个JS文件,而浏览器是有并发限制,也就是同时并发只能下载几个文件。当需要加载的文件非常多,网页的性能可想而知,所以我们需要合并多个文件以减少文件的数量。文件压缩 :我们知道文件越大,下载越慢,而针对JavaScript和CSS,里面的空格,换行这些都是为了让我们读代码时更容易阅读,但是对机器来说,这些对它没有影响。
2.3、提升效率
提高开发效率。主要体现在:
2.3.1、 Vendor前缀
在CSS3使用越来越多的时候,我们都知道一些CSS3的新特性,在不同的浏览器中,CSS有不同的前缀,如果我们手工添加将会很繁琐,而如果使用构建工具,很多构建工具可以自动给我添加CSS的Vendor前缀 。关于vendor前缀的学习
2.3.2、新语法
Javascript、CSS 的语法规范在不断更新,但是浏览器的兼容性却不能同步的更新,开发者可以通过 webpack 预处理器进行编译,自由的使用 JS、CSS 等语言的新语法。
webpack 使用 loader 对文件进行预处理 。
你可以构建包括 JavaScript 在内的任何静态资源,如 Less 、Sass 、ES6 、TypeScript 。通过预处理器将 TypeScript 编译成 JavaScript、SCSS 编译成 CSS、ES6 编译成 ES5 等。
开发者还可以使用 Node.js 轻松编写自己的 loader。常用预处理器:
babel-loader :使用 Babel 加载 ES2015+ 代码并将其转换为 ES5; less-loader :加载并编译 LESS 文件; sass-loader :加载并编译 SASS/SCSS 文件; postcss-loader :使用 PostCSS 加载并转换 CSS/SSS 文件。
2.3.3、 单元测试
JavaScript的单元测试在使用MVC或者MVVM的框架后,变得越来越容易,而单元测试是质量保证的一个很重要的手段,所以在提交之前,使用构建工具自动跑一遍我们的单元测试是非常有必要的,能进一步检测你的项目的健壮性和容错能力。关于MVVM的学习
2.3.4、 代码分析
我们写的JavaScript很多时候会有一些潜在的bug, 比如忘了添加分号,某个变量没有等等,使用一些JavaScript的代码分析工具,可以很好的帮我们检查一些常见的问题。
3、Webpack、Grunt、Gulp
Gulp/Grunt 是基于task任务 的一种能够优化前端的开发流程的工具,而WebPack 是一种模块化 的解决方案,是基于整个项目进行构建的。
Gulp/Grunt在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。
Gulp/Grunt强调的是前端开发的工作流程 ,我们可以通过配置一系列的task (Gulp中的gulp.task()方法配置),定义task处理的事务 (例如文件压缩合并、雪碧图、启动server、sass/less预编译、版本控制等)然后定义执行顺序 ,来让gulp执行这些task,从而构建项目的整个前端开发流程。核心是 task runner 。
如图: 而webpack把你的项目当做一个整体,通过一个给定的主文件 (如:index.js ),Webpack将从这个文件开始找到你的项目的所有依赖文件 ,使用loaders处理 它们,最后打包为一个(或多个) 浏览器可识别的JavaScript文件。
它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。通过 loader的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、AMD 模块、ES6 模块、CSS、图片、JSON、Coffeescript、Less 等 如图: 所以, Gulp和Webpack的侧重点是不同的,我们可以总结为一句话:
Gulp 侧重于开发整个过程 的控制管理Webpack 更侧重于模块打包
4、webpack配置的基本含义
先附上一小段代码示例:
const path = require('path');
module.exports = {
entry: "./app/entry",
output: {
path: path.resolve(__dirname, "dist"),
filename: "[chunkhash].js",
publicPath: "/assets/",
},
module: {
rules: [
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, "app")
],
exclude: [
path.resolve(__dirname, "app/demo-files")
],
loader: "babel-loader",
options: {
presets: ["es2015"]
},
},
},
resolve: {
modules: [
"node_modules",
path.resolve(__dirname, "app")
],
extensions: [".js", ".json", ".jsx", ".css"],
alias: {
"module": "new-module"
},
},
devtool: "source-map",
plugins: [
],
}
当 webpack 处理应用程序时,它会递归地构建一个依赖关系图 (dependency graph ),那么依赖关系图是什么呢?
依赖图 指的就是文件和文件直接的依赖关系 ,webpack中文文档首页就附上了这张图:
4.1、entry(入口)
入口是指依赖关系图的开始,从入口开始寻找依赖,打包构建。
webpack 允许一个或多个入口配置。
配置示例如下:
module.exports = {
entry: 'index.js',
};
4.2、output(出口\输出)
输出则是用于配置 webpack 构建打包的出口,如打包的位置,打包的文件名等等。
配置示例如下:
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
},
};
4.3、loader(资源加载器\资源转换器)
webpack 自带 JavaScript 和 JSON 文件的打包构建能力,无需格外配置。 而其他类型的文件,如 CSS 、Less 、TypeScript 、csv\tsv 、xml 、woff\woff2\ttf 、yaml\toml\json5 ,则需要安装 loader 来进行处理。
loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块 ,以供应用程序使用,以及被添加到依赖图中。
它类似于一个“task-runner” 。
配置示例如下:
module.exports = {
module: {
rules: [
{
test: /.txt$/,
use: 'raw-loader'
},{
test: /\.(csv|tsv)$/,
use:'csv-loader'
},{
test:/\.xml$/,
use:'xml-loader'
},test:/\.(css|less)$/,
use:[MiniCssExtractPlugin.loader,'css-loader','less-loader']
}
···
],
},
};
4.4、plugin(插件\扩展器)
插件则是用于扩展 webpack 的能力,常见的插件有:
配置示例如下:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
插件丰富,开发者社区同样提供了大量插件,也使得 webpack 的可用功能更加多样。
4.5、mode(模式)
webpack5 提供了模式选择,包括开发模式(development) 、生产模式(production) 、空模式 ,并对不同模式做了对应的内置优化。可通过配置模式让项目性能更优。
我们需要根据不同模式进行判断,比如生产模式中我们需要代码压缩,不需要devServer之类,
配置示例如下:
module.exports = {
mode: 'development',
};
4.6、 resolve(解析)
resolve 用于设置模块如何解析,常用配置如下:
alias :配置别名,简化模块引入;extensions :在引入模块时可不带后缀;symlinks :用于配置 npm link 是否生效,禁用可提升编译速度;
配置示例如下:
module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.d.ts'],
alias: {
'@': paths.appSrc,
},
symlinks: false,
}
}
4.7、optimization(优化)
optimization 用于自定义 webpack 的内置优化配置,一般用于生产模式提升性能,常用配置项如下:
minimize :是否需要压缩 bundle;minimizer :配置压缩工具,如 TerserPlugin、OptimizeCSSAssetsPlugin;splitChunks :拆分 bundle;runtimeChunk :是否需要将所有生成 chunk 之间共享的运行时文件拆分出来;
配置示例如下:
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin(),
],
splitChunks: {
chunks: 'all',
cacheGroups:{
vendors:{
test: /[\\/]node_modules[\\/]/,
chunks: "all",
name: 'vendors',
priority: 10,
enforce: true
}
}
},
},
}
5、webpack中常用术语
5.1、Asset
这个术语主要是用来描述我们通常在web应用或者其他应用中用到的图片、字体文件、音视频,以及其他类型的一些文件。这些资源通常为一个个单独的文件,但在webpack中,我们借助style-loader或者css-loader也能进行适当的管理。
5.2、Bundle
bundle 通常是由多个不同的模块产生,它是已经加载完毕 和被编译后的源代码 的最终版本
5.3、Bundle Splitting:
这是webpack优化代码的一种方法,即将一个单独的应用拆解 为多个bundle 。
通过将多个bundle中公共引入的模块拆解出来,我们可以减少项目的代码量,从而减小应用的体积,并且通过浏览器缓存,我们可以将代码进一步优化。
5.4、Chunk
这个webpack中专用的术语用于管理webpack内部的打包进程。
bundle由许多chunk组成 。
chunk有几种类型,比如说“入口”和“子块”。通常chunk和输出的bundle一一对应,但是,有些是一对多的关系。
5.5、Code Splitting
Code Splitting表示将你的代码拆分成多个bundle或chunk,之后你可以按需加载它们,而不是简单地加载一个单独的文件。
5.6、Configration(配置)
webpack的配置文件是一段非常普通的javascript代码,它会输出一个对象,然后webpack将会基于对象中的每个属性开始运行。
5.7、Dependency Graph(依赖关系图)
Dependency Graph只要一个文件依赖另一个文件才能有所作为,webpack把这个文件定义为依赖项。webpack会从一个入口点开始,通过递归的方式构建出一个依赖关系图,这里面包括每一个被拆分的小模块,每一个asset。
(依赖关系图)
5.8、Entry Point
入口点告诉webpack从哪里开始解析,根据构建出来的依赖关系图,从而知道哪些部分将会输出为bundle
5.9、HMR(热更新)
Hot Module Replacement (HMR) : 即热更新 ,当项目在运行时发生变更、文件新增、文件删除时,整个项目无需全部全局加载。
5.10、Module
相比于一个完整的项目,项目中分散的一个个功能性模块能够提供一个对于程序员来说更加专注的视角。一个编写良好的模块能够形成一个很清晰的抽象结构,保证之后的维护基于此能够变得规范化和开发具有明确性。
5.11、Output
指定输出编译后代码的位置。
注意:即使指定了多个入口点(entry points),Ouput配置项也只能设置一个 。
5.12、Target
Target配置用于指定项目的运行环境(browser、nodejs、electron等),以使webpack编译器以不同的方式进行编译
5.13、TreeShaking
TreeShaking是消除未使用/多余的代码,或更准确地说,是实时代码导入。webpack编译器通过分析代码中使用的import语句、引入的代码块的使用情况来判断哪些依赖部分被使用,以及哪些依赖部分没有被使用需要丢弃掉。
本博客参考:
|