我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

我从 webpack 换到 vite,又换回了 webpack

CommonJs 与 ESM 关于循环依靠的处理的战略是天壤之别的,webpack 在运转时注入的webpack_require逻辑在处理循环依靠时的体现与 CommonJs 规范共同。Webapck 依据 moduleId,先到缓存里去找之前有没有加载过,假如有加载过,就直接拿缓存中的模块。假如没有,就新建一个 module,并赋值给缓存中,然后调用 moduleId 模块。所以由于缓存的存在,呈现循环依靠时才不会呈现无限循环调用的状况。

由于 ESM 的静态 import 才能,能够在代码运转之前对依靠链路进行静态剖析。所以在 ESM 形式下,一旦发现循环依靠,ES6 自身就不会再去执行依靠的那个模块了,所以程序能够正常完毕。这也说明晰 ES6 自身就支撑循环依靠,确保程序不会由于循环依靠陷入无限调用。

正是由于处理机制的不同,导致 Vite 下循环引证的文件都会呈现调用栈为 null 的状况。

找了个webpack插件circular-dependency-plugin 查看了一下循环引证的文件,发现像下面这样跨多组件引证的当地有几十处。改代码也不太实际,只能先换回webpack了。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

我从 webpack 换到 vite,又换回了 webpack

假如是其他文件的循环引证,也能够梳理更改。可是吊诡的当地在于,调用栈会呈现 null。这个在开发中呈现了底子没办法debug。有时候有上下文,仅仅中心呈现null还能揣度一下,假如提示一串null,那底子没办法开发。

我从 webpack 换到 vite,又换回了 webpack

CommonJs 与 ESM 关于循环依靠的处理的战略是天壤之别的,webpack 在运转时注入的webpack_require逻辑在处理循环依靠时的体现与 CommonJs 规范共同。Webapck 依据 moduleId,先到缓存里去找之前有没有加载过,假如有加载过,就直接拿缓存中的模块。假如没有,就新建一个 module,并赋值给缓存中,然后调用 moduleId 模块。所以由于缓存的存在,呈现循环依靠时才不会呈现无限循环调用的状况。

由于 ESM 的静态 import 才能,能够在代码运转之前对依靠链路进行静态剖析。所以在 ESM 形式下,一旦发现循环依靠,ES6 自身就不会再去执行依靠的那个模块了,所以程序能够正常完毕。这也说明晰 ES6 自身就支撑循环依靠,确保程序不会由于循环依靠陷入无限调用。

正是由于处理机制的不同,导致 Vite 下循环引证的文件都会呈现调用栈为 null 的状况。

找了个webpack插件circular-dependency-plugin 查看了一下循环引证的文件,发现像下面这样跨多组件引证的当地有几十处。改代码也不太实际,只能先换回webpack了。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

前言

Vite 经过一段时间的发展,目前的生态现已非常丰厚了。它不仅用于 VueReactSvelteSolidMarkoAstroShopify Hydrogen,以及 StorybookLaravelRails 等项目都现已接入了Vite,而且也趋于稳定,所以就着手把项目的 Webpack 替换为 Vite

切换为 Vite

Vite 生态现在很丰厚了,底子上插件按名称搜索一下,照着文档就能够把 webpack 替换到 Vite。由于每个项目的装备都不相同,所以也没有什么统一的操作步骤,下面列一些典型替换的比方。

进口

index.html 的位置需求放到项目的最外层,而不是 public 文件夹内。相同 entry 的进口文件也需求从 pages 里换到 index.html 里。由 <script type="module" src="https://juejin.im/post/7160670274521104397/..."> 引进。

module.exports = defineConfig({
  pages: {
    index: {
      // page 的进口
      entry: 'src/main.ts',
      // 模板来历
      template: 'index.html',
      chunks: ['chunk-vendors', 'chunk-common', 'index']
    }
  }
})
<!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" />
    <link rel="icon" href="/assets/favicon.ico" />
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

文件loader

这儿挑几个比方(下面比方 webpack 版本都为 webpack5)。

  1. yaml 由本来的 yaml-loader 替换为 rollup-plugin-yamlx
    rules: [
      {
        test: /.ya?ml$/,
        use: 'yaml-loader'
      }
    ]
