likes
comments
collection
share

vite和webpack的性能优化和区别

作者站长头像
站长
· 阅读数 15

性能优化概述

1.分包策略

Vite和Webpack都支持性能优化-分包策略,下面简要介绍一下它们的实现方法:

Vite分包策略

Vite是一款基于ESM的构建工具,Vite的分包策略主要通过动态引入实现,可以自动进行代码拆分,实现按需加载和运行时优化。在Javascript中,可以使用ES6的import()语法来实现动态引入:

const module = import('./module.js');

Vite还支持使用预构建Chunk来优化加载速度,可以在vite.config.js文件中设置rollupOptions项来实现预构建Chunk:

module.exports = {
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          react: ['react', 'react-dom']
        }
      }
    }
  }
};

除了动态引入和预构建Chunk,Vite还支持手动配置Chunk,以实现更细粒度的控制。可以使用 import.meta.glob() 函数来匹配文件对 Chunk 进行手动配置。

import.meta.glob('../components/*.js').then(modules => {
  Promise.all(modules.values()).then(components => {
    // ...
  })
})

Webpack分包策略

Webpack可以使用以下方式实现分包策略:

  • 使用代码分割插件(Model Splitting)

通过代码分割插件在构建过程中实现自动化的代码分割。

const path = require('path');

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js'
  },
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
};
  • 使用动态导入(Dynamic Imports)

    通过动态导入将代码拆分成多个小块,按需加载。

import('./module.js')
  .then((module) => {
    // ...
  })
  .catch((err) => {
    // ...
  });

Webpack还支持使用webpackPrefetch和webpackPreload来实现预加载预取的功能,提高用户体验。

// webpackPreload
const Component = () => import(/* webpackPreload: true */ './Component.js');

// webpackPrefetch
const Component = () => import(/* webpackPrefetch: true */ './Component.js');

以上就是Vite和Webpack的分包策略实现方法和代码示例。

2.gzip压缩

Vite和Webpack都提供了Gzip压缩的功能,以便在前端性能优化中使用。

在Vite中,可以通过在vite.config.js中设置compress参数来开启Gzip压缩:

// vite.config.js

export default {
  server: {
    compress: true
  }
}

在Webpack中,可以通过在webpack.config.js中配置CompressionPlugin插件来开启Gzip压缩:

const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
  plugins: [
    new CompressionPlugin({
      algorithm: 'gzip'
    })
  ]
};

这些配置将为我们自动压缩生成的文件,并在传输到客户端时解压文件以提高性能。

值得注意的是,由于Gzip压缩需要花费一些CPU时间,建议在服务器端启用压缩。如果你正在使用CDN,你也可以在CDN端配置Gzip压缩。

3.动态引入

Webpack和Vite都支持使用动态引入来提高前端性能。动态引入的主要作用是延迟加载,只在需要的时候才加载相关的模块,减少了首次加载时的负担。

在Vite中,可以实现动态引入的几种方式:

  1. 使用ES6动态导入语法
import('./path/to/module').then(result => {
  // do something with the module
}).catch(error => {
  // handle error
});

这将以异步方式加载模块,可以在需要时动态引入。

  1. 在组件的setup函数中使用异步加载
import { defineComponent, ref, onMounted } from 'vue';

export default defineComponent({
  setup() {
    const moduleRef = ref(null);
    onMounted(async () => {
      const result = await import('./path/to/module');
      moduleRef.value = result;
    });
    return {
      moduleRef,
    };
  },
});

这种方式使用了Vue 3中的setup函数,使用Promise来异步加载模块,并将结果存储在ref中。

  1. 使用异步组件
const AsyncComponent = defineAsyncComponent(() => import('./path/to/module'));

export default defineComponent({
  components: {
    AsyncComponent,
  },
  template: `<AsyncComponent />`,
});

这里使用了Vue 3中的defineAsyncComponent函数,通过传入异步加载模块的路径来创建异步组件。这样组件的加载过程将会被延迟到当组件被使用时再进行。

需要注意的是,为了使动态引入能够真正发挥作用,还需要配置Vite的按需动态导入功能。在vite.config.js文件中,可以通过设置rollupOptions参数来开启此功能:

