Webpack和 vite

Vite 和 Webpack都是现代前端构建工具,但它们在设计理念、构建方式和性能方面有着显著的区别。以下是 Vite 和 Webpack之间的主要区别:

设计理念

Webpack

  • 打包一切Webpack的核心理念是将所有资源(JavaScript、CSS、图片等)视为模块,将它们打包成一个或多个 bundle。
  • 依赖图Webpack通过分析入口文件及其依赖关系,构建一个依赖图,然后将这些模块打包到一起。

Vite

  • 即时开发服务器:Vite 的核心理念是利用浏览器的原生 ES 模块支持,在开发环境中提供即时的模块热替换(HMR),无需预打包。
  • 现代构建工具:Vite 在生产环境中使用 Rollup 进行打包,提供高效的构建性能和灵活的配置。

开发体验

Webpack

  • 打包时间长:在开发环境中,Webpack需要将整个项目打包成一个或多个 bundle,这会导致初次启动时间较长,尤其是对于大型项目。
  • 热更新Webpack提供模块热替换(HMR),但由于需要重新打包,更新速度可能较慢。

Vite

  • 即时启动:Vite 利用浏览器的原生 ES 模块支持,无需预打包,启动速度非常快。
  • 即时热更新:Vite 的 HMR 速度非常快,因为它只需要重新编译和发送变化的模块,而不是整个项目。

构建性能

Webpack

  • 单次打包Webpack在构建过程中会将所有资源打包成一个或多个 bundle,构建时间较长。
  • 优化插件Webpack通过各种优化插件(如 Tree Shaking、代码分割等)来提高构建性能,但配置复杂。

Vite

  • 分块构建:Vite 在开发环境中不进行预打包,而是在请求时按需加载模块,极大地提高了开发效率。
  • Rollup 构建:在生产环境中,Vite 使用 Rollup 进行打包,提供高效的构建性能和灵活的配置。

配置复杂度

Webpack

  • 配置复杂Webpack的配置文件通常较为复杂,需要手动配置各种 Loader 和 Plugin,以处理不同类型的资源。
  • 灵活性高:虽然配置复杂,但 Webpack提供了高度的灵活性,可以满足各种复杂的构建需求。

Vite

  • 配置简单:Vite 的配置文件相对简单,内置了对常见资源类型的支持,极大地简化了配置过程。
  • 开箱即用:Vite 提供了开箱即用的默认配置,适合大多数项目的需求。

插件生态

Webpack

  • 成熟生态Webpack作为老牌的构建工具,拥有庞大的插件生态,可以满足各种需求。
  • 社区支持Webpack拥有广泛的社区支持,几乎可以找到所有常见问题的解决方案。

Vite

  • 快速增长:Vite 的插件生态正在快速增长,许多常见的功能已经有对应的插件支持。
  • 兼容性:Vite 支持 Rollup 插件,进一步扩展了其插件生态。

示例对比

Webpack配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
devServer: {
contentBase: './dist',
hot: true
}
};

Vite 配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
plugins: [vue()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
});

总结

  • 开发体验:Vite 提供了更快的启动速度和即时的模块热替换,极大地提升了开发体验。Webpack在开发环境中的启动速度较慢,但也提供了模块热替换功能。
  • 构建性能:Vite 在开发环境中不进行预打包,构建速度更快。在生产环境中,Vite 使用 Rollup 进行打包,性能优异。Webpack在构建过程中需要打包所有资源,构建时间较长,但通过各种优化插件可以提高性能。
  • 配置复杂度:Vite 的配置文件相对简单,开箱即用,适合大多数项目的需求。Webpack的配置文件较为复杂,但提供了高度的灵活性,可以满足各种复杂的构建需求。
  • 插件生态Webpack拥有成熟的插件生态和广泛的社区支持。Vite 的插件生态正在快速增长,并且支持 Rollup 插件,扩展了其插件生态。

总体来说,Vite 更适合现代前端开发,特别是对于需要快速迭代和高效开发的项目。而 Webpack由于其成熟的生态和高度的灵活性,仍然是许多复杂项目的首选。

HMR(Hot Module Replacement)热更新又称热替换

当你对代码进行修改并保存后,Webpack将对代码重新打包,并将新的模块发送到浏览器端,浏览器通过新的模块替换老的模块,这样在不刷新浏览器的前提下就能够对应用进行更新。HMR 的核心就是客户端从服务端拉取更新后的文件。准确的说是 chunk diff(chunk 需要更新的部分),

实际上 WDS(webpack-dev-server)与浏览器之间维护了一个 websocket 进行通信。

当本地资源发生变化后, WDS 会向浏览器推送更新,并带上构建时的 hash,让浏览器与上一次的资源进行对比

客户端对比出差异后会向 WDS 发起 Ajax 请求来获取更改内容(文件列表、hash),也就是请求 update.json,

这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该 chunk 的增量更新也就是请求 update.js。更新的 js 是存储在内存中的

如何配置webpack多入口?