import PluginYamlX from 'rollup-plugin-yamlx'
plugins: [
  ...other,
  PluginYamlX()
]
  1. svg-sprite 由本来的 svg-sprite-loader 替换为 vite-plugin-svg-icons
const resolve = (...dirs) => require('path').resolve(__dirname, ...dirs)
chainWebpack(config) {
    const svgRule = config.module.rule('svg')
    svgRule.exclude.add(resolve('base/assets/icons')).end()
    config.module
      .rule('icons')
      .test(/.svg$/)
      .include.add(resolve('base/assets/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'ys-svg-[name]'
      })
      .end()
}
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { resolve } from 'path'
const pathResolve = (dir: string): string => {
  return resolve(__dirname, '.', dir)
}
plugins: [
  ...other,
  createSvgIconsPlugin({
    // Specify the icon folder to be cached
    iconDirs: [pathResolve('base/assets/icons/svg')],
    // Specify symbolId format
    symbolId: 'ys-svg-[name]'
  }),
]
  1. 留意文件加载方法的共同性,比方本来的 svg-loader 直接 import 引证的是路径地址,而 vite-svg-loader 默许是 Vue 组件。 所以 Vite 需求把默许方法改成和 webpack lodaer 共同。
plugins: [
  svgLoader({ defaultImport: 'url' })
]

每个替换的插件都要看一下文档,也许某个装备便是你需求的功用。

大局常量

比方开发的版本信息,开发环境变量等等。

new webpack.DefinePlugin({
  APP_VERSION: process.env.VUE_APP_VERSION,
  ENV_TEST: process.env.VUE_ENV_TEST
})
import { defineConfig, loadEnv } from 'vite'
const { VITE_SENV_TEST, VITE_APP_VERSION } = loadEnv(mode, process.cwd())
export default ({ mode }: { mode: string }) => {
  return defineConfig({
    define: {
      APP_VERSIONVITE_APP_VERSIONENV_TESTVITE_SENV_TEST
    }
  })
})

这儿留意,Vite 和 webpack 默许露出的环境变量前缀不相同。

主动加载模块

比方 lodash

plugins: [
  new webpack.ProvidePlugin({
    _: 'lodash'
  }),
]
import inject from '@rollup/plugin-inject'
plugins: [
  inject({
    _: 'lodash',
    exclude: ['**/*.css', '**/*.yaml'],
    include: ['**/*.ts', '**/*.js', '**/*.vue', '**/*.tsx', '**/*.jsx']
  }),
]

底子上所有在用的插件都能够找到对应替换的,乃至像 monacoqiankunsentry运用量相对没那么大的都有。

这儿仅仅举例兼容旧代码,lodash 最好仍是写个工具替换成 es-loadsh。

webpack require context

在 webpack 中咱们能够经过require.context办法动态解析模块。比较常用的一个做法便是指定某个目录,经过正则匹配等方法加载某些模块,这样在后续增加新的模块后,能够起到动态主动导入的效果。

比方 layout,router 的主动注册都能够这样用。

const modules = require.context('base/assets/icons/svg', false, /.svg$/)

Vite 支撑运用特别的import.meta.glob函数从文件系统导入多个模块:

const modules = import.meta.glob('base/assets/icons/svg/*.svg')

externals

externals: {
  config: 'config',
}
import { viteExternalsPlugin } from 'vite-plugin-externals'
plugins: [
  viteExternalsPlugin({
    config: 'config'
  })
]

ESM 模块

由于 Vite 运用了 ESM 模块方法,所以 commonJs模块 都需求替换成 ESM模块

const path = require('path')
import path from 'path'

也正是由于这个原因,所以才会又换回了 webpack,这个下面再讲。

主动化转化

社区也有一些主动化从Wepback转为Vite的工具,比方vue-cli-plugin-vite,webpack-to-vite,wp2vite等等。

假如是小项目,能够测验一下。大项目不建议运用,不可控。感兴趣的能够去看对应的文档。

ESM 的循环引证问题

能够看到 ViteIssues 有许多相关的问题评论。