// vite.config.js

export default {
  rollupOptions: {
    output: {
      manualChunks: {},
    },
  },
};

此配置将分离每个动态导入的文件,并生成一个独立的代码块。这样可以按需加载模块,从而提高性能。

在Webpack中,可以实现动态引入的几种方式:

  1. 使用ES6动态导入语法
import('./path/to/module').then(result => {
  // do something with the module
}).catch(error => {
  // handle error
});

这将以异步方式加载模块,可以在需要时动态引入。

  1. 在React懒加载组件中使用
const MyComponent = lazy(() => import('./path/to/module'));

使用了React.lazy()函数来实现懒加载。此函数接受一个返回动态加载模块的import()函数的参数。

  1. 使用webpack的内置require.ensure()
require.ensure(['./path/to/module'], function (require) {
  var result = require('./path/to/module');
  // do something with the module
});

这种方式使用了webpack的内置函数require.ensure(),可以将块(chunk)分离出来并延迟加载模块。

在使用动态引入时,还可以通过配置webpack的output.publicPath属性,将异步块的基础路径设置为CDN地址,以加快异步加载速度。例如:

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'https://cdn.example.com/'
}

需要注意的是,在使用动态引入时,还需要配置webpack的代码分离和优化功能。可以通过在webpack.config.js文件中设置optimization.splitChunks来实现此目的:

optimization: {
  splitChunks: {
    chunks: 'async',
    minSize: 20000,
    maxSize: 0,
    minChunks: 1,
    maxAsyncRequests: 30,
    maxInitialRequests: 30,
    enforceSizeThreshold: 50000,
    cacheGroups: {
      defaultVendors: {
        test: /[\/]node_modules[\/]/,
        priority: -10,
        reuseExistingChunk: true,
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true,
      },
    },
  },
},

这样,webpack会自动分离出符合条件的模块,生成独立的代码块,在需要时进行加载。

值得注意的是,动态引入虽然可以优化首次加载时间,但在使用多个包时可能会导致过多的HTTP请求,这可能导致首屏渲染延迟。因此,需要根据实际情况选择何时使用动态引入。

补充:

为了避免这些问题,并且进一步提高性能,可以采用以下一些方法:

  1. 预加载和预取。在Webpack中,可以使用webpackPrefetchwebpackPreload注释,以启用自动预取和/或预加载。例如:
import(/* webpackPrefetch: true */ './path/to/module');

这将告诉浏览器提前下载此模块,以便在需要时立即加载。

  1. 按用户需求加载。如果你有一些模块是高频访问的,那么可以在页面加载时先加载这些模块,而将其他模块延迟加载。这样可以防止不必要的HTTP请求,并加快页面响应速度。
  2. 避免过多的动态引入。虽然动态引入可以解决代码分离的问题,但是如果不加以控制,也可能导致模块的数量过于庞大,进而导致过多的HTTP请求和降低性能的可能。因此,在使用动态引入时,必须注意模块数量的把握,避免过度动态引入。

4.CDN加速

Vite和Webpack都支持使用CDN加速来优化前端性能。使用CDN可以将静态资源放置在离用户更近、更容易访问的地方,这样可以减少网络延迟,加快资源加载速度。

在Vite中,可以通过以下方式来使用CDN资源加速:

  1. 在 vite.config.js 文件中设置 base 属性
export default {
  base: 'https://cdn.example.com/',
  // ...
}

设置 base 属性后,资源的 baseURL 将会被设置为此处的值,JavaScript、CSS、图片等静态资源都将从这个地址加载。

  1. 在 index.html 文件中手动引入 CDN 资源
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>My App</title>
    <link rel="stylesheet" href="https://cdn.example.com/path/to/main.css">
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

这种方式可以手动指定要加载的静态资源,并从CDN加载,但需要注意的是,这种方式可能会增加HTML文件的大小和复杂度。

  1. 在 vite.config.js 文件中使用 CDN 插件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePluginCdn } from 'vite-plugin-cdn';

