背景
最近,就 前端开发过程中的痛点及可优化项
做了一次收集。其中, 构建耗时、我的项目编译速度慢
的字眼呈现了好几次。
随着业务的疾速倒退,咱们很多我的项目的体积也疾速收缩。随之而来的,就是打包变慢等问题。
晋升研发效率
,是技术人永恒的谋求。
咱们我的项目也有启动慢的问题,共事也提到过几次。刚好我之前也做过相似的摸索和优化,于是就借这个机会,革新一下我的项目,解决启动耗时的问题
。
于昨天下午(2021.4.7 23:00),胜利嵌入 Vite, 我的项目启动工夫由约 190s => 20s
, 热更新工夫缩短为 2s
。
两头踩了一些坑,好在最初爬出来了,相干技术要点都会在下文中出现。
FBI Warning:以下文字,只是我联合本人的理论我的项目, 总结进去的一些肤浅的教训,如有谬误,欢送斧正 :)
明天的次要内容:
为什么 Vite 启动这么快
我的我的项目如何植入 Vite
我在革新过程中遇到的问题
对于 Vite 开发、打包上线的一些思考
相干代码和论断
注释
为什么 Vite 启动这么快
底层实现上,Vite 是基于 esbuild 预构建依赖的。
esbuild 应用 go 编写,并且比以 js 编写的打包器预构建依赖, 快 10 – 100 倍。
因为 js 跟 go 相比切实是太慢了,js 的个别操作都是毫秒计,go 则是纳秒。
另外,两者的 启动形式
也有所差别。
webpack 启动形式
Vite 启动形式
Webpack 会 先打包
,而后启动开发服务器,申请服务器时间接给予打包后果。
而 Vite 是 间接启动
开发服务器,申请哪个模块再对该模块进行 实时编译
。
因为古代浏览器自身就反对 ES Module,会主动向依赖的 Module 发出请求。
Vite 充分利用了这一点,将开发环境下的模块文件,就作为浏览器要执行的文件,而不是像 W ebpack 那样进行 打包合并
。
因为 Vite 在启动的时候 不须要打包
,也就意味着 不须要剖析模块的依赖
、 不须要编译
。
因而启动速度十分快。当浏览器申请某个模块时,再依据须要对模块内容进行编译。
这种按需动静编译的形式,极大的缩减了编译工夫,我的项目越简单、模块越多,vite 的劣势越显著。
在 HMR(热更新)方面,当改变了一个模块后,仅需让浏览器从新申请该模块即可,不像 webpack 那样须要把该模块的相干依赖模块全副编译一次,效率更高。
从理论的开发体验来看,在 Vite 模式下,开发环境能够霎时启动,然而等到页面进去,要等一段时间。
我的我的项目如何植入 Vite
新我的项目
创立一个 Vite 新我的项目就比较简单:
yarn create @vitejs/app
生成好之后,间接启动就能够了:
已有我的项目
已有我的项目的迁徙,略微繁琐一些。
首先,退出 Vite 的相干配置。这里我应用了一个 cli 工具:wp2vite
.
装置好之后,间接执行:
这一步,会主动生成 Vite 的配置文件,并引入相干的依赖。
把依赖装置一下,启动就能够了。
如果没有意外的话,你会 播种一堆报错
。
祝贺你,进入开心欢快的踩坑环节。
我在革新过程中遇到的问题
1. alias 谬误
我的项目代码里配置了一些别名,vite 无奈辨认,所以须要在 vite 外面也配置 alias:
resolve: {
alias: {'@': resolve(__dirname, 'src'),
},
},
2. 无奈辨认 less 全局变量
解决办法:
把自定义的全局变量从内部注入即可,间接在 vite.config.js
的 css 选项中退出:
css: {
preprocessorOptions: {
less: {
modifyVars: {hack: `true;@import '${resolve('./src/vars.less')}';`,
...themeVariables,
},
javascriptEnabled: true,
},
},
},
3. Uncaught Error: Target container is not a DOM element.
根元素未找到。
起因是:默认生成的 index.html 中:
<div id="root"></div>
id 是 root, 而逻辑中的是#app
, 这里间接改成 id=app
即可。
4. typings 文件找不到
typings 文件未找到
。
这个谬误,乍一看,一头雾水。
进去看一下源代码和编译后的代码:
源代码:
编译后:
typings 文件这不是好好的在这吗,怎么就找不到?
想了一下:Vite 不晓得 typeings 文件是不须要被编译的,须要通知编译器不编译这个文件。
最初在 TS 官网文档里找到了答案:
https://www.typescriptlang.or…
Type-Only Imports and Export
This feature is something most users may never have to think about; however, if you’ve hit issues under –isolatedModules, TypeScript’s transpileModule API, or Babel, this feature might be relevant.
TypeScript 3.8 adds a new syntax for type-only imports and exports.
import type {SomeThing} from "./some-module.js";
export type {SomeThing};
须要独自引入 types, 于是把代码改为:
同时要留神,如果一个文件有有多个导出,也要离开引入:
惟一苦楚的是: 全局都须要改一遍,体力活。
至此,typeings 问题完满解决。
5. 无奈辨认 svg
咱们在应用 svg 作为图标组件的时候,个别是:
import Icon from '@ant-design/icons';
import ErrorSvg from '@/assets/ico_error.svg';
const ErrorIcon = (props: any) => <Icon component={ErrorSvg} />;
// ...
<ErrorIcon />
浏览器报错:
error occurred in the </src/assets/ico_error.svg> component
很显著的看到,这里是把 文件门路
作为组件了。
当初要做的是:把这个文件门路,换成能够辨认的组件。
搜寻一番,找到了个插件:vite-plugin-react-svg
退出配置:
const reactSvgPlugin = require('vite-plugin-react-svg');
plugins: [reactSvgPlugin(),
],
import MyIcon from './svgs/my-icon.svg?component';
function App() {
return (
<div>
<MyIcon />
</div>
);
}
须要留神的是:引入的 svg 文件须要加 ?component
作为后缀。
看了一下源码,这个后缀是用来作为标识符的,
如果后缀匹配上是component
, 就解析文件,并缓存,最初返回后果:
晓得原理之后,就须要把全副的 .svg
=> .svg?component
。
vscode 一键替换就能够,不过留神别把 node_module 外面的也替换了。
6. global 未定义
global
是 Node 外面的变量,会在客户端报错?
一层层看上来,原来是引入的第三方包应用了 global。
看 vite 文档里提到了 Client Types:
追加到 tsconfig
外面:
"compilerOptions": {"types": ["node", "jest", "vite/client"],
}
而后,并没有什么乱用。。。
没方法,只得祭出 window
大法。
在入口 index.tsx 外面加上:
(window as any).global = window;
刷新,好了。
7. [未解决] 代替 HtmlWebpackPlugin
还须要注入一些内部变量,批改入口 html, favicon, title 之类。
找到一个插件:vite-plugin-singlefile
不过并没有什么用。
有理解的同学请留言赐教。
至此,整个 app 曾经能在本地跑起来了,build 也没问题。
7. 线上打包构建时,内存溢出
本地能跑起来,打包也没问题,前面当然是放到线上跑一跑啦。
立即安顿!
内存不足,我就给你加点:
搞定!
对于 Vite 开发、打包上线的一些思考
从理论应用来看,vite 在一些性能上还是无奈齐全代替 webpack。
毕竟是后起之秀,相干的生态还须要继续欠缺。
集体认为,目前一种比拟稳当的形式是:
- 保留 webpack dev & build 的能力,
vite 仅作为开发的辅助
等相干工具再欠缺一些,再思考齐全迁徙过去。
相干代码和论断
一个残缺的 Vite demo
仓库地址:https://github.com/beMySun/re…
业务我的项目的 vite.config.js 残缺配置
import {defineConfig} from 'vite';
import reactRefresh from '@vitejs/plugin-react-refresh';
import legacyPlugin from '@vitejs/plugin-legacy';
import {resolve} from 'path';
const fs = require('fs');
const lessToJS = require('less-vars-to-js');
const themeVariables = lessToJS(fs.readFileSync(resolve(__dirname, './src/antd-custom.less'), 'utf8'));
const reactSvgPlugin = require('vite-plugin-react-svg');
// https://cn.vitejs.dev/config/
export default defineConfig({
base: './',
root: './',
resolve: {
alias: {
'react-native': 'react-native-web',
'@': resolve(__dirname, 'src'),
},
},
define: {'process.env.REACT_APP_IS_LOCAL': '\'true\'','window.__CID__': JSON.stringify(process.env.cid ||'id'),
},
server: {
port: 8080,
proxy: {
'/api': {
target: 'https://stoku.test.shopee.co.id/',
changeOrigin: true,
cookieDomainRewrite: {'stoku.test.shopee.co.id': 'localhost',},
},
},
},
build: {
target: 'es2015',
minify: 'terser',
manifest: false,
sourcemap: false,
outDir: 'build',
rollupOptions: {},},
esbuild: {},
optimizeDeps: {},
plugins: [
// viteSingleFile({
// title: 'dynamic title', // doesn't work
// }),
reactSvgPlugin(),
reactRefresh(),
legacyPlugin({
targets: [
'Android > 39',
'Chrome >= 60',
'Safari >= 10.1',
'iOS >= 10.3',
'Firefox >= 54',
'Edge >= 15',
],
}),
// vitePluginImp({
// libList: [
// {
// libName: 'antd',
// style: (name) => `antd/es/${name}/style`,
// },
// ],
// }),
],
css: {
preprocessorOptions: {
less: {
modifyVars: {hack: `true;@import '${resolve('./src/vars.less')}';`,
...themeVariables,
},
javascriptEnabled: true,
},
},
},
});
最初
应用 Vite 能大幅缩短我的项目构建工夫,晋升开发效率。
不过也要联合我的项目的理论状况,正当取舍。
对于我的这个我的项目而言,把 Vite 作为辅助开发的一种形式,还是挺有用的。
期待 Vite 能持续欠缺,为研发提效。
好了,内容大略就这么多,心愿对大家有所帮忙。
满腹经纶,如有谬误,欢送斧正。
谢谢。
最初,如果感觉内容有帮忙,能够关注下我的公众号,把握最新动静,一起学习!