github.com/vitejs/vite… github.com/vitejs/vite…

假如是 Vue SFC 文件的循环引证,按官方文档来就能够解决。

我从 webpack 换到 vite,又换回了 webpack

假如是其他文件的循环引证,也能够梳理更改。可是吊诡的当地在于,调用栈会呈现 null。这个在开发中呈现了底子没办法debug。有时候有上下文,仅仅中心呈现null还能揣度一下,假如提示一串null,那底子没办法开发。

我从 webpack 换到 vite,又换回了 webpack

CommonJs 与 ESM 关于循环依靠的处理的战略是天壤之别的,webpack 在运转时注入的webpack_require逻辑在处理循环依靠时的体现与 CommonJs 规范共同。Webapck 依据 moduleId,先到缓存里去找之前有没有加载过,假如有加载过,就直接拿缓存中的模块。假如没有,就新建一个 module,并赋值给缓存中,然后调用 moduleId 模块。所以由于缓存的存在,呈现循环依靠时才不会呈现无限循环调用的状况。

由于 ESM 的静态 import 才能,能够在代码运转之前对依靠链路进行静态剖析。所以在 ESM 形式下,一旦发现循环依靠,ES6 自身就不会再去执行依靠的那个模块了,所以程序能够正常完毕。这也说明晰 ES6 自身就支撑循环依靠,确保程序不会由于循环依靠陷入无限调用。

正是由于处理机制的不同,导致 Vite 下循环引证的文件都会呈现调用栈为 null 的状况。

找了个webpack插件circular-dependency-plugin 查看了一下循环引证的文件,发现像下面这样跨多组件引证的当地有几十处。改代码也不太实际,只能先换回webpack了。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

前言

Vite 经过一段时间的发展,目前的生态现已非常丰厚了。它不仅用于 VueReactSvelteSolidMarkoAstroShopify Hydrogen,以及 StorybookLaravelRails 等项目都现已接入了Vite,而且也趋于稳定,所以就着手把项目的 Webpack 替换为 Vite

切换为 Vite

Vite 生态现在很丰厚了,底子上插件按名称搜索一下,照着文档就能够把 webpack 替换到 Vite。由于每个项目的装备都不相同,所以也没有什么统一的操作步骤,下面列一些典型替换的比方。

进口

index.html 的位置需求放到项目的最外层,而不是 public 文件夹内。相同 entry 的进口文件也需求从 pages 里换到 index.html 里。由 <script type="module" src="https://juejin.im/post/7160670274521104397/..."> 引进。

module.exports = defineConfig({
  pages: {
    index: {
      // page 的进口
      entry: 'src/main.ts',
      // 模板来历
      template: 'index.html',
      chunks: ['chunk-vendors', 'chunk-common', 'index']
    }
  }
})
<!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" />
    <link rel="icon" href="/assets/favicon.ico" />
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

文件loader

这儿挑几个比方(下面比方 webpack 版本都为 webpack5)。

  1. yaml 由本来的 yaml-loader 替换为 rollup-plugin-yamlx
    rules: [
      {
        test: /.ya?ml$/,
        use: 'yaml-loader'
      }
    ]
import PluginYamlX from 'rollup-plugin-yamlx'
plugins: [
  ...other,
  PluginYamlX()
]
  1. svg-sprite 由本来的 svg-sprite-loader 替换为 vite-plugin-svg-icons
const resolve = (...dirs) => require('path').resolve(__dirname, ...dirs)
chainWebpack(config) {
    const svgRule = config.module.rule('svg')
    svgRule.exclude.add(resolve('base/assets/icons')).end()
    config.module
      .rule('icons')
      .test(/.svg$/)
      .include.add(resolve('base/assets/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'ys-svg-[name]'
      })
      .end()
}
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { resolve } from 'path'
const pathResolve = (dir: string): string => {
  return resolve(__dirname, '.', dir)
}
plugins: [
  ...other,
  createSvgIconsPlugin({
    // Specify the icon folder to be cached
    iconDirs: [pathResolve('base/assets/icons/svg')],
    // Specify symbolId format
    symbolId: 'ys-svg-[name]'
  }),
]
  1. 留意文件加载方法的共同性,比方本来的 svg-loader 直接 import 引证的是路径地址,而 vite-svg-loader 默许是 Vue 组件。 所以 Vite 需求把默许方法改成和 webpack lodaer 共同。
