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

insert image description here

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

insert image description here

How to start Vite

insert image description here
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

insert image description here
insert image description here
Once generated, just start it directly:
insert image description here

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:
insert image description here
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

insert image description here
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

insert image description here
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.

insert image description here
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

insert image description here
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: insert image description here
After compiling:
insert image description here
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:
insert image description here
At the same time, note that if a file has multiple exports, they must be imported separately:
insert image description here
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:
insert image description here

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.
insert image description here
If the suffix matches a component, it parses the file, caches it, and finally returns the result:
insert image description here
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

insert image description here
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:
insert image description here
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!
insert image description here
Insufficient memory, I will add some for you:
insert image description here

insert image description here
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
insert image description here

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.

Guess you like

Origin blog.csdn.net/zhangdaiscott/article/details/131974420