background
Recently, a collection was made on the pain points and optimizeable items in the front-end development process. Among them, words such as time-consuming construction and slow project compilation speed appeared several times.
With the rapid development of business, the volume of many of our projects has also expanded rapidly. Then, there are problems such as slow packaging.
Improving R&D efficiency is the eternal pursuit of technicians.
Our project also has the problem of slow start, and colleagues have mentioned it several times. It just so happened that I had done similar exploration and optimization before, so I took this opportunity to transform the project and solve the problem of time-consuming startup.
Yesterday afternoon, Vite was successfully embedded, the project startup time was reduced from about 190s => 20s, and the hot update time was shortened to 2s.
I stepped on some pits in the middle, but fortunately I finally climbed out. The relevant technical points will be presented below.
Today's main content:
- Why does Vite start up so fast
- How can my project be implanted
- Problems encountered during Vite transformation and solutions
- Some thoughts on Vite development, packaging and launching
- Related code and conclusion
text
Why does Vite start up so fast
In terms of underlying implementation, Vite is based on esbuild pre-built dependencies.
esbuild is written in go and pre-builds dependencies 10 - 100 times faster than bundlers written in js.
Because js is too slow compared to go, the general operation of js is in milliseconds, and go is in nanoseconds.
In addition, the starting methods of the two are also different.
How to start webpack
How to start Vite
Webpack will package first, then start the development server, and give the packaging result directly when requesting the server.
However, Vite directly starts the development server, requests which module and then compiles the module in real time.
Since modern browsers support ES Module, they will automatically send requests to dependent Modules.
Vite takes full advantage of this, and treats the module files in the development environment as files to be executed by the browser, instead of packaging and merging them like Webpack.
Since Vite does not need to be packaged at startup, it means that there is no need to analyze module dependencies and no need to compile. So the startup is very fast. When the browser requests a module, the module content is compiled as needed.
This method of on-demand dynamic compilation greatly reduces the compilation time. The more complex the project and the more modules, the more obvious the advantages of vite.
In terms of HMR (hot update), when a module is changed, the browser only needs to request the module again, unlike webpack, which needs to compile all the related dependent modules of the module once, which is more efficient.
From the actual development experience, in Vite mode, the development environment can be started instantly, but it takes a while to wait until the page comes out.
How to implant my project into Vite
new project
Creating a new Vite project is relatively simple:
yarn create @vitejs/app
Once generated, just start it directly:
Existing project
The migration of existing projects is a little more cumbersome.
First, add the relevant configuration of Vite. Here I use a cli tool: wp2vite.
After installation, execute directly:
This step will automatically generate Vite configuration files and introduce related dependencies.
Just install the dependencies and start it.
If nothing else, you'll get a bunch of errors.
Congratulations, you have entered the happy stepping stage.
Problems I encountered during the remodel
1. alias error
Some aliases are configured in the project code, which cannot be recognized by vite, so aliases need to be configured in vite as well:
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
2. Unable to recognize less global variables
Solution:
You can inject custom global variables from the outside, and add them directly to the css option of vite.config.js:
css: {
preprocessorOptions: {
less: {
modifyVars: {
hack: `true;@import '${resolve('./src/vars.less')}';`,
...themeVariables,
},
javascriptEnabled: true,
},
},
},
3. Uncaught Error: Target container is not a DOM element.
Root element not found.
The reason is: in the index.html generated by default:
<div id="root"></div>
The id is root, and the logic is #app, just change it to id=app here.
4. The typings file could not be found
typings file not found.
This error, at first glance, is confusing.
Go in and have a look at the source code and the compiled code:
Source code:
After compiling:
Isn't the typings file right here, why can't it be found?
Think about it: Vite does not know that the typings file does not need to be compiled, and needs to tell the compiler not to compile this file.
Finally found the answer in the TS official documentation:
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html
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 need to be imported separately, so change the code to:
At the same time, note that if a file has multiple exports, they must be imported separately:
the only pain is: the whole thing needs to be changed again, manual work.
So far, the typings problem has been perfectly solved.
5. Cannot recognize svg
When we use svg as an icon component, it is generally:
import Icon from '@ant-design/icons';
import ErrorSvg from '@/assets/ico_error.svg';
const ErrorIcon = (props: any) => <Icon component={ErrorSvg} />;
// ...
<ErrorIcon />
The browser reports an error:
error occurred in the </src/assets/ico_error.svg> component
It is obvious that the file path is used as a component here.
What to do now is: replace this file path with a recognizable component.
After searching, I found a plugin: vite-plugin-react-svg
Join the configuration:
const reactSvgPlugin = require('vite-plugin-react-svg');
plugins: [
reactSvgPlugin(),
],
import MyIcon from './svgs/my-icon.svg?component';
function App() {
return (
<div>
<MyIcon />
</div>
);
}
It should be noted that the imported svg file needs to be suffixed with ?component.
After looking at the source code, this suffix is used as an identifier.
If the suffix matches a component, it parses the file, caches it, and finally returns the result:
After knowing the principle, you need to put all .svg => .svg?component .
Vscode can be replaced with one click, but be careful not to replace the ones in node_module.
6. global is undefined
global is a variable in Node, will it report an error on the client?
Looking at it layer by layer, it turns out that the imported third-party package uses global.
See the Client Types mentioned in the vite document:
append to tsconfig:
"compilerOptions": {
"types": ["node", "jest", "vite/client"],
}
Then, there's nothing messy about it. . .
There is no way, I have to use the window method.
Add in the entry index.tsx:
(window as any).global = window;
Refresh, that's it.
7. [Unsolved] Alternative to HtmlWebpackPlugin
It also needs to inject some external variables, modify the entry html, favicon, title and so on.
Found a plugin: vite-plugin-singlefile
But it didn't help.
Students who have knowledge, please leave a message to enlighten me.
So far, the whole app has been able to run locally, and the build is no problem.
8. Memory overflow occurs when packaging and building online
It can run locally, and it’s no problem to pack it. Of course, it will be run online later.
Schedule now!
Insufficient memory, I will add some for you:
Done!
Some thoughts on Vite development, packaging and launching
From the perspective of actual use, vite still cannot completely replace webpack in some functions.
After all, it is a rising star, and the related ecology still needs to be continuously improved.
Personally, I think a relatively safe way is to:
- Retain the ability of webpack dev & build, vite is only used as an aid for development
Wait for the relevant tools to be improved, and then consider completely migrating over.
Related code and conclusion
A complete Vite demo
Warehouse address: https://github.com/beMySun/react-hooks-i18n-template/tree/test-wp2vite
The complete configuration of vite.config.js for business projects
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,
},
},
},
});
at last
Using Vite can greatly shorten project construction time and improve development efficiency.
However, it is necessary to combine the actual situation of the project and make a reasonable choice.
For this project of mine, it is quite useful to use Vite as a way to assist development.
It is expected that Vite will continue to improve and improve the efficiency of research and development.
Well, that's about all the content, I hope it will be helpful to everyone.