plugins: [
  svgLoader({ defaultImport: 'url' })
]

每个替换的插件都要看一下文档,也许某个装备便是你需求的功用。

大局常量

比方开发的版本信息,开发环境变量等等。

new webpack.DefinePlugin({
  APP_VERSION: process.env.VUE_APP_VERSION,
  ENV_TEST: process.env.VUE_ENV_TEST
})
import { defineConfig, loadEnv } from 'vite'
const { VITE_SENV_TEST, VITE_APP_VERSION } = loadEnv(mode, process.cwd())
export default ({ mode }: { mode: string }) => {
  return defineConfig({
    define: {
      APP_VERSIONVITE_APP_VERSIONENV_TESTVITE_SENV_TEST
    }
  })
})

这儿留意,Vite 和 webpack 默许露出的环境变量前缀不相同。

主动加载模块

比方 lodash

plugins: [
  new webpack.ProvidePlugin({
    _: 'lodash'
  }),
]
import inject from '@rollup/plugin-inject'
plugins: [
  inject({
    _: 'lodash',
    exclude: ['**/*.css', '**/*.yaml'],
    include: ['**/*.ts', '**/*.js', '**/*.vue', '**/*.tsx', '**/*.jsx']
  }),
]

底子上所有在用的插件都能够找到对应替换的,乃至像 monacoqiankunsentry运用量相对没那么大的都有。

这儿仅仅举例兼容旧代码,lodash 最好仍是写个工具替换成 es-loadsh。

webpack require context

在 webpack 中咱们能够经过require.context办法动态解析模块。比较常用的一个做法便是指定某个目录,经过正则匹配等方法加载某些模块,这样在后续增加新的模块后,能够起到动态主动导入的效果。

比方 layout,router 的主动注册都能够这样用。

const modules = require.context('base/assets/icons/svg', false, /.svg$/)

Vite 支撑运用特别的import.meta.glob函数从文件系统导入多个模块:

const modules = import.meta.glob('base/assets/icons/svg/*.svg')

externals

externals: {
  config: 'config',
}
import { viteExternalsPlugin } from 'vite-plugin-externals'
plugins: [
  viteExternalsPlugin({
    config: 'config'
  })
]

ESM 模块

由于 Vite 运用了 ESM 模块方法,所以 commonJs模块 都需求替换成 ESM模块

const path = require('path')
import path from 'path'

也正是由于这个原因,所以才会又换回了 webpack,这个下面再讲。

主动化转化

社区也有一些主动化从Wepback转为Vite的工具,比方vue-cli-plugin-vite,webpack-to-vite,wp2vite等等。

假如是小项目,能够测验一下。大项目不建议运用,不可控。感兴趣的能够去看对应的文档。

ESM 的循环引证问题

能够看到 ViteIssues 有许多相关的问题评论。

github.com/vitejs/vite… github.com/vitejs/vite…

假如是 Vue SFC 文件的循环引证,按官方文档来就能够解决。

我从 webpack 换到 vite,又换回了 webpack

假如是其他文件的循环引证,也能够梳理更改。可是吊诡的当地在于,调用栈会呈现 null。这个在开发中呈现了底子没办法debug。有时候有上下文,仅仅中心呈现null还能揣度一下,假如提示一串null,那底子没办法开发。

我从 webpack 换到 vite,又换回了 webpack

CommonJs 与 ESM 关于循环依靠的处理的战略是天壤之别的,webpack 在运转时注入的webpack_require逻辑在处理循环依靠时的体现与 CommonJs 规范共同。Webapck 依据 moduleId,先到缓存里去找之前有没有加载过,假如有加载过,就直接拿缓存中的模块。假如没有,就新建一个 module,并赋值给缓存中,然后调用 moduleId 模块。所以由于缓存的存在,呈现循环依靠时才不会呈现无限循环调用的状况。

