Skip to content

Commit 0b7d5b2

Browse files
committed
Support Turbopack
1 parent bfa898a commit 0b7d5b2

File tree

5 files changed

+126
-32
lines changed

5 files changed

+126
-32
lines changed

apps/landing/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"scripts": {
77
"dev": "node ./script.js && next dev",
88
"search": "node ./script.js",
9-
"build": "node ./script.js && next build --webpack",
9+
"build": "node ./script.js && next build",
1010
"start": "npx serve ./out",
1111
"lint": "eslint"
1212
},
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { existsSync } from 'node:fs'
2+
import { dirname, join } from 'node:path'
3+
4+
export function findRoot(dir: string) {
5+
let root = dir
6+
let prev = null
7+
const collectecd: string[] = []
8+
while (prev === null || root !== prev) {
9+
if (existsSync(join(root, 'package.json')) && !collectecd.includes(root)) {
10+
collectecd.push(root)
11+
}
12+
prev = root
13+
root = dirname(root)
14+
}
15+
if (collectecd.length > 0) {
16+
return collectecd.pop() ?? process.cwd()
17+
}
18+
return process.cwd()
19+
}

packages/next-plugin/src/plugin.ts

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
22
import { join, relative, resolve } from 'node:path'
33

4+
import { exportClassMap, exportFileMap, exportSheet } from '@devup-ui/wasm'
45
import {
56
DevupUIWebpackPlugin,
67
type DevupUIWebpackPluginOptions,
78
} from '@devup-ui/webpack-plugin'
89
import { type NextConfig } from 'next'
910

