preface

  • I wrote that beforevite 与 vue2Integrated articles, just call himπŸ–– Vue2. X retrofit ⚑️ Vite – 1.0
  • Time flies, more than a month has passed and a certain degree of accumulation of a part of the new posture, need to1.0Make some improvements and additions; Then write the2.0
  • 2.0Mainly forviteIntegrate and do somethingMining pit guide, and1.0It doesn’t matterPlease eat directly

πŸ“’ Note: It is only recommended to run vite in development mode in the production environment as before; Webpack, after all, is more sophisticated in packaging

Project background

  • The transformation project is a very important, iterative and frequent system of the company; It now has over 100 pages
  • Engineering formwork by@vue/cliTo create thevue2.xVersion for internal usewebpack4.xbuild
  • As projects get bigger (50 pages per year or so), the need for a cold start becomes more pressing

Technical analysis

  • While Vite is growing fast, NPM plugins for Vite are also catching on fast; But there was always something out of reach in our old projects

  • Here I mainly with my actual transformation of the problems encountered to do the technical summary, if you have encountered other problems in the process of use, this article to solve the problem ideas also have a certain reference value

  • The following are the transformation problems I encountered (for vue2 project generated by @vue/ CLI)

    1. The default project root directory entry is requiredindex.htmlPoint to existingpublic/index.html
    2. Convert CSS notation@import '~normalize.css/normalize.cssIn the~The alias
    3. eliminateimport('@/pages/' + path)Written in vite warning ⚠️
    4. conversionrequire δΈΊ importSyntax —- CommonJs to ESModule
    5. The compatible webpackrequire.contexgrammar
    6. support<script>Write in code blockjsxSyntax —- render returns JSX

vite plugins

  • First, the project was modified based on an official plugin, Vite-plugin-vue2

    npm i -D vite-plugin-vue2
    Copy the code
  • You might want to know how to write a Vite plugin first

Point index.html to public/index.html

  • Plug-in vite – plugin – HTML – the template

    npm i -D vite-plugin-html-template
    Copy the code
  • Quote from vite’s official website

    You may have noticed that in a Vite project, index.html is in the outermost layer of the project instead of in the public folder. This is intentional: Vite is a server during development, and index.html is the entry file for that Vite project.

  • The principle of analytic

    1. In development modeviteAll resources are passedhttp serverReturn to before browsingindex.htmlThere is no exception

    This means that we can intercept/and /index.html requests through the plugin’s configureServer and then read public/index.html and return it

    {
      name: 'vite-vue2:html'.configureServer(server) {
        server.middlewares.use((req, res, next) = > {
          // Intercepts/or /index.html requests
          if (req.url === '/' || req.url === '/index.html') {
            const html = fs.readFileSync(path.join(__dirname, 'public/index.html'), 'utf8')
            / / return public/index. HTML
            res.end(html)
          } else {
            next()
          }
        })
      },
    }
    Copy the code
    1. In build mode we need to touch a new concept virtual file
    • Official Demo πŸ‘‰ introduces a virtual file

    • We use load to properly load public/index.html in build mode

      {
        name: 'vite-vue2:html'.load(id) {
          if (id.endsWith('index.html')) {
            const html = fs.readFileSync(path.join(__dirname, 'public/index.html'), 'utf8')
            / / return public/index. HTML
            return html
          }
        },
      }
      Copy the code
    • XDM might say why not load index.html via config.root;

    • The root directory of the vue2 project is the source directory, and index. HTML appears as source code, not as a static file

    • Changing config.root to public causes many other problems; For example, @/views/home.vue is intended to find/SRC /views/home.vue

    • πŸ‘‰ index.html is the entry file for the Vite project