由于 ESM 的静态 import 才能,能够在代码运转之前对依靠链路进行静态剖析。所以在 ESM 形式下,一旦发现循环依靠,ES6 自身就不会再去执行依靠的那个模块了,所以程序能够正常完毕。这也说明晰 ES6 自身就支撑循环依靠,确保程序不会由于循环依靠陷入无限调用。

正是由于处理机制的不同,导致 Vite 下循环引证的文件都会呈现调用栈为 null 的状况。

找了个webpack插件circular-dependency-plugin 查看了一下循环引证的文件,发现像下面这样跨多组件引证的当地有几十处。改代码也不太实际,只能先换回webpack了。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

前言

Vite 经过一段时间的发展,目前的生态现已非常丰厚了。它不仅用于 VueReactSvelteSolidMarkoAstroShopify Hydrogen,以及 StorybookLaravelRails 等项目都现已接入了Vite,而且也趋于稳定,所以就着手把项目的 Webpack 替换为 Vite

切换为 Vite

Vite 生态现在很丰厚了,底子上插件按名称搜索一下,照着文档就能够把 webpack 替换到 Vite。由于每个项目的装备都不相同,所以也没有什么统一的操作步骤,下面列一些典型替换的比方。

进口

index.html 的位置需求放到项目的最外层,而不是 public 文件夹内。相同 entry 的进口文件也需求从 pages 里换到 index.html 里。由 <script type="module" src="https://juejin.im/post/7160670274521104397/..."> 引进。

module.exports = defineConfig({
  pages: {
    index: {
      // page 的进口
      entry: 'src/main.ts',
      // 模板来历
      template: 'index.html',
      chunks: ['chunk-vendors', 'chunk-common', 'index']
    }
  }
})
<!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" />
    <link rel="icon" href="/assets/favicon.ico" />
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

文件loader

这儿挑几个比方(下面比方 webpack 版本都为 webpack5)。

  1. yaml 由本来的 yaml-loader 替换为 rollup-plugin-yamlx
    rules: [
      {
        test: /.ya?ml$/,
        use: 'yaml-loader'
      }
    ]
import PluginYamlX from 'rollup-plugin-yamlx'
plugins: [
  ...other,
  PluginYamlX()
]
  1. svg-sprite 由本来的 svg-sprite-loader 替换为 vite-plugin-svg-icons
const resolve = (...dirs) => require('path').resolve(__dirname, ...dirs)
chainWebpack(config) {
    const svgRule = config.module.rule('svg')
    svgRule.exclude.add(resolve('base/assets/icons')).end()
    config.module
      .rule('icons')
      .test(/.svg$/)
      .include.add(resolve('base/assets/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'ys-svg-[name]'
      })
      .end()
}
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { resolve } from 'path'
const pathResolve = (dir: string): string => {
  return resolve(__dirname, '.', dir)
}
plugins: [
  ...other,
  createSvgIconsPlugin({
    // Specify the icon folder to be cached
    iconDirs: [pathResolve('base/assets/icons/svg')],
    // Specify symbolId format
    symbolId: 'ys-svg-[name]'
  }),
]
  1. 留意文件加载方法的共同性,比方本来的 svg-loader 直接 import 引证的是路径地址,而 vite-svg-loader 默许是 Vue 组件。 所以 Vite 需求把默许方法改成和 webpack lodaer 共同。
plugins: [
  svgLoader({ defaultImport: 'url' })
]

每个替换的插件都要看一下文档,也许某个装备便是你需求的功用。

大局常量

比方开发的版本信息,开发环境变量等等。

new webpack.DefinePlugin({
  APP_VERSION: process.env.VUE_APP_VERSION,
  ENV_TEST: process.env.VUE_ENV_TEST
})
import { defineConfig, loadEnv } from 'vite'
const { VITE_SENV_TEST, VITE_APP_VERSION } = loadEnv(mode, process.cwd())
export default ({ mode }: { mode: string }) => {
  return defineConfig({
    define: {
      APP_VERSIONVITE_APP_VERSIONENV_TESTVITE_SENV_TEST
    }
  })
})

这儿留意,Vite 和 webpack 默许露出的环境变量前缀不相同。

主动加载模块

比方 lodash

