SoFunction
Updated on 2025-03-10

Vite builds projects and supports micro front-end

Thanks toSuper high performance of esbuild, vite has attracted much attention since its birth and has maintained active development iteration. Up to now, vite has iterated to version 2.7.10, and all aspects have basically met the conditions for production and use. During this period, I tried using vite for packaging construction in my project. This article is a record of the process of this construction.

Basic configuration

Use firstvite official scaffoldingGenerate project.

yarn create vite vite-demo --template react-ts

Use the above commandreact-tsThe template has been created calledvite-demoproject. Since the team I use react and typescript to develop on a daily basis, I chosereact-tsThere are many templates that vite officially supports, which can be found increate-viteView in  .

After the project is initialized, the directory structure is as follows:

.
|____index.html
|____.gitignore
|____package.json
|____tsconfig.json
|____vite.
|____src
| |____App.tsx
| |____main.tsx
| |____App.css
| |____index.css
| |____vite
| |____logo.svg
| |____favicon.svg

The contents are as follows:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// /config/
export default defineConfig({
  plugins: [react()]
})

It can be seen that vite has made relatively complete packaging, and the development experience has been greatly improved compared to the previous version.

After installing the dependencies as instructed, the speed is indeed very fast after starting the application. Now let’s do some basic transformations.

I usually use less to write styles. Vite has already done a good job of supporting it. After installing the dependencies, I just need to directly reference them in the code.Just do it. For a tried and tested developer, styles still need to be scoped, and css modules are usually used.

Install less preprocessor,

yarn add --dev less

Then modifyFile, add css modules configuration:

export default defineConfig({
  ...
  css: {
    modules: {
      localsConvention: 'camelCaseOnly', // We use the camel form    },
  },
  ...
})

After adding the configuration, just add the originalChange toThat's right, this is the same as create-react-app.

Here is a vscode plugin-css-modulesIt can realize intelligent prompts for style class names during encoding, and at the same time, click on the style class name to jump to the style definition place, which is very useful. If you use the naming method of the scribing form when writing styles, for example.xxx-container, then you need to configure this vscode plugin as follows

{
  "": true
}

This allows you to use the scribing form when writing styles, and the camel style is used in the code.

Since I developed a middle and backend project, using antd and lodash, everyone knows that these two are large users who load on demand. We used to usebabel-plugin-importTo deal with it, there are many similar solutions in the vite ecosystem. I chosevite-plugin-impThis plugin, modifiedas follows:

import vitePluginImp from 'vite-plugin-imp';

export default defineConfig({
  ...
  plugins: [
    ...
    vitePluginImp({
      libList: [
        {
          libName: 'lodash',
          libDirectory: '',
          camel2DashComponentName: false,
        },
        {
          libName: 'antd',
          style(name) {
              // use less
              return `antd/es/${name}/style/`;
          },
        },
      ],
    }),
  ],
  css: {
    ...
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
      },
    },
  },
});

antd already supports Tree Shaking by default, and the above configuration will eventually only handle styles on-demand loading. lodash does not support Tree Shaking, we can also use the ESM versionlodash-es, so that vite-plugin-imp can be used, and the configuration is as follows:

export default defineConfig({
  resolve: {
    alias: [{
      find: /^lodash$/,
      replacement: 'lodash-es',
    }],
  },
});

Usually, when we develop front-end projects, we need some proxy to call the back-end API interface, and the vite configuration is as follows:

export default defineConfig({
    ...
    server: {
      proxy: {
        '/api_path/': {
          target: '/',
          changeOrigin: true,
        },
      },
    },
});

The underlying agents are all based onhttp-proxyImplementation, I won’t explain too much here.

Now you can develop your code happily.

Support micro front-end construction

Because our middle and backend applications are managed using micro front-end (qiankun), the above configuration cannot be recognized by qiankun after packaging. The main reasons can be found.here, we need to do some extra processing.

We know that using webpack to build a micro front-end is necessary to add the following three configuration items:

{
  output: {
    libraryTarget: 'umd',
    library: `${APP_NAME}-[name]`,
    jsonpFunction: `webpackJsonp_${APP_NAME}`,
  }
}

In vite, you can directly use the settingsforumdTo set the UMD specification, but the actual construction results cannot be recognized by qiankun. It is conjecture that it may be related to vite's use of html entry.

To change the idea, we regard the current entire application as a library, output it as a UMD specification, and then manually write an html file to load the output JS.

Modify the configuration as follows:

export default defineConfig({
  ...
  build: {
    lib: {
      name,
      entry: (__dirname, 'src/'),
      formats: ['umd'],
    },
  },
  ...
})

After the configuration is completed, executeyarn buildThe prompt is as follows:

UMD and IIFE output formats are not supported for code-splitting builds.

Because there are routes in our application, we use on-demand loading. We will rollup theinlineDynamicImportsConfiguration open:

export default defineConfig({
  ...
  build: {
    rollupOptions: {
      output: {
        inlineDynamicImports: true,
      },
    },
  },
  ...
})

In this way, after the construction is completed, there are two files in the dist directory.and

Now we want to generateNow.

Because vite uses ES Modules directly in the development mode and is not packaged, it is generated in the development mode.and productionIt's different.

We modify the project root directoryfor:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/src/" rel="external nofollow"  />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
    <!-- style placeholder -->
  </head>
  <body>
    <div ></div>
    <!-- script placeholder -->
  </body>
</html>

Pay attention to the two lines of comments, we will do different processing in development mode and production construction.

There is one in the vite plugin APItransformindexhtmlThe html content in the development mode can be customized, so the configuration of our development mode is as follows:

// /config/
export default defineConfig({
  ...
  plugins: [
    ...
    {
      name: 'dev html',
      apply: 'serve',
      transformIndexHtml(indexHtml: string) {
        return indexHtml
          .replace('<!-- style placeholder -->', '')
          .replace('<!-- script placeholder -->', '<script type="module" src="/src/"></script>');
      },
    },
    ...
  ],
});

Production construction requires the help of@rollup/plugin-htmlThis plugin implements custom html content.

import html from '@rollup/plugin-html';
import fs from 'fs';

const entryHtml = ('./', { encoding: 'utf-8' });

export default defineConfig({
  ...
  plugins: [
    ...
    {
      name: 'build html',
      apply: 'build',
      ...html({
        template: () => {
          return entryHtml
            .replace(
              '<!-- style placeholder -->',
              '<link rel="stylesheet" type="text/css" href="" rel="external nofollow"  />',
            )
            .replace(
              '<!-- script placeholder -->',
              `<script type="text/javascript" src="${name}."></script>`,
            );
        },
      }),
    },
    ...
  ],
});

Through the above configuration, build again, qiankun can load this sub-app.

Other Instructions

1. Support for old browsers

Since my project this time is a middle and backend project, I don’t have strong demands on support for old browsers, so I didn’t deal with it in the project. In fact, vite official also gave a solution, that is@vitejs/plugin-legacyThis plugin.

The principle is also very simple, it is through<script nomodule>To implement the execution of related scripts in browsers that do not support ES Modules, and useSystemJSTo load the module.

2. Notes on TypeScript

After the initialization of the scaffolding is completed, it can be developed using TypeScript. Here is an additional explanation: the compiler option needs to be enabled.isolatedModules:true, because vite uses esbuild to process ts files, converting ts to js only without type checking (relying on the editor to handle type checking, such as vscode). Therefore, when encountering some pure type import and export, an error will occur and needs to be enabled.isolatedModules:trueTo avoid this problem. If this option cannot be enabled for some reasons, you can userollup-plugin-friendly-type-importsThis package is used to handle it, and the README of this package also explains why there is such a problem.

3. Connect CDN

Based on the above configuration, the root path used by the browser when loading resources (/) Loading, if CDN is used, the resource loading 404 will occur.

We can configurebaseTo set the basic path, similar to webpackPUBLIC_PATH

export default defineConfig({
  base: '/some/public/path',
})

4. Build error

4.1 Package not found

The error message is:

[plugin: vite:dep-scan] Failed to resolve entry for package "xxx"

Usually, the dependency package is not properly configured in the main, module and other fields, causing vite to fail to find the entrance to the package.

You can set the alias to map it to the correct file.

export default defineConfig({
  resolve: {
    alias: [{
      find: /^SOME_PACKAGE_NAME$/,
      replacement: 'SOME_PACKAGE_NAME/dist/',
    }],
  },
});

4.2 Request timeout

The error message is:

net::ERR_ABORTED 408 (Request Timeout)

After starting the development server, the browser experiences a request timeout error. This is because vite detects a request to the dependent package and the dependency has not been processed by vite. Pre-building will be triggered, resulting in request timeout and page overloading.

We can refresh the vite several times and complete the pre-build, or add dependencies.Come and handle it in advance.

4.3 An error occurred in importing module

The error message is:

Internal server error: Failed to resolve import "./" from "node_modules/.vite/?v=7bec0e27". Does the file exist?

Maybe it is because some dependency package output formats are not supported yet, you can check out this oneissue

This error only exists during the development server operation and processing process, and will not appear after the page is displayed normally. After ignoring this error, it has no effect at present.

summary

Overall, vite has basically met the conditions for production and use. If it is a regular application development, the configuration of vite is very simple and can be said to be used out of the box. It is also very convenient if you need to add additional configuration.

The big problem at present is that the surrounding ecology is not very mature, and many mature packages have weak support for vite (ES Modules). At the same time, if the infrastructure atmosphere within the team is relatively strong, the toolkit you develop yourself should also consider this aspect.

This is the article about vite construction project and supporting micro front-end. For more related vite construction project content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!