Convert CSS notation@import '~normalize.css/normalize.cssIn the~The alias

  • This is aviteMore powerful parts, support the use ofresolve.alias Official note πŸ‘‰ Vite path aliases also comply with CSS
  • Pit!!!!!!: only recognizealias/xxxxDon’t recognizealiasxxxx
    • You have the following configuration
        {
          resolve: {
            alias: {
              The '@': path.join(__dirname, 'src'),
              '~': path.join(__dirname, 'node_modules'), // This is usually used for CSS import}}}Copy the code
    • They will be@/xxxx,~/xxxxHit,But not by @xxxx,~xxxxhit
    • A lot of people have this when they write CSS@import '~normalize.css/normalize.css'; —- This inability to hit
    • You need to write it like this
        resolve: {
          alias: [
            // For @xxxx and @/ XXXX
            { find: The '@'.replacement: path.join(__dirname, 'src')},/ / ~ / XXXX
            { find: ~ / / * * // ^ ~? = \ /), replacement: path.join(__dirname, 'node_modules')},/ / ~ XXXX
            { find: / * ~ * // ^ ~? ! / / /), replacement: path.join(__dirname, 'node_modules/')},]},Copy the code

eliminateimport('@/pages/' + path)Written in vite warning ⚠️

  • Plug-in vite – plugin – dynamic – import

    npm i -D vite-plugin-dynamic-import
    Copy the code
  • So this is kind of a tricky one, and there are two things to think about

    1. @This alias replacement —- vite reported an error
    2. pathDynamic path analysis —- vite warning
  • The principle of analytic

    1. impot('@/pages/' + path)You essentially enumerate all the files under Pages and generate oneswitchTo provide matching

    If the directory structure is as follows:

    β”œ ─ ─ SRC / | β”œ ─ ─ pages / | | β”œ ─ ─ foo vue | | β”œ ─ ─ bar / | | | β”œ ─ ─ index. The vue | β”œ ─ ─ routes. The tsCopy the code
    // src/routes.ts
    function load(path) {
      return import('@/pages/' + path)
    }
    
    const routes = [
      {
        name: 'foo'.path: '/foo'.component: () = > load('foo'),}, {name: 'bar'.path: '/bar'.component: () = > load('bar'),},]Copy the code

    Will generate:

    function load(path) {
      return __variableDynamicImportRuntime__('@/pages/' + path)
    }
    
    const routes = [
      {
        name: 'foo'.path: '/foo'.component: () = > load('foo'),}, {name: 'bar'.path: '/bar'.component: () = > load('bar'),},]// List all possible paths
    function __variableDynamicImportRuntime__(path) {
      switch (path) {
        case './pages/foo': return import('./pages/foo.vue');
        case './pages/foo.vue': return import('./pages/foo.vue');
        case './pages/bar': return import('./pages/bar/index.vue');
        case './pages/bar/index': return import('./pages/bar/index.vue');
        case './pages/bar/index.vue': return import('./pages/bar/index.vue'); }}Copy the code
  • See the dynamic-import-vars link

conversionrequire δΈΊ importgrammar

  • Plug-in vite plugin — commonjs

    npm i -D vite-plugin-commonjs
    Copy the code
  • The problem is CommonJs to ESModule, NPM found several packages do not implement my function (either do not convert, or inject environment variables error); Simply wrote a simplified version of their own, but also to broaden their technical line (can not eat ready-made, will do their own is not)

  • Technology selection

    1. acornJs Abstract Syntax tree (AST) tool
    2. acorn-walkSyntax tree traversal tool
  • The principle of analytic

    1. Let’s use Acorn to convert the code toAST
    2. Use acorn-walk to traverseASTParse out the file that require loads and convert it to import format

    If there is code below

    const pkg = require('.. /package.json');
    
    const routers = [{
      path: '/foo'.component: require('@/pages/foo.vue').default;
    }];
    Copy the code

    Will generate:

    import pkg  from ".. /package.json";
    import _MODULE_default___EXPRESSION_object__ from "@/pages/foo.vue";
    
    const routers = [{
      path: '/foo'.component: _MODULE_default___EXPRESSION_object__;
    }];
    Copy the code

The compatible webpackrequire.contexgrammar

  • Plug-in @ originjs/vite – plugin – the require – context

    npm i -D @originjs/vite-plugin-require-context
    Copy the code
  • Consistent with vite’s built-in import.meta.globEager behavior

support<script>Write in code blockjsxgrammar

  • in@vue/cliThe configurationbabel.confg.jsYou can use it directlyjsx
  • invite-plugin-vue2Need to specify<script lang="jsx">

Complete configuration

  • Add in the project root directoryvite.config.ts

Note: The following configuration may need to be adjusted to suit your project

import path from 'path'
import { defineConfig } from 'vite'
Mandatory * Vite supports the official vue2 plug-in
import { createVuePlugin } from 'vite-plugin-vue2'
// Mandatory * Read public/index.html
import htmlTemplate from 'vite-plugin-html-template'
// Optional - compatible with CommonJs
import { vitePluginCommonjs } from 'vite-plugin-commonjs'
// Optional - compatible import('@views/' + path)
import { dynamicImport } from 'vite-plugin-dynamic-import'
// Optional - compatible with webpack require.contex
import viteRequireContext from '@originjs/vite-plugin-require-context'

export default defineConfig({
  plugins: [
    createVuePlugin({
      jsx: true,})./** * webpack project require */
    vitePluginCommonjs(),
    /** * compatible with import('@views/' + path)
     */
    dynamicImport(),
    /** * require. Context in webpack project */
    viteRequireContext(),
    /** * Uses the public/index.html template */ by default
    htmlTemplate(),
  ],
  resolve: {
    alias: [{find: The '@'.replacement: path.join(__dirname, 'src')}, {find: ~ / / * * // ^ ~? = \ /), replacement: path.join(__dirname, 'node_modules')}, {find: / * ~ * // ^ ~? ! / / /), replacement: path.join(__dirname, 'node_modules/')},].// Same as extensions in Webpack
    extensions: ['.vue'.'.js'.'.jsx'.'.ts'.'.tsx'.'.json'],},define: {
    / / with webpack DefinePlugin
    'process.env': process.env,
  }
})

Copy the code

run

  • Add the packge.json scripts command

    {
      "scripts": {
    + "vite": "export NODE_ENV=development; vite"}}Copy the code
  1. npm run vite

πŸŽ‰ Boom shakalaka!!!