plugins: [
  new webpack.ProvidePlugin({
    _: 'lodash'
  }),
]
import inject from '@rollup/plugin-inject'
plugins: [
  inject({
    _: 'lodash',
    exclude: ['**/*.css', '**/*.yaml'],
    include: ['**/*.ts', '**/*.js', '**/*.vue', '**/*.tsx', '**/*.jsx']
  }),
]

底子上所有在用的插件都能够找到对应替换的,乃至像 monacoqiankunsentry运用量相对没那么大的都有。

这儿仅仅举例兼容旧代码,lodash 最好仍是写个工具替换成 es-loadsh。

webpack require context

在 webpack 中咱们能够经过require.context办法动态解析模块。比较常用的一个做法便是指定某个目录,经过正则匹配等方法加载某些模块,这样在后续增加新的模块后,能够起到动态主动导入的效果。

比方 layout,router 的主动注册都能够这样用。

const modules = require.context('base/assets/icons/svg', false, /.svg$/)

Vite 支撑运用特别的import.meta.glob函数从文件系统导入多个模块:

const modules = import.meta.glob('base/assets/icons/svg/*.svg')

externals

externals: {
  config: 'config',
}
import { viteExternalsPlugin } from 'vite-plugin-externals'
plugins: [
  viteExternalsPlugin({
    config: 'config'
  })
]

ESM 模块

由于 Vite 运用了 ESM 模块方法,所以 commonJs模块 都需求替换成 ESM模块

const path = require('path')
import path from 'path'

也正是由于这个原因,所以才会又换回了 webpack,这个下面再讲。

主动化转化

社区也有一些主动化从Wepback转为Vite的工具,比方vue-cli-plugin-vite,webpack-to-vite,wp2vite等等。

假如是小项目,能够测验一下。大项目不建议运用,不可控。感兴趣的能够去看对应的文档。

ESM 的循环引证问题

能够看到 ViteIssues 有许多相关的问题评论。

github.com/vitejs/vite… github.com/vitejs/vite…

假如是 Vue SFC 文件的循环引证,按官方文档来就能够解决。

我从 webpack 换到 vite,又换回了 webpack

假如是其他文件的循环引证,也能够梳理更改。可是吊诡的当地在于,调用栈会呈现 null。这个在开发中呈现了底子没办法debug。有时候有上下文,仅仅中心呈现null还能揣度一下,假如提示一串null,那底子没办法开发。

我从 webpack 换到 vite,又换回了 webpack

CommonJs 与 ESM 关于循环依靠的处理的战略是天壤之别的,webpack 在运转时注入的webpack_require逻辑在处理循环依靠时的体现与 CommonJs 规范共同。Webapck 依据 moduleId,先到缓存里去找之前有没有加载过,假如有加载过,就直接拿缓存中的模块。假如没有,就新建一个 module,并赋值给缓存中,然后调用 moduleId 模块。所以由于缓存的存在,呈现循环依靠时才不会呈现无限循环调用的状况。

由于 ESM 的静态 import 才能,能够在代码运转之前对依靠链路进行静态剖析。所以在 ESM 形式下,一旦发现循环依靠,ES6 自身就不会再去执行依靠的那个模块了,所以程序能够正常完毕。这也说明晰 ES6 自身就支撑循环依靠,确保程序不会由于循环依靠陷入无限调用。

正是由于处理机制的不同,导致 Vite 下循环引证的文件都会呈现调用栈为 null 的状况。

找了个webpack插件circular-dependency-plugin 查看了一下循环引证的文件,发现像下面这样跨多组件引证的当地有几十处。改代码也不太实际,只能先换回webpack了。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。

我从 webpack 换到 vite,又换回了 webpack

CommonJs 与 ESM 关于循环依靠的处理的战略是天壤之别的,webpack 在运转时注入的webpack_require逻辑在处理循环依靠时的体现与 CommonJs 规范共同。Webapck 依据 moduleId,先到缓存里去找之前有没有加载过,假如有加载过,就直接拿缓存中的模块。假如没有,就新建一个 module,并赋值给缓存中,然后调用 moduleId 模块。所以由于缓存的存在,呈现循环依靠时才不会呈现无限循环调用的状况。