11+
import { preload } from './preload'
12+
1013
type DevupUiNextPluginOptions = Omit<
1114
Partial<DevupUIWebpackPluginOptions>,
1215
'watch'
@@ -26,9 +29,9 @@ export function DevupUI(
2629
process.env.TURBOPACK === '1' || process.env.TURBOPACK === 'auto'
2730
// turbopack is now stable, TURBOPACK is set to auto without any flags
2831
if (isTurbo) {
29-
if (process.env.NODE_ENV === 'production') {
30-
throw new Error('Devup UI is not supported in production with turbopack')
31-
}
32+
// if (process.env.NODE_ENV === 'production') {
33+
// throw new Error('Devup UI is not supported in production with turbopack')
34+
// }
3235

3336
config ??= {}
3437
config.turbopack ??= {}
@@ -39,6 +42,7 @@ export function DevupUI(
3942
cssDir = resolve(distDir, 'devup-ui'),
4043
singleCss = false,
4144
devupFile = 'devup.json',
45+
include = [],
4246
} = options
4347

4448
const sheetFile = join(distDir, 'sheet.json')
@@ -54,35 +58,56 @@ export function DevupUI(
5458
recursive: true,
5559
})
5660
if (!existsSync(gitignoreFile)) writeFileSync(gitignoreFile, '*')
61+
const theme = existsSync(devupFile)
62+
? JSON.parse(readFileSync(devupFile, 'utf-8'))?.['theme']
63+
: undefined
5764
// disable turbo parallel
58-
process.env.TURBOPACK_DEBUG_JS = '*'
59-
process.env.NODE_OPTIONS ??= ''
60-
process.env.NODE_OPTIONS += ' --inspect-brk'
65+
const excludeRegex = new RegExp(
66+
`node_modules(?!.*(${['@devup-ui', ...include]
67+
.join('|')
68+
.replaceAll('/', '[\\/\\\\_]')})([\\/\\\\.]|$))`,
69+
)
70+
71+
if (process.env.NODE_ENV !== 'production') {
72+
process.env.TURBOPACK_DEBUG_JS = '*'
73+
process.env.NODE_OPTIONS ??= ''
74+
process.env.NODE_OPTIONS += ' --inspect-brk'
75+
} else {
76+
preload(excludeRegex, libPackage, singleCss, theme, cssDir)
77+
}
6178

6279
const rules: NonNullable<typeof config.turbopack.rules> = {
6380
[`./${relative(process.cwd(), cssDir).replaceAll('\\', '/')}/*.css`]: [
6481
{
6582
loader: '@devup-ui/webpack-plugin/css-loader',
6683
},
6784
],
68-
'*.{tsx,ts,js,mjs}': [
69-
{
70-
loader: '@devup-ui/webpack-plugin/loader',
71-
options: {
72-
package: libPackage,
73-
cssDir,
74-
sheetFile,
75-
classMapFile,
76-
fileMapFile,
77-
watch: process.env.NODE_ENV === 'development',
78-
singleCss,
79-
// for turbopack, load theme is required on loader
80-
theme: existsSync(devupFile)
81-
? JSON.parse(readFileSync(devupFile, 'utf-8'))?.['theme']
82-
: undefined,
85+
'*.{tsx,ts,js,mjs}': {
86+
loaders: [
87+
{
88+
loader: '@devup-ui/webpack-plugin/loader',
89+
options: {
90+
package: libPackage,
91+
cssDir,
92+
sheetFile,
93+
classMapFile,
94+
fileMapFile,
95+
defaultSheet: JSON.parse(exportSheet()),
96+
defaultClassMap: JSON.parse(exportClassMap()),
97+
defaultFileMap: JSON.parse(exportFileMap()),
98+
watch: process.env.NODE_ENV === 'development',
99+
singleCss,
100+
// for turbopack, load theme is required on loader
101+
theme,
102+
},
103+
},
104+
],
105+
condition: {
106+
not: {
107+
path: excludeRegex,
83108
},
84109
},
85-
],
110+
},
86111
}
87112
Object.assign(config.turbopack.rules, rules)
88113
return config
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { globSync, readFileSync, writeFileSync } from 'node:fs'
2+
import { basename, join, relative } from 'node:path'
3+
4+
import { codeExtract, registerTheme } from '@devup-ui/wasm'
5+
6+
import { findRoot } from './find-root'
7+
8+
export function preload(
9+
excludeRegex: RegExp,
10+
libPackage: string,
11+
singleCss: boolean,
12+
theme: object,
13+
cssDir: string,
14+
) {
15+
const projectRoot = findRoot(process.cwd())
16+
17+
const collected = globSync(['**/*.tsx', '**/*.ts', '**/*.js', '**/*.mjs'], {
18+
cwd: projectRoot,
19+
exclude: (filename) => excludeRegex.test(filename),
20+
})
21+
registerTheme(theme)
22+
for (const file of collected) {
23+
const filePath = relative(process.cwd(), join(projectRoot, file))
24+
const { cssFile, css } = codeExtract(
25+
filePath,
26+
readFileSync(filePath, 'utf-8'),
27+
libPackage,
28+
cssDir,
29+
singleCss,
30+
false,
31+
true,
32+
)
33+
34+
if (cssFile) {
35+
writeFileSync(join(cssDir, basename(cssFile!)), css ?? '', 'utf-8')
36+
}
37+
}
38+
}

packages/webpack-plugin/src/loader.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import {
77
exportFileMap,
88
exportSheet,
99
getCss,
10+
importClassMap,
11+
importFileMap,
12+
importSheet,
1013
registerTheme,
1114
} from '@devup-ui/wasm'
1215
import type { RawLoaderDefinitionFunction } from 'webpack'
@@ -19,7 +22,11 @@ export interface DevupUILoaderOptions {
1922
fileMapFile: string
2023
watch: boolean
2124
singleCss: boolean
25+
// turbo
2226
theme?: object
27+
defaultSheet: object
28+
defaultClassMap: object
29+
defaultFileMap: object
2330
}
2431
let init = false
2532

@@ -34,32 +41,37 @@ const devupUILoader: RawLoaderDefinitionFunction<DevupUILoaderOptions> =
3441
fileMapFile,
3542
singleCss,
3643
theme,
44+
defaultClassMap,
45+
defaultFileMap,
46+
defaultSheet,
3747
} = this.getOptions()
3848
const callback = this.async()
3949
const id = this.resourcePath
40-
if (theme && !init) {
50+
if (!init) {
4151
init = true
42-
registerTheme(theme)
52+
if (defaultFileMap) importFileMap(defaultFileMap)
53+
if (defaultClassMap) importClassMap(defaultClassMap)
54+
if (defaultSheet) importSheet(defaultSheet)
55+
if (theme) registerTheme(theme)
4356
}
4457

4558
try {
46-
let rel = relative(dirname(this.resourcePath), cssDir).replaceAll(
47-
'\\',
48-
'/',
49-
)
59+
let relCssDir = relative(dirname(id), cssDir).replaceAll('\\', '/')
60+
61+
const relativePath = relative(process.cwd(), id)
5062

51-
if (!rel.startsWith('./')) rel = `./${rel}`
63+
if (!relCssDir.startsWith('./')) relCssDir = `./${relCssDir}`
5264
const {
5365
code,
5466
css = '',
5567
map,
5668
cssFile,
5769
updatedBaseStyle,
5870
} = codeExtract(
59-
id,
71+
relativePath,
6072
source.toString(),
6173
libPackage,
62-
rel,
74+
relCssDir,
6375
singleCss,
6476
false,
6577
true,

0 commit comments

Comments
 (0)