Webpack中配置多个入口文件可以让你为不同的页面或功能模块生成独立的打包文件。这样做可以提高应用的可扩展性,并允许对不同页面加载不同的资源,优化加载速度。下面是如何在 Webpack中配置多入口的步骤:

1. 基础多入口配置

webpack.config.js 文件中,你可以设置一个对象作为 entry 属性的值,每个键值对应一个入口文件。例如,如果你想为“首页”和“关于页面”分别创建一个入口,可以这样配置:

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
// 其他配置...
entry: {
home: './src/home.js',
about: './src/about.js',
},
output: {
filename: '[name].bundle.js', // 使用 [name] 占位符确保每个入口生成独立的文件
path: path.resolve(__dirname, 'dist')
},
// 其他配置...
};

在这个例子中,Webpack将会为 home.jsabout.js 分别打包生成 home.bundle.jsabout.bundle.js

2. 配合 HtmlWebpackPlugin 使用

通常在使用多入口配置时,会搭配 HtmlWebpackPlugin 插件来生成每个入口的 HTML 文件。这样做可以自动为每个 HTML 文件注入正确的脚本标签。以下是如何配置 HtmlWebpackPlugin 以适应多入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: {
home: './src/home.js',
about: './src/about.js',
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/home.html',
filename: 'home.html',
chunks: ['home'] // 指定只包含 home 入口生成的文件
}),
new HtmlWebpackPlugin({
template: './src/about.html',
filename: 'about.html',
chunks: ['about'] // 指定只包含 about 入口生成的文件
})
],
// 其他配置...
};

在这个配置中,chunks 选项告诉 HtmlWebpackPlugin 只将指定的 JavaScript 文件包含到生成的 HTML 中。这确保了 home.html 只引用了 home.bundle.jsabout.html 只引用了 about.bundle.js

3. 高级应用和优化

当你的应用变得更加复杂时,你可能需要考虑代码拆分和优化。Webpack提供了如 SplitChunksPlugin 的插件来帮助进行代码分割,抽取公共模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 可以是 async, initial, all
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
automaticNameDelimiter: '~',
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};

这些高级功能可以帮助你更好地管理和优化大型应用的资源。

配置多入口可以非常灵活,确保根据你的项目需求调整配置。

在使用 Webpack进行前端项目构建时,控制输出文件的大小是优化加载时间和提高应用性能的重要策略之一。限制打包文件大小至1MB或其他特定大小可以通过配置和优化技术实现。下面是一些主要方法:

1. 配置 performance 属性

Webpack提供了 performance 配置项,允许你设置资源文件大小警告的阈值。虽然这不会阻止文件超过指定大小,但它会在构建过程中提醒你文件大小问题。

1
2
3
4
5
6
7
8
9
module.exports = {
// 其他配置...
performance: {
hints: 'warning', // 或 'error' 如果你想让构建失败
maxEntrypointSize: 1024000, // 最大入口文件大小(字节)
maxAssetSize: 1024000, // 单个资源最大大小(字节)
},
// 其他配置...
};

在这个配置中,maxEntrypointSize 控制入口点总体大小的限制,而 maxAssetSize 控制单个资源(如输出的每个 JavaScript 文件)的大小。如果任一文件超出这个限制,Webpack将根据 hints 的配置显示警告或错误。

2. 代码分割

使用代码分割技术是减小打包文件大小的有效方式。通过将代码拆分成多个块,只有用户需要时才加载,可以显著减少初始加载时间和资源大小。

动态导入

Webpack支持通过动态 import() 语法来实现代码分割。例如,可以将不同路由下的组件拆分为独立的代码块:

1
2
const HomePage = () => import(/* webpackChunkName: "home" */ './HomePage');
const AboutPage = () => import(/* webpackChunkName: "about" */ './AboutPage');

SplitChunksPlugin

Webpack中,SplitChunksPlugin 插件可以自动帮助你拆分公共模块:

1
2
3
4
5
6
7
8
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
maxSize: 1024000, // 尝试将每个块的大小限制在1MB以内
},
},
};

这里的 maxSize 选项告诉 Webpack尝试将每个块的大小限制在指定的字节数以下。

3. 优化和压缩资源

确保你使用了如 UglifyJS、Terser 或其他 Webpack插件来压缩 JavaScript 代码。此外,对于 CSS 和图片资源,也应该使用相应的加载器和插件进行优化和压缩:

  • CSS: 使用 css-loadermini-css-extract-plugin 来压缩和优化样式表。
  • 图片: 使用 image-webpack-loader 来压缩图片文件。

4. 监控和分析

使用 webpack-bundle-analyzer 或其他类似工具来可视化和分析输出文件的大小和依赖。这可以帮助你识别哪些库或模块占用了过多空间,并进行相应的优化。

1
2
3
4
5
6
7
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
plugins: [
new BundleAnalyzerPlugin(),
],
};

通过这些方法,你可以更有效地控制 Webpack构建输出的大小,提升应用的性能和用户体验。