由于 ESM 的静态 import 才能,能够在代码运转之前对依靠链路进行静态剖析。所以在 ESM 形式下,一旦发现循环依靠,ES6 自身就不会再去执行依靠的那个模块了,所以程序能够正常完毕。这也说明晰 ES6 自身就支撑循环依靠,确保程序不会由于循环依靠陷入无限调用。

正是由于处理机制的不同,导致 Vite 下循环引证的文件都会呈现调用栈为 null 的状况。

找了个webpack插件circular-dependency-plugin 查看了一下循环引证的文件,发现像下面这样跨多组件引证的当地有几十处。改代码也不太实际,只能先换回webpack了。

我从 webpack 换到 vite,又换回了 webpack

webpack 的优化

webpack 仍是用官方封装的 Vue CLI

缓存

webpack4 仍是运用 hard-source-webpack-plugin 为模块供给中心缓存的,可是 webpack5 现已内置了该功用。

module.exports = {
  chainWebpack(config) {
    config.cache(true)
  }
}

hard-source-webpack-plugin 作者现已被 webpack 招安了,原插件也现已不保护了,所以有条件仍是升级到 webpack5

esbuild 编译

编译能够运用 esbuild-loader 来替换 babel-loader,打包这一块就和 Vite 相差不多了。

我从 webpack 换到 vite,又换回了 webpack

看了下 vue-cli 的装备,需求换的 rule 是这几个。大约的装备如下:

chainWebpack(config) {
const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        jsxFactory: 'h',
	jsxFragment: 'Fragment',
	loader: 'jsx',
	target: 'es2015'
      })
      .end()
const tsRule = config.module.rule('typescript')
    tsRule.uses.clear()
    tsRule
      .use('ts')
      .loader('esbuild-loader')
      .end()
}

留意,上面的 jsx 装备只适用于 Vue3,由于 Vue2 没有露出 h 办法。

假如要在 Vue2 上运用 jsx 解析,得需求一个解析 Vue2 语法完好运转时的包。
pnpm i @lancercomet/vue2-jsx-runtime -D

React 关于全新 JSX 转化的思维
@lancercomet/vue2-jsx-runtime github

大约便是把 jsx transform结构单独移了出来,以脱离结构适配 SWCTSC 或许 ESBuildjsx transform

    const rule = config.module.rule('js')
    // 整理自带的babel-loader
    rule.uses.clear()
    // 增加esbuild-loader
    rule
      .use('esbuild-loader')
      .loader('esbuild-loader')
      .options({
        target: 'es2015',
        loader: 'jsx',
        jsx: 'automatic',
        jsxImportSource: '@lancercomet/vue2-jsx-runtime'
      })
      .end()

一起需求修正 tsconfig.json

{
  "compilerOptions": {
    ...
    "jsx": "react-jsx",  // Please set to "react-jsx". 
    "jsxImportSource": "@lancercomet/vue2-jsx-runtime"  // Please set to package name.
  }
}

类型查看

类型查看这块开发时能够交给 IDE 来处理,没必要再跑一个线程。

  chainWebpack(config) {
    // disable type check and let `vue-tsc` handles it
    config.plugins.delete('fork-ts-checker')
  }

代码紧缩

这些其实功用影响现已不大了,聊胜于无。

const { ESBuildMinifyPlugin } = require('esbuild-loader')
  chainWebpack(config) {
    config.optimization.minimizers.delete('terser')
    config.optimization.minimizer('esbuild').use(ESBuildMinifyPlugin, [{ minify: true, css: true }])
  }

优化成果

这是 Vue-CLI 优化之后的打包,现已和 Vite 底子共同了。至于开发,两者的逻辑不相同,热更新确实是慢。

我从 webpack 换到 vite,又换回了 webpack

我从 webpack 换到 vite,又换回了 webpack

完毕

Vite 的生态现已很丰厚了,底子能满意绝大多数的需求了。咱们这次搬迁由于平常开发留传的一些问题而失利了。应该检讨平常写代码不能只为了快,而疏忽一些细节。

这便是本篇文章的全部内容了,感谢咱们的观看。