export default defineConfig({
  plugins: [
    vue(),
    VitePluginCdn({
        modules:[
            {
                name: 'vue',
                var: 'Vue',
                path: 'vue/dist/vue.min.js'
            },
            {
                name: 'vue-router',
                var: 'VueRouter',
                path: 'vue-router/dist/vue-router.min.js'
            },
            {
                name: 'chart.js',
                var: 'Chart',
                path: 'chart.js/dist/Chart.min.js'
            }
        ],
        prodUrl: 'https://cdn.example.com/{{module}}/{{version}}/{{path}}',
        // 以下配置可以是 CDN 来加速引入的资源。
        // 必须是数组形式,且选项都必须包含 `test` 和 `method` 属性。
        // 具体可选项请参考 `preload-webpack-plugin` 的 `include` 参数。
        allowList: [
            {
              test: /bootstrap-vue/(.*?).(js|css|woff|woff2|ttf|svg|png|jpe?g|gif)$/,
              method: 'GET',
              //可选的扩展加载,vue使用
              ext: 'js'
            }
        ]
    })
  ]
})

使用 vite-plugin-cdn 插件可以方便地自动将指定的模块从CDN加载。需要注意的是,这个插件需要按照指定规则的方式来定义模块和版本。具体用法可以参考 vite-plugin-cdn 的官方文档。

以上这些方法都可以实现CDN资源加速,根据实际使用场景可以灵活选择。

在Webpack中,可以通过以下方式来使用CDN资源加速:

  1. 使用 HtmlWebpackPlugin 插件

在 webpack.config.js 文件中使用 HtmlWebpackPlugin 插件,在 template 配置中引入CDN地址

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // ...
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      cdn: {
        js: [
          'https://cdn.example.com/jquery.min.js',
          'https://cdn.example.com/bootstrap.min.js'
        ],
        css: [
          'https://cdn.example.com/bootstrap.min.css'
        ]
      }
    })
  ],
  // ...
};

在 HTML 模板文件中,将 js 和 css 链接插入到模板中:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>My App</title>
    <% for (var i in htmlWebpackPlugin.options.cdn.css) { %>
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
    <% } %>
  </head>
  <body>
    <div id="app"></div>
    <% for (var i in htmlWebpackPlugin.options.cdn.js) { %>
      <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>
  </body>
</html>

这种方式可以将静态资源链接插入到运行 HTML 模板源文件中,以指定CDN地址加载。

  1. 在 output.publicPath 中设置 CDN 地址

在 webpack.config.js 文件中设置 output.publicPath 属性:

module.exports = {
  output: {
    publicPath: 'https://cdn.example.com/',
  },
  // ...
}

这样设置后,通过Webpack打包后的静态资源将从指定的CDN地址加载,比如JS、CSS、图片等静态资源。

以上这些方法都可以实现CDN资源加速,根据实际使用场景可以灵活选择。

vite和webpack的区别

综述:

  1. 构建速度:Vite的构建速度比Webpack快得多。Vite使用现代浏览器原生支持的 ES 模块标准,避免了打包和编译的大量时间,而Webpack则需要在打包时对所有模块进行解析和编译。
  2. 开发模式:Vite支持快速的“即时重载”(Instant Reload)功能,当你编辑代码后,浏览器会自动更新页面,更新速度非常快。Webpack则需要手动刷新浏览器。
  3. 配置:Webpack需要通过复杂的配置来管理各种不同的loader、插件、代码分割和优化设置等等。相比之下,Vite的默认配置非常简单,只需要少量配置即可满足大部分需求。
  4. 生态系统和插件支持:由于Webpack已经成为主流的前端构建工具,因此有大量的生态系统和社区支持,包括各种loader、插件、优化工具等等。相比之下,Vite是较新的工具,社区和插件支持还比较有限。

当使用Vite和Webpack来构建一个简单的React应用时,它们之间会有以下区别:

使用Vite构建React应用的代码示例:

// vite.config.js
import reactRefresh from '@vitejs/plugin-react-refresh';

export default {
  plugins: [reactRefresh()],
};

// src/index.jsx
import React from 'react';
import ReactDOM from 'react-dom';

const App = () => {
  const [count, setCount] = React.useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));

