When I tried to migrate the old project Webpack to Vite, I found that it was not so fragrant.

If you are interested in front-end eight-part essays, you can pay attention to the Gongzhong account: Code Farmer Supply Station, there is always the useful information you want.

Background

Recently, I made a collection of pain points and optimizable items in the front-end development process. Among them, the words “time-consuming to build and slow project compilation speed” appear several times.

With the rapid development of our business, the volume of many of our projects has also expanded rapidly. Along with this, problems such as slower packaging have arisen.

Improving R&D efficiency is the eternal pursuit of technicians.

Our project also has the problem of slow startup, and colleagues have mentioned it several times. I happened to have 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 pitfalls in the middle, but fortunately I climbed out in the end. The relevant technical points will be presented below.

Today’s main content:

  • Why Vite starts so fast
  • How to embed Vite into my project
  • Problems encountered during the transformation process and their solutions
  • Some thoughts on Vite development, packaging and launch
  • Related code and conclusions

Text

Why does Vite start so quickly

Underlying implementation, Vite is based on esbuild pre-built dependencies.

esbuild is written in go and is 10 – 100 times faster than packagers written in js to pre-build dependencies.

Because js is too slow compared to go. The general operations of js are measured in milliseconds, while go is measured in nanoseconds.

In addition, the startup methods of the two are also different.

webpack startup method

[9GQMK7]F7$UQ}9SRI(R7ML.png

Vite startup method

image.png

Webpack will package first, then start the development server, and directly give the packaging result when requesting the server.

Vite starts the development server directly, requests which module and then compiles the module in real time.

Since modern browsers natively support ES Modules, they will automatically make requests to dependent Modules.

Vite takes full advantage of this and uses 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 when it is started, it means that there is no need to analyze module dependencies or compile it. So the startup speed is very fast. When the browser requests a module, the module content is compiled as needed.

This method of dynamic compilation on demand greatly reduces compilation time. The more complex the project and the more modules there are, the more obvious the advantages of Vite will be.

In terms of HMR (hot update), after changing a module, you only need to ask the browser to request the module again. Unlike webpack, which needs to compile all the dependent modules of the module once, it is more efficient.

Judging from the actual development experience, in Vite mode, the development environment can be started instantly, but it takes a while until the page comes out.

How to embed Vite into my project

New Project

Creating a new Vite project is relatively simple:

yarn create @vitejs/app

QBRE_05QJLGA_5P0J5%P{%8.png

After it is generated, just start it directly:

3U042{4N4GC5NXWVJT_B{CA.png

Existing project

Migrating existing projects is a little more cumbersome.

First, add the relevant configuration of Vite. Here I used a cli tool: wp2vite.

After installation, directly execute:

In this step, Vite’s configuration file will be automatically generated and related dependencies will be introduced.

Install the dependencies and start it.

If nothing unexpected happens, you will get a bunch of errors.

Congratulations, you have entered the happy pit-trapping phase.

Problems I encountered during the transformation process

1. alias error

SL{2C(QBAGXD(D4)AHNH2JO.png

There are some aliases configured in the project code, which cannot be recognized by vite, so you need to configure alias in vite as well:


 resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
    },
  },

2. Less global variables cannot be recognized

FN8E(4)@3%F}7J@G%X}XG.png

Solution:

Just 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.

S0R435FNUU$88{F(WN0}JQW.png

Root element not found.

The reason is: in the index.html generated by default:

<div id="root"></div>

The id is root, and the logical one is #app. Just change it to id=app here.

4. typings file not found

typings file not found.

This error, at first glance, seems confusing.

Go in and take a look at the source code and compiled code:

source code:

After compilation:

Isn’t the typings file here? Why can’t I find it?

After thinking about it: Vite doesn’t know that the typings file does not need to be compiled, and needs to tell the compiler not to compile this file.

Finally I found the answer in the TS official documentation:

www.typescriptlang.org/docs/handbo…

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 introduced separately, so the code is changed to:

At the same time, please note that if a file has multiple exports, they must be imported separately:

The only painful thing is: the whole situation needs to be changed, which is physical work.

At this point, the typings problem is perfectly solved.

5. Unable to recognize svg

When we use svg as an icon component, it is usually:

import Icon from '@ant-design/icons';
import ErrorSvg from '@/assets/ico_error.svg';

const ErrorIcon = (props: any) => <Icon component={ErrorSvg} />;

// ...
<ErrorIcon />

Browser 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 we need to do now is: change this file path to a component that can be recognized.

After some searching, I found a plug-in: vite-plugin-react-svg

Add 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 added with ?component as a suffix.

After looking at the source code, this suffix is used as an identifier.

Y)76Q1$DTVQIYP99G@IO{5J.png

If the suffix matches component, the file is parsed, cached, and the result is returned:

After knowing the principle, you need to convert all .svg => .svg?component.

You can replace vscode with one click, but be careful not to replace the ones in node_module as well.

6. global is undefined

global is a variable in Node. Will an error be reported on the client?

Looking at it layer by layer, it turns out that the imported third-party package uses global.

Look at the vite documentation mentioning Client Types:

Append to tsconfig:


 "compilerOptions": {
    "types": ["node", "jest", "vite/client"],
 }

Then, there is no messing around. . .

I have no choice but to resort to the window method.

Add in the entry index.tsx:


(window as any).global = window;

Refresh, OK.

7. [Unresolved] Replace HtmlWebpackPlugin

You also need to inject some external variables, modify the entry html, favicon, title and so on.

Found a plugin: vite-plugin-singlefile

But it was of no use.

If you know anything about it, please leave a message and let me know.

At this point, the entire app can run locally, and the build is no problem.

8. Memory overflow occurs during online packaging and building

It can be run locally and packaged without any problem. Of course, it will be put online later.

Arrange now!

Insufficient memory, I will add some for you:

_`3DFJ7{1NX6$R}FUYM(H32.png

Done!

Some thoughts on Vite development, packaging and launch

From the actual use point of view, vite still cannot completely replace webpack in some functions.

After all, it is a rising star, and the related ecology needs to continue to be improved.

Personally, I think a safer way at present is:

  • Retain the ability of webpack dev & build, vite is only used as an assistant for development

Wait until the relevant tools are improved, and then consider completely migrating over.

Related codes and conclusions

A complete Vite demo

Warehouse address: github.com/beMySun/rea…

image.png

Vite.config.js complete configuration of business project


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,
      },
    },
  },
});

Finally

Using Vite can significantly shorten project construction time and improve development efficiency.

However, reasonable choices must be made based on the actual situation of the project.

For this project of mine, it is quite useful to use Vite as a way to assist development.

We look forward to Vite continuing to improve and improve efficiency for research and development.

Okay, that’s about all the content, I hope it will be helpful to everyone.

Original link: https://juejin.cn/post/7260688774623641657

The knowledge points of the article match the official knowledge archives, and you can further learn relevant knowledge. Vue entry-level skills treewebpack packaging toolFront-end modularization 39763 people are learning the system