Skip to content

Commit ddf413e

Browse files
committed
♻️ Combine plugins
1 parent 053d0f3 commit ddf413e

File tree

3 files changed

+125
-150
lines changed

3 files changed

+125
-150
lines changed

resources/scripts/build/wordpress.js

Lines changed: 0 additions & 123 deletions
This file was deleted.
Lines changed: 124 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import type { Plugin } from 'vite'
22
import resolveConfig from 'tailwindcss/resolveConfig'
3+
import {
4+
defaultRequestToExternal,
5+
defaultRequestToHandle,
6+
} from '@wordpress/dependency-extraction-webpack-plugin/lib/util'
37

8+
// Theme JSON Types
49
interface ThemeJsonColor {
510
name: string
611
slug: string
@@ -78,33 +83,51 @@ interface ThemeJsonOptions {
7883
title?: string
7984
}
8085

81-
/**
82-
* Converts a slug or kebab-case string into Title Case.
83-
*
84-
* Examples:
85-
* - Input: "primary-color" -> Output: "Primary Color"
86-
* - Input: "text-lg" -> Output: "Text Lg"
87-
*/
86+
// WordPress Plugin Helper Functions
87+
function extractNamedImports(imports: string): string[] {
88+
return imports
89+
.match(/{([^}]+)}/)[1]
90+
.split(',')
91+
.map((s) => s.trim())
92+
}
93+
94+
function handleNamedReplacement(namedImports: string[], external: string[]): string {
95+
return namedImports
96+
.map((imports) => {
97+
const [name, alias = name] = imports
98+
.split(' as ')
99+
.map((script) => script.trim())
100+
101+
return `const ${alias} = ${external.join('.')}.${name};`
102+
})
103+
.join('\n')
104+
}
105+
106+
function handleReplacements(imports: string, external: string[]): string {
107+
if (imports.includes('{')) {
108+
const namedImports = extractNamedImports(imports)
109+
return handleNamedReplacement(namedImports, external)
110+
}
111+
112+
if (imports.includes('* as')) {
113+
const alias = imports.match(/\*\s+as\s+(\w+)/)[1]
114+
return `const ${alias} = ${external.join('.')};`
115+
}
116+
117+
const name = imports.trim()
118+
return `const ${name} = ${external.join('.')};`
119+
}
120+
121+
// Theme JSON Helper Functions
88122
const toTitleCase = (slug: string): string =>
89123
slug
90124
.split('-')
91125
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
92126
.join(' ')
93127

94-
/**
95-
* Checks if a value is a valid CSS color.
96-
*
97-
* Examples:
98-
* - Input: "#ff0000" -> true
99-
* - Input: "rgb(255, 255, 0)" -> true
100-
* - Input: "invalid-color" -> false
101-
*/
102128
const isValidColor = (value: any): boolean =>
103129
typeof value === 'string' && (value.startsWith('#') || value.startsWith('rgb'))
104130