使用Webpack构建React应用的代码示例:

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/index.jsx',

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js',
  },

  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
      {
        test: /.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },

  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
    }),
    new MiniCssExtractPlugin(),
  ],

  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 9000,
  },

  resolve: {
    extensions: ['.js', '.jsx', '.json'],
  },
};

可以看到,在Vite中,非常简单地设置了一个插件,然后在React组件中使用了Hooks,并在index.jsx文件中使用ReactDOM.render方法来渲染,而在Webpack的代码示例中,需要通过Webpack配置文件来引入插件、使用Loader加载器和Plugin插件以及配置打包输出文件的路径和名称等等,相比之下更为复杂。

1. 开发模式下的运行方式不同

Vite在开发模式下使用 Rollup 进行打包,并提供了一个内置的 HTTP 服务器来提供服务。它使用 ES modules 作为默认的模块系统,可以快速地进行热更新和快速构建。

Webpack在开发模式下使用自己的开发服务器进行工作,支持热更新,但通常需要使用一些插件来实现一些高级功能,如HMR(热模块替换)。

以下是一个使用Vite的示例代码,index.html 文件中直接引用模块,浏览器通过 Vite 内置的 HTTP 服务器加载模块:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>My App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

以下是一个使用Webpack的示例代码,webpack-dev-server通过监听文件变化来触发热更新:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js',
  },
  devServer: {
    contentBase: './dist',
    hot: true,
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'My App',
    }),
  ],
};

2. 构建方式和性能

Vite在开发模式下使用Rollup进行构建,支持按需编译和充分利用现代浏览器的原生ES模块,所以它的速度更快,比如热刷新延时更短、构建速度更快等。但在实际项目中,如需要自定义构建方式和高级功能的话,需要对Rollup的运行机制有一定的了解。

Webpack基于模块化思想和依赖分析,在生产模式下可以更好地实现代码压缩、分离、图片压缩等复杂的构建操作。同时Webpack还内置了一些优化策略,如启用多线程并发构建、使用Tree shaking技术等,因此Webpack在处理大型项目时更具优势。

以下是一个使用Vite的示例代码,build 命令会通过 Rollup 进行构建:

// vite.config.js

export default {
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    rollupOptions: {
      input: 'src/main.js',
    },
  },
}

以下是一个使用Webpack的示例代码,npm run build 命令会通过 Webpack 进行构建:

// webpack.config.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'My App',
    }),
  ],
};

3. 配置方式

Vite使用ES modules进行导入和导出,而配置文件也是一个ES module,可以直接使用ES6语法,简易直观。此外,Vite还提供了一个内置的插件管理系统和一些现成的插件,方便用户管理和使用。

Webpack使用CommonJS方式来导入和导出模块,配置文件是一个CommonJS模块,使用的是Node.js的API,需要一定的配置经验,但也更加灵活,可以满足

4. 支持的语言

Vite除了支持JavaScript和CSS,还支持以.vue文件为代表的单文件组件,这种组件可以将HTML、CSS和JavaScript打包到一个文件中。Vue.js等框架也积极支持Vite,称其是其未来的构建工具。

Webpack虽然可以支持JavaScript和CSS,但是它的打包方式更加灵活,支持Sass、Less等CSS预处理器,同时也可以使用Babel来支持ES6以上的JavaScript语法。

以下是一个使用Vite的示例代码,.vue文件包含HTML、CSS和JavaScript等三种代码:

<template>
  <div>
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      msg: 'Welcome to Your Vue.js App - Vite',
    }
  },
}
</script>

<style>
h1 {
  color: #00f;
}
</style>

以下是一个使用Webpack的示例代码,.scss文件包含CSS代码和变量:

$primary-color: #00f;

body {
  background-color: lighten($primary-color, 50%);
  color: darken($primary-color, 30%);
}

5. 插件生态和拓展性

Webpack的插件生态很丰富,提供了很多社区开发的插件,可以满足各种需求,可以针对性的选择安装,非常方便。同时Webpack还支持自定义插件,可以非常灵活地拓展其功能。

Vite的插件生态相对较少,但Vite插件系统提供了许多钩子和API,开发者可以通过编写自定义插件来扩展Vite的功能,比如添加自定义的路由、中间件等。

以上这些都是Vite和Webpack的区别。