一、Vite 高级应用的 HMR 热更新、glob-import 批量导入、预编译、Vite SSR 应用及 SSR 静态站点导出
Vite
中的热更新,通过 Vite
命令行生成的项目默认都开启了热更新,同时 Vite
中的热更新是根据不同框架去实现的。HMR API
,对于 import.meta.hot
,通过 vite build
去 build
代码之后,在 build
的 production
的 bundle
里面是没有 hot
代码的,对于发布线上的代码是没有 hot
的需要,需要判断。对于 import.meta.hot.accept
,vite
推了一个热更新,它就会接收到这个热更新,main.js
,代码如下:
import './style.css'
function render ( ) {
document. querySelector ( '#app' ) . innerHTML = `
<h1>Hello Vite!</h1>
<a href="https://vitejs.dev/guide/features.html" target="_blank">Documentation</a>
` ;
}
render ( ) ;
if ( import . meta. hot) {
import . meta. hot. accept ( ( newModule ) => {
newModule. render ( ) ;
} ) ;
}
Vite
中的 glob-import
,具备批量导入的功能,可以使用 import.meta.glob
。如果直接编译引入,可以使用 globEager
。比如批量导入 glob
目录下的所有文件,代码如下:
const globModules = import . meta. glob ( './glob/*' ) ;
Object. entries ( globModules) . forEach ( ( [ k, v] ) => {
v ( ) . then ( m => console. log ( k + ':' + m. default) ) ;
} ) ;
Vite
中的预编译,会将非 ES Module
的文件编译成 ES Module
,这是因为 Vite
依赖浏览器原生的 ES Module
加载方式。在 vite.config.js
中,optimizeDeps
可以指明项目中哪些文件需要预编译,哪些不需要预编译,include
是需要预编译,exclude
是不需要预编译。预编译也会将零散的文件打包到一起,代码如下:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig ( {
plugins : [ react ( ) ] ,
optimizeDeps : {
include : [ 'react' ] ,
exclude : [ 'lodash-es' ]
}
} )
在 nodejs
服务中集成 vite
,vite
提供的这些方法也是异步的,代码如下:
import ReactDOMServer from 'react-dom/server' ;
import { StaticRouter } from 'react-router-dom' ;
import { App } from './App' ;
export function render ( url, context ) {
return ReactDOMServer. renderToString (
< StaticRouter location= { url} context= { context} >
< App / >
< / StaticRouter>
) ;
}
const express = require ( 'express' ) ;
const app = express ( ) ;
const { createServer : createViteServer } = require ( 'vite' ) ;
createViteServer ( {
server : {
middlewareMode : 'ssr' ,
}
} ) . then ( ( vite ) => {
app. use ( vite. middlewares) ;
app. get ( '*' , async ( req, res ) => {
let template = fs. readFileSync ( 'index.html' , 'utf-8' ) ;
template = await vite. transformIndexHtml ( req. url, template) ;
const { render } = await vite. ssrLoadModule ( '/src/server-entry.jsx' ) ;
const html = await render ( req. url) ;
const responseHtml = template. replace ( '<!--APP_HTML--!>' , 'html' ) ;
res. set ( 'content-type' , 'text/html' ) . send ( responseHtml) ;
} ) ;
app. listen ( 4000 ) ;
} ) ;
Node
集成 build
的 vite ssr
,代码如下:
const express = require ( 'express' ) ;
const fs = require ( 'fs' ) ;
const app = express ( ) ;
const template = fs. readFileSync ( 'dist/client/index.html' ) ;
const isProd = process. env. NODE_ENV === 'production' ;
app. get ( '*' , async ( req, res ) => {
const render = require ( './dist/server/server-entry' ) . render;
const context = { } ;
const html = await render ( req. url, context) ;
if ( context. url) {
res. redirect ( 301 , context. url) ;
return ;
}
const responseHtml = template. replace ( '<!--APP_HTML--!>' , 'html' ) ;
res. set ( 'content-type' , 'text/html' ) . send ( responseHtml) ;
} ) ;
app. listen ( 4000 ) ;
修改 package.json
中的 scripts
下的 build
,如下:
"scripts" : {
"dev" : "vite" ,
"build" : "npm run build:client && npm run build:server" ,
"build:client" : "vite build --outDir dist/client" ,
"build:server" : "vite build --outDir dist/server --ssr src/server-entry.jsx" ,
"preview" : "vite preview" ,
"start" : "NODE_ENV=devlopment node server.js"
} ,
Vite
中 SSR
静态站点导出,prerender.js
,代码如下:
const path = require ( 'path' ) ;
const fs = require ( 'fs' ) ;
const template = fs. readFileSync ( 'dist/client/index.html' ) ;
const render = require ( './dist/server/server-entry' ) . render;
const routesToRender = path. readdirSync ( 'src/pages' ) . map ( ( file ) => {
return file. replace ( '.jsx' , '' ) . toLowerCase ( ) ;
} ) ;
for ( const route of routesToRender) {
const context = { } ;
const html = render ( route, context)
const responseHtml = template. replace ( '<!--APP_HTML--!>' , 'html' ) ;
const filePath = ` dist/static/ ${ route} .html ` ;
fs. writeFileSync ( filePath, responseHtml) ;
console. log ( ` prerender ${ filePath} ` ) ;
}