105-
/**
106-
* Recursively processes a Tailwind color object into an array of ThemeJsonColor.
107-
*/
108131
const processColors = (
109132
obj: Record<string, any>,
110133
prefix = ''
@@ -129,7 +152,7 @@ const processColors = (
129152
return palette
130153
}
131154

132-
// Convert Tailwind values to Theme JSON structures
155+
// Conversion Functions
133156
const convertTailwindColorsToThemeJson = (config: any): ThemeJsonColor[] =>
134157
processColors(resolveConfig(config).theme.colors)
135158

@@ -139,7 +162,7 @@ const convertTailwindFontFamiliesToThemeJson = (
139162
Object.entries(resolveConfig(config).theme.fontFamily).map(([name, value]) => ({
140163
name: toTitleCase(name),
141164
slug: name.toLowerCase(),
142-
fontFamily: Array.isArray(value) ? value.join(', ') : value,
165+
fontFamily: Array.isArray(value) ? value.join(', ') : String(value),
143166
}))
144167

145168
const convertTailwindFontSizesToThemeJson = (
@@ -151,14 +174,91 @@ const convertTailwindFontSizesToThemeJson = (
151174
size: Array.isArray(value) ? value[0] : value,
152175
}))
153176

154-
// Merge default settings with user options
155177
const mergeSettings = (
156178
defaults: ThemeJsonSettings,
157179
overrides: ThemeJsonSettings | undefined
158180
): ThemeJsonSettings => ({ ...defaults, ...overrides })
159181

160-
// Plugin definition
161-
export default function wordPressThemeJson(options: ThemeJsonOptions = {}): Plugin {
182+
// Plugin Exports
183+
export function wordpressPlugin(): Plugin {
184+
const dependencies = new Set<string>()
185+
186+
return {
187+
name: 'wordpress-plugin',
188+
enforce: 'post',
189+
transform(code: string, id: string) {
190+
if (!id.endsWith('.js')) {
191+
return
192+
}
193+
194+
const imports = [
195+
...(code.match(/^import .+ from ['"]@wordpress\/[^'"]+['"]/gm) || []),
196+
...(code.match(/^import ['"]@wordpress\/[^'"]+['"]/gm) || []),
197+
]
198+
199+
imports.forEach((statement) => {
200+
const match =
201+
statement.match(/^import (.+) from ['"]@wordpress\/([^'"]+)['"]/) ||
202+
statement.match(/^import ['"]@wordpress\/([^'"]+)['"]/)
203+
204+
if (!match) {
205+
return
206+
}
207+
208+
const [, imports, pkg] = match
209+
210+
if (!pkg) {
211+
return
212+
}
213+
214+
const external = defaultRequestToExternal(`@wordpress/${pkg}`)
215+
const handle = defaultRequestToHandle(`@wordpress/${pkg}`)
216+
217+
if (external && handle) {
218+
dependencies.add(handle)
219+
220+
const replacement = imports
221+
? handleReplacements(imports, external)
222+
: `const ${pkg.replace(/-([a-z])/g, (_, letter) =>
223+
letter.toUpperCase()
224+
)} = ${external.join('.')};`
225+
226+
code = code.replace(statement, replacement)
227+
}
228+
})
229+
230+
return { code, map: null }
231+
},
232+
generateBundle() {
233+
this.emitFile({
234+
type: 'asset',
235+
fileName: 'editor.deps.json',
236+
source: JSON.stringify([...dependencies]),
237+
})
238+
},
239+
}
240+
}
241+
242+
export function wordpressRollupPlugin(): Plugin {
243+
return {
244+
name: 'wordpress-rollup-plugin',
245+
options(opts: any) {
246+
opts.external = (id: string) => id.startsWith('@wordpress/')
247+
opts.output = opts.output || {}
248+
opts.output.globals = (id: string) => {
249+
if (id.startsWith('@wordpress/')) {
250+
const packageName = id.replace('@wordpress/', '')
251+
return `wp.${packageName.replace(/-([a-z])/g, (_, letter) =>
252+
letter.toUpperCase()
253+
)}`
254+
}
255+
}
256+
return opts
257+
},
258+
}
259+
}
260+
261+
export function wordPressThemeJson(options: ThemeJsonOptions = {}): Plugin {
162262
const defaultSettings: ThemeJsonSettings = {
163263
background: { backgroundImage: true },
164264
color: {
@@ -182,7 +282,6 @@ export default function wordPressThemeJson(options: ThemeJsonOptions = {}): Plug
182282

183283
return {
184284
name: 'wordpress-theme-json',
185-
186285
generateBundle() {
187286
const themeJson: Record<string, any> = {
188287
__generated__: '⚠️ This file is generated. Do not edit.',
@@ -216,7 +315,6 @@ export default function wordPressThemeJson(options: ThemeJsonOptions = {}): Plug
216315
}
217316
}
218317

219-
// Append optional fields
220318
if (options.customTemplates) themeJson.customTemplates = options.customTemplates
221319
if (options.patterns) themeJson.patterns = options.patterns
222320
if (options.styles) themeJson.styles = options.styles
@@ -230,4 +328,4 @@ export default function wordPressThemeJson(options: ThemeJsonOptions = {}): Plug
230328
})
231329
},
232330
}
233-
}
331+
}

vite.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import laravel from 'laravel-vite-plugin'
33
import {
44
wordpressPlugin,
55
wordpressRollupPlugin,
6+
wordPressThemeJson,
67
} from './resources/scripts/build/wordpress'
7-
import wordPressThemeJson from './resources/scripts/build/theme-json'
88
import tailwindConfig from './tailwind.config.js'
99

1010
export default defineConfig({

0 commit comments

Comments
 (0)