Prevent dynamic fn replacement when not imported by tuono (#57)

* fix: prevent dynamic fn replacement when not imported by tuono

* feat: update version to v0.10.3

* Revert "fix(deps): update dependency zustand to v5 (#55)"

This reverts commit d7a086dfb1.

* Revert "fix(deps): update dependency zustand to v4.5.5 (#37)"

This reverts commit b36dc0b897.

* Revert "chore(deps): update dependency @testing-library/react to v16 (#38)"

This reverts commit 1a1b62698c.

* Revert "chore(deps): update dependency @tanstack/config to ^0.13.0 (#32)"

This reverts commit 6c7cc62371.

* revert pnpm update

* Revert "chore(deps): update dependency vitest to v2 (#45)"

This reverts commit c5b5f6aefe.

* Revert "chore(deps): update dependency node to v20.18.0 (#33)"

This reverts commit 588326cc57.
This commit is contained in:
Valerio Ageno
2024-10-16 20:41:33 +02:00
committed by GitHub
parent d7a086dfb1
commit 002733cd99
16 changed files with 121 additions and 73 deletions
+1 -1
View File
@@ -1 +1 @@
20.18.0 v20.10.0
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tuono" name = "tuono"
version = "0.10.2" version = "0.10.3"
edition = "2021" edition = "2021"
authors = ["V. Ageno <valerioageno@yahoo.it>"] authors = ["V. Ageno <valerioageno@yahoo.it>"]
description = "The react/rust fullstack framework" description = "The react/rust fullstack framework"
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tuono_lib" name = "tuono_lib"
version = "0.10.2" version = "0.10.3"
edition = "2021" edition = "2021"
authors = ["V. Ageno <valerioageno@yahoo.it>"] authors = ["V. Ageno <valerioageno@yahoo.it>"]
description = "The react/rust fullstack framework" description = "The react/rust fullstack framework"
@@ -33,7 +33,7 @@ either = "1.13.0"
tower-http = {version = "0.6.0", features = ["fs"]} tower-http = {version = "0.6.0", features = ["fs"]}
colored = "2.1.0" colored = "2.1.0"
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.10.2"} tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.10.3"}
# Match the same version used by axum # Match the same version used by axum
tokio-tungstenite = "0.24.0" tokio-tungstenite = "0.24.0"
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] } futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "tuono_lib_macros" name = "tuono_lib_macros"
version = "0.10.2" version = "0.10.3"
edition = "2021" edition = "2021"
description = "The react/rust fullstack framework" description = "The react/rust fullstack framework"
keywords = [ "react", "typescript", "fullstack", "web", "ssr"] keywords = [ "react", "typescript", "fullstack", "web", "ssr"]
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "workspace", "name": "workspace",
"packageManager": "pnpm@9.12.1", "packageManager": "pnpm@9.1.1",
"scripts": { "scripts": {
"dev": "turbo watch dev", "dev": "turbo watch dev",
"build": "turbo build --filter tuono", "build": "turbo build --filter tuono",
@@ -20,7 +20,7 @@
"author": "Valerio Ageno", "author": "Valerio Ageno",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@tanstack/config": "^0.13.0", "@tanstack/config": "^0.7.0",
"@types/node": "^20.12.7", "@types/node": "^20.12.7",
"@types/react": "^18.3.1", "@types/react": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/eslint-plugin": "^8.0.0",
@@ -35,7 +35,7 @@
"prettier": "^3.2.4", "prettier": "^3.2.4",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"vite": "^5.2.11", "vite": "^5.2.11",
"vitest": "^2.0.0" "vitest": "^1.5.2"
}, },
"dependencies": { "dependencies": {
"turbo": "^2.0.12" "turbo": "^2.0.12"
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "tuono-fs-router-vite-plugin", "name": "tuono-fs-router-vite-plugin",
"version": "0.10.2", "version": "0.10.3",
"description": "Plugin for the tuono's file system router. Tuono is the react/rust fullstack framework", "description": "Plugin for the tuono's file system router. Tuono is the react/rust fullstack framework",
"scripts": { "scripts": {
"dev": "vite build --watch", "dev": "vite build --watch",
@@ -44,8 +44,8 @@
"vite": "^5.2.11" "vite": "^5.2.11"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/config": "^0.13.0", "@tanstack/config": "^0.7.11",
"@types/babel__core": "^7.20.5", "@types/babel__core": "^7.20.5",
"vitest": "^2.0.0" "vitest": "^1.5.2"
} }
} }
@@ -1,11 +1,11 @@
import { defineConfig, mergeConfig } from 'vitest/config' import { defineConfig, mergeConfig } from 'vitest/config'
import { tanstackViteConfig } from '@tanstack/config/vite' import { tanstackBuildConfig } from '@tanstack/config/build'
const config = defineConfig({}) const config = defineConfig({})
export default mergeConfig( export default mergeConfig(
config, config,
tanstackViteConfig({ tanstackBuildConfig({
entry: './src/index.ts', entry: './src/index.ts',
srcDir: './src', srcDir: './src',
}), }),
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "tuono-lazy-fn-vite-plugin", "name": "tuono-lazy-fn-vite-plugin",
"version": "0.10.2", "version": "0.10.3",
"description": "Plugin for the tuono's lazy fn. Tuono is the react/rust fullstack framework", "description": "Plugin for the tuono's lazy fn. Tuono is the react/rust fullstack framework",
"scripts": { "scripts": {
"dev": "vite build --watch", "dev": "vite build --watch",
@@ -43,9 +43,9 @@
"vite": "^5.2.11" "vite": "^5.2.11"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/config": "^0.13.0", "@tanstack/config": "^0.7.11",
"@types/babel__core": "^7.20.5", "@types/babel__core": "^7.20.5",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"vitest": "^2.0.0" "vitest": "^1.5.2"
} }
} }
+37 -35
View File
@@ -1,6 +1,7 @@
import type { Plugin } from 'vite' import type { Plugin } from 'vite'
import * as babel from '@babel/core' import * as babel from '@babel/core'
import type { PluginItem } from '@babel/core' import type { PluginItem } from '@babel/core'
import { isTuonoDynamicFnImported } from './utils'
import { import {
TUONO_MAIN_PACKAGE, TUONO_MAIN_PACKAGE,
@@ -12,7 +13,6 @@ import * as t from '@babel/types'
import type { import type {
Identifier, Identifier,
ImportDeclaration,
CallExpression, CallExpression,
ArrowFunctionExpression, ArrowFunctionExpression,
StringLiteral, StringLiteral,
@@ -26,13 +26,8 @@ const RemoveTuonoLazyImport: PluginItem = {
name: 'remove-tuono-lazy-import-plugin', name: 'remove-tuono-lazy-import-plugin',
visitor: { visitor: {
ImportSpecifier: (path) => { ImportSpecifier: (path) => {
if ((path.node.imported as Identifier).name === TUONO_DYNAMIC_FN_ID) { if (isTuonoDynamicFnImported(path)) {
if ( path.remove()
(path.parentPath.node as ImportDeclaration).source.value ===
TUONO_MAIN_PACKAGE
) {
path.remove()
}
} }
}, },
}, },
@@ -46,18 +41,39 @@ const ReplaceTuonoLazyImport: PluginItem = {
name: 'remove-tuono-lazy-import-plugin', name: 'remove-tuono-lazy-import-plugin',
visitor: { visitor: {
ImportSpecifier: (path) => { ImportSpecifier: (path) => {
if ((path.node.imported as Identifier).name === TUONO_DYNAMIC_FN_ID) { if (isTuonoDynamicFnImported(path)) {
if ( ;(path.node.imported as Identifier).name = TUONO_LAZY_FN_ID
(path.parentPath.node as ImportDeclaration).source.value ===
TUONO_MAIN_PACKAGE
) {
;(path.node.imported as Identifier).name = TUONO_LAZY_FN_ID
}
} }
}, },
}, },
} }
const turnLazyIntoStatic = {
VariableDeclaration: (path: babel.NodePath<t.VariableDeclaration>): void => {
path.node.declarations.forEach((el) => {
const init = el.init as CallExpression
if ((init.callee as Identifier).name === TUONO_DYNAMIC_FN_ID) {
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)
}
}
})
},
}
/** /**
* [SERVER build] * [SERVER build]
* This plugin statically imports the lazy loaded components * This plugin statically imports the lazy loaded components
@@ -65,27 +81,13 @@ const ReplaceTuonoLazyImport: PluginItem = {
const TurnLazyIntoStaticImport: PluginItem = { const TurnLazyIntoStaticImport: PluginItem = {
name: 'turn-lazy-into-static-import-plugin', name: 'turn-lazy-into-static-import-plugin',
visitor: { visitor: {
VariableDeclaration: (path) => { Program: (path) => {
path.node.declarations.forEach((el) => { path.traverse({
const init = el.init as CallExpression ImportSpecifier: (subPath) => {
if ((init.callee as Identifier).name === TUONO_DYNAMIC_FN_ID) { if (isTuonoDynamicFnImported(subPath)) {
const importName = (el.id as Identifier).name path.traverse(turnLazyIntoStatic)
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)
} }
} },
}) })
}, },
}, },
+19
View File
@@ -0,0 +1,19 @@
import { TUONO_MAIN_PACKAGE, TUONO_DYNAMIC_FN_ID } from './constants'
import type * as t from '@babel/types'
import type { Identifier, ImportDeclaration } from '@babel/types'
export const isTuonoDynamicFnImported = (
path: babel.NodePath<t.ImportSpecifier>,
): boolean => {
if ((path.node.imported as Identifier).name !== TUONO_DYNAMIC_FN_ID) {
return false
}
if (
(path.parentPath.node as ImportDeclaration).source.value !==
TUONO_MAIN_PACKAGE
) {
return false
}
return true
}
@@ -10,24 +10,51 @@ const PokemonspokemonImport = dynamic(
) )
` `
const CLIENT_RESULT = `import { createRoute, lazyLoadComponent as dynamic } from 'tuono'; const NON_DYNAMIC_SOURCE = `
const IndexImport = dynamic(() => import('./../src/routes/index')); import { createRoute } from 'tuono'
const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[pokemon]'));` import {dynamic} from 'external-lib'
const SERVER_RESULT = `import { createRoute } from 'tuono'; const IndexImport = dynamic(() => import('./../src/routes/index'))
import IndexImport from "./../src/routes/index"; const PokemonspokemonImport = dynamic(
import PokemonspokemonImport from "./../src/routes/pokemons/[pokemon]";` () => import('./../src/routes/pokemons/[pokemon]'),
)
`
describe('Transpile tuono source', () => { describe('Transpile tuono source', () => {
it('Into the client bundle', () => { it('Into the client bundle', () => {
const bundle = LazyLoadingPlugin().transform?.(SOURCE_CODE, 'id') const bundle = LazyLoadingPlugin().transform?.(SOURCE_CODE, 'id')
expect(bundle).toBe(CLIENT_RESULT) expect(bundle)
.toBe(`import { createRoute, lazyLoadComponent as dynamic } from 'tuono';
const IndexImport = dynamic(() => import('./../src/routes/index'));
const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[pokemon]'));`)
}) })
it('Into the server bundle', () => { it('Into the server bundle', () => {
const bundle = LazyLoadingPlugin().transform?.(SOURCE_CODE, 'id', { const bundle = LazyLoadingPlugin().transform?.(SOURCE_CODE, 'id', {
ssr: true, ssr: true,
}) })
expect(bundle).toBe(SERVER_RESULT) expect(bundle).toBe(`import { createRoute } from 'tuono';
import IndexImport from "./../src/routes/index";
import PokemonspokemonImport from "./../src/routes/pokemons/[pokemon]";`)
})
})
describe('Non tuono dynamic function', () => {
it('Into the client bundle', () => {
const bundle = LazyLoadingPlugin().transform?.(NON_DYNAMIC_SOURCE, 'id')
expect(bundle).toBe(`import { createRoute } from 'tuono';
import { dynamic } from 'external-lib';
const IndexImport = dynamic(() => import('./../src/routes/index'));
const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[pokemon]'));`)
})
it('Into the server bundle', () => {
const bundle = LazyLoadingPlugin().transform?.(NON_DYNAMIC_SOURCE, 'id', {
ssr: true,
})
expect(bundle).toBe(`import { createRoute } from 'tuono';
import { dynamic } from 'external-lib';
const IndexImport = dynamic(() => import('./../src/routes/index'));
const PokemonspokemonImport = dynamic(() => import('./../src/routes/pokemons/[pokemon]'));`)
}) })
}) })
+2 -2
View File
@@ -1,11 +1,11 @@
import { defineConfig, mergeConfig } from 'vitest/config' import { defineConfig, mergeConfig } from 'vitest/config'
import { tanstackViteConfig } from '@tanstack/config/vite' import { tanstackBuildConfig } from '@tanstack/config/build'
const config = defineConfig({}) const config = defineConfig({})
export default mergeConfig( export default mergeConfig(
config, config,
tanstackViteConfig({ tanstackBuildConfig({
entry: './src/index.ts', entry: './src/index.ts',
srcDir: './src', srcDir: './src',
}), }),
+6 -6
View File
@@ -1,6 +1,6 @@
{ {
"name": "tuono-router", "name": "tuono-router",
"version": "0.10.2", "version": "0.10.3",
"description": "React routing component for the framework tuono. Tuono is the react/rust fullstack framework", "description": "React routing component for the framework tuono. Tuono is the react/rust fullstack framework",
"scripts": { "scripts": {
"dev": "vite build --watch", "dev": "vite build --watch",
@@ -44,14 +44,14 @@
"dependencies": { "dependencies": {
"react-intersection-observer": "^9.13.0", "react-intersection-observer": "^9.13.0",
"vite": "^5.2.11", "vite": "^5.2.11",
"zustand": "5.0.0" "zustand": "4.4.7"
}, },
"devDependencies": { "devDependencies": {
"@tanstack/config": "^0.13.0", "@tanstack/config": "^0.7.11",
"@testing-library/jest-dom": "^6.4.5", "@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^16.0.0", "@testing-library/react": "^15.0.7",
"jsdom": "^25.0.0", "jsdom": "^24.0.0",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"vitest": "^2.0.0" "vitest": "^1.5.2"
} }
} }
+2 -2
View File
@@ -1,7 +1,7 @@
/// <reference types="vitest" /> /// <reference types="vitest" />
/// <reference types="vite/client" /> /// <reference types="vite/client" />
import { defineConfig, mergeConfig } from 'vitest/config' import { defineConfig, mergeConfig } from 'vitest/config'
import { tanstackViteConfig } from '@tanstack/config/vite' import { tanstackBuildConfig } from '@tanstack/config/build'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
const config = defineConfig({ const config = defineConfig({
@@ -16,7 +16,7 @@ const config = defineConfig({
export default mergeConfig( export default mergeConfig(
config, config,
tanstackViteConfig({ tanstackBuildConfig({
entry: './src/index.ts', entry: './src/index.ts',
srcDir: './src', srcDir: './src',
}), }),
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "tuono", "name": "tuono",
"version": "0.10.2", "version": "0.10.3",
"description": "The react/rust fullstack framework", "description": "The react/rust fullstack framework",
"scripts": { "scripts": {
"dev": "vite build --watch", "dev": "vite build --watch",
@@ -99,7 +99,7 @@
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"vitest": "^2.0.0" "vitest": "^1.5.2"
}, },
"sideEffects": false, "sideEffects": false,
"keywords": [ "keywords": [
+2 -2
View File
@@ -1,7 +1,7 @@
/// <reference types="vitest" /> /// <reference types="vitest" />
/// <reference types="vite/client" /> /// <reference types="vite/client" />
import { defineConfig, mergeConfig } from 'vitest/config' import { defineConfig, mergeConfig } from 'vitest/config'
import { tanstackViteConfig } from '@tanstack/config/vite' import { tanstackBuildConfig } from '@tanstack/config/build'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
const config = defineConfig({ const config = defineConfig({
@@ -10,7 +10,7 @@ const config = defineConfig({
export default mergeConfig( export default mergeConfig(
config, config,
tanstackViteConfig({ tanstackBuildConfig({
entry: [ entry: [
'./src/index.ts', './src/index.ts',
'./src/build/index.ts', './src/build/index.ts',