mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-29 22:02:46 -07:00
Create babel plugin to handle lazy loading (#4)
* feat: create babel plugin to handle lazy loading * fix: update typescript CI to also run the tests in the pipelines * doc: update lazy loading component inline documentation * fix: typescript pipeline * fix: update CI typescript test command * fix: prevent duplicate pipelines on PR * feat: create separate vite plugin package * chore: refined lazy fn package * test: add test to lazy fn plugin * feat: update version to v0.1.5
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import type { Plugin } from 'vite'
|
||||
import * as babel from '@babel/core'
|
||||
import type { PluginItem } from '@babel/core'
|
||||
|
||||
import * as t from '@babel/types'
|
||||
|
||||
import type {
|
||||
Identifier,
|
||||
ImportDeclaration,
|
||||
CallExpression,
|
||||
ArrowFunctionExpression,
|
||||
StringLiteral,
|
||||
} from '@babel/types'
|
||||
|
||||
/**
|
||||
* This plugin just removes the `lazy` imported function from any tuono import
|
||||
*/
|
||||
const RemoveTuonoLazyImport: PluginItem = {
|
||||
name: 'remove-tuono-lazy-import-plugin',
|
||||
visitor: {
|
||||
ImportSpecifier: (path) => {
|
||||
if ((path.node.imported as Identifier).name === 'lazy') {
|
||||
if (
|
||||
(path.parentPath.node as ImportDeclaration).source.value === 'tuono'
|
||||
) {
|
||||
path.remove()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Import { lazy } from 'react'
|
||||
*/
|
||||
const ImportReactLazy: PluginItem = {
|
||||
name: 'import-react-lazy-plugin',
|
||||
visitor: {
|
||||
Program: (path: any) => {
|
||||
let isReactImported = false
|
||||
|
||||
path.node.body.forEach((val: any) => {
|
||||
if (val.type === 'ImportDeclaration' && val.source.value === 'react') {
|
||||
isReactImported = true
|
||||
// TODO: Handle also here case of already imported react
|
||||
// Right now works just for the main routes file
|
||||
}
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!isReactImported) {
|
||||
const importDeclaration = t.importDeclaration(
|
||||
[t.importSpecifier(t.identifier('lazy'), t.identifier('lazy'))],
|
||||
t.stringLiteral('react'),
|
||||
)
|
||||
path.unshiftContainer('body', importDeclaration)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* For the server side we need to statically import the lazy loaded components
|
||||
*/
|
||||
const TurnLazyToStaticImport: PluginItem = {
|
||||
name: 'turn-lazy-to-static-import-plugin',
|
||||
visitor: {
|
||||
VariableDeclaration: (path) => {
|
||||
path.node.declarations.forEach((el) => {
|
||||
const init = el.init as CallExpression
|
||||
if ((init.callee as Identifier).name === 'lazy') {
|
||||
const importName = (el.id as Identifier).name
|
||||
const importPath = (
|
||||
(
|
||||
(init.arguments[0] as ArrowFunctionExpression)
|
||||
.body as CallExpression
|
||||
).arguments[0] as StringLiteral
|
||||
).value
|
||||
|
||||
if (importName && importPath) {
|
||||
const importDeclaration = t.importDeclaration(
|
||||
[t.importDefaultSpecifier(t.identifier(importName))],
|
||||
t.stringLiteral(importPath),
|
||||
)
|
||||
|
||||
path.replaceWith(importDeclaration)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export function LazyLoadingPlugin(): Plugin {
|
||||
return {
|
||||
name: 'vite-plugin-tuono-lazy-loading',
|
||||
enforce: 'pre',
|
||||
transform(code, _id, opts): string | undefined | null {
|
||||
if (code.includes('lazy') && code.includes('tuono')) {
|
||||
const res = babel.transformSync(code, {
|
||||
plugins: [
|
||||
['@babel/plugin-syntax-jsx', {}],
|
||||
['@babel/plugin-syntax-typescript', { isTSX: true }],
|
||||
[RemoveTuonoLazyImport],
|
||||
[!opts?.ssr ? ImportReactLazy : []],
|
||||
[opts?.ssr ? TurnLazyToStaticImport : []],
|
||||
],
|
||||
sourceMaps: true,
|
||||
})
|
||||
|
||||
return res?.code
|
||||
}
|
||||
return code
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user