diff --git a/examples/webpack-plugin/WebpackPlugin.js b/examples/webpack-plugin/WebpackPlugin.js deleted file mode 100644 index 84a9a9d6f8..0000000000 --- a/examples/webpack-plugin/WebpackPlugin.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Just a normal Webpack plugin - */ -export class WebpackPlugin { - constructor(log) { - this.log = log - } - - apply(compiler) { - if (!this.log) return - - this.log({ - message: this.constructor.name, - suffix: 'applied!', - }) - } -} diff --git a/examples/webpack-plugin/WebpackPlugin.ts b/examples/webpack-plugin/WebpackPlugin.ts new file mode 100644 index 0000000000..bbfe25dedb --- /dev/null +++ b/examples/webpack-plugin/WebpackPlugin.ts @@ -0,0 +1,11 @@ +/** + * Just a normal Webpack plugin + */ +export class WebpackPlugin { + constructor(public log: (...args: any[]) => void) { + } + + apply(compiler: any) { + this.log?.(this.constructor.name, 'applied!') + } +} diff --git a/examples/webpack-plugin/bud.config.ts b/examples/webpack-plugin/bud.config.ts index 1e9cf3d1e8..540604b122 100644 --- a/examples/webpack-plugin/bud.config.ts +++ b/examples/webpack-plugin/bud.config.ts @@ -1,6 +1,6 @@ import {bud} from '@roots/bud' -import {WebpackPlugin} from './WebpackPlugin.js' +const {WebpackPlugin} = require('./WebpackPlugin.js') /** * This is an example of how to use a Webpack plugin @@ -20,7 +20,7 @@ bud .use({ label: `inline-plugin`, apply: async () => { - console.log({message: 'inline-plugin', suffix: 'applied!'}) + console.log('inline-plugin applied!') await bud.fs.write( bud.path(`@storage`, `inline-plugin-output`), `inline-plugin-test-success`, @@ -35,13 +35,13 @@ bud { label: `array-plugin-1`, apply() { - console.log({message: 'array-plugin-1', suffix: 'applied!'}) + console.log('array-plugin-1 applied!') }, }, new (class { public label = `array-plugin-2` public apply() { - console.log({message: 'array-plugin-2', suffix: 'applied!'}) + console.log('array-plugin-2 applied!') } })(), ]) diff --git a/sources/@roots/bud-support/package.json b/sources/@roots/bud-support/package.json index 2f09aef5ac..8b36befc32 100644 --- a/sources/@roots/bud-support/package.json +++ b/sources/@roots/bud-support/package.json @@ -55,6 +55,7 @@ "./axios": "./lib/axios/index.js", "./chalk": "./lib/chalk/index.js", "./chokidar": "./lib/chokidar/index.js", + "./cjs-shim": "./lib/cjs-shim/index.js", "./clean-stack": "./lib/clean-stack/index.js", "./clean-webpack-plugin": "./lib/clean-webpack-plugin/index.js", "./clipanion": "./lib/clipanion/index.js", @@ -132,6 +133,9 @@ "chokidar": [ "./lib/chokidar/index.d.ts" ], + "cjs-shim": [ + "./lib/cjs-shim/index.d.ts" + ], "clean-stack": [ "./lib/clean-stack/index.d.ts" ], diff --git a/sources/@roots/bud-support/src/cjs-shim/index.ts b/sources/@roots/bud-support/src/cjs-shim/index.ts new file mode 100644 index 0000000000..9ec48442e7 --- /dev/null +++ b/sources/@roots/bud-support/src/cjs-shim/index.ts @@ -0,0 +1,7 @@ +import {createRequire} from 'node:module' +import path from 'node:path' +import url from 'node:url' + +globalThis.require = createRequire(import.meta.url) +globalThis.__filename = url.fileURLToPath(import.meta.url) +globalThis.__dirname = path.dirname(__filename) diff --git a/sources/@roots/bud-support/src/utilities/files.ts b/sources/@roots/bud-support/src/utilities/files.ts index 44bbbef3b9..19c1e3eaae 100644 --- a/sources/@roots/bud-support/src/utilities/files.ts +++ b/sources/@roots/bud-support/src/utilities/files.ts @@ -2,6 +2,7 @@ import type * as esbuild from '@roots/bud-support/esbuild' import type {Filesystem} from '@roots/bud-support/filesystem' import type {InspectResult} from '@roots/filesystem/filesystem' +import {builtinModules} from 'node:module' import {join, parse} from 'node:path' import * as filesystem from '@roots/bud-support/filesystem' @@ -163,17 +164,16 @@ async function getFileInfo(filename: string) { paths.storage, `configs`, file.base, - `${current.sha1}${file.ext.replace(/(.*)ts$/, `$1js`)}`, + `${current.sha1}${file.ext.replace(/(.*)ts$/, `$1mjs`)}`, ) const modified = current.sha1 !== file.sha1 const uncompiled = !(await fs.exists(outfile)) if (modified || uncompiled) { - if (uncompiled) - logger.log(`${file.name} has not been compiled yet`) - else if (modified) - logger.log(`${file.name} has been modified since last compiled`) + uncompiled && logger.log(file.name, `has not been compiled yet`) + modified && + logger.log(file.name, `has been modified since last compiled`) // Update the hash to the current state file.sha1 = current.sha1 @@ -186,7 +186,7 @@ async function getFileInfo(filename: string) { const tmpfile = join( paths.basedir, file.dir, - `.${file.name}${file.ext.replace(/(.*)ts$/, `$1js`)}`, + `.${file.name}${file.ext.replace(/(.*)ts$/, `$1mjs`)}`, ) logger.scope(`fs`).info(`copying ${outfile} to tmpfile:`, tmpfile) @@ -232,7 +232,11 @@ async function esTransform({ await transformer.build({ absWorkingDir: paths.basedir, allowOverwrite: true, + bundle: true, entryPoints: [file.path], + external: [`@roots/bud`, `node:*`, ...builtinModules], + format: `esm`, + inject: [`@roots/bud-support/cjs-shim`], outfile, platform: `node`, }) @@ -252,8 +256,10 @@ function getFileType( function getFileTarget(file: {name?: string}) { if (file.name?.includes(`production`) || file.name?.includes(`prod`)) return `production` + if (file.name?.includes(`development`) || file.name?.includes(`dev`)) return `development` + return `base` } diff --git a/sources/@roots/bud-tailwindcss/src/extension/index.ts b/sources/@roots/bud-tailwindcss/src/extension/index.ts index 3f75216b89..4510d6ee9e 100644 --- a/sources/@roots/bud-tailwindcss/src/extension/index.ts +++ b/sources/@roots/bud-tailwindcss/src/extension/index.ts @@ -44,7 +44,6 @@ class BudTailwindCss extends BudTailwindOptionsApi { ) .setPlugin(`tailwindcss`, [ await this.resolve(`tailwindcss`, import.meta.url), - this.configPath ?? this.config, ]) .setPluginOptions(`env`, { features: { @@ -70,18 +69,19 @@ class BudTailwindCss extends BudTailwindOptionsApi { }) } + /** + * {@link Extension.configAfter} + */ @bind public override async configAfter(bud: Bud) { - this.setResolvedConfig(this.resolveConfig()) - const options = this.configPath ?? (this.config as any) - bud.postcss.setPluginOptions(`tailwindcss`, options) + bud.postcss.setPluginOptions(`tailwindcss`, this.resolveConfig()) } /** * {@link Extension.register} */ @bind - public override async register(_bud: Bud) { + public override async register() { await this.sourceConfig() } } diff --git a/sources/@roots/bud-tailwindcss/src/extension/options.ts b/sources/@roots/bud-tailwindcss/src/extension/options.ts index 4653d42dc1..5639be0e46 100644 --- a/sources/@roots/bud-tailwindcss/src/extension/options.ts +++ b/sources/@roots/bud-tailwindcss/src/extension/options.ts @@ -94,6 +94,7 @@ class BudTailwindOptionsApi >(...params: [K, VK] | [V]) { if (params.length === 1) { const [value] = params + this.setConfig((config = {content: []}) => ({ ...config, theme: { @@ -101,7 +102,7 @@ class BudTailwindOptionsApi extend: {...(config?.theme?.extend ?? {}), ...value}, }, })) - this.resolveConfig() + return this } @@ -114,8 +115,6 @@ class BudTailwindOptionsApi }, })) - this.resolveConfig() - return this } @@ -140,17 +139,23 @@ class BudTailwindOptionsApi */ @bind public generateImports( - imports: Array<`${keyof ThemeConfig & string}`> | boolean = true, + imports: + | Array< + | `${keyof ThemeConfig & string}.${string}` + | `${keyof ThemeConfig & string}` + > + | boolean = true, ) { - this.resolveConfig() - const makeStaticModule = (key: `${keyof ThemeConfig & string}`) => { + this.logger.log(`@tailwind/${key}`, `generating module`) + const value = get(this.resolvedConfig.theme, key) - this.logger.log(`@tailwind/${key}: generating module`) return `export default ${JSON.stringify(value)};` } this.app.hooks.action(`config.after`, async bud => { + this.resolveConfig() + const importableKeys = Array.isArray(imports) ? imports : Object.keys(this.resolvedConfig.theme) @@ -209,10 +214,11 @@ class BudTailwindOptionsApi * Resolve a tailwind config value */ @bind - public resolveThemeValue( - key: K, - extendedOnly?: boolean, - ): Config[K] { + public resolveThemeValue< + K extends + | `${keyof ThemeConfig & string}.${string}` + | `${keyof ThemeConfig & string}`, + >(key: K, extendedOnly?: boolean): Config[K] { if (extendedOnly) { if (!this.config?.theme?.extend) throw new Error( @@ -229,7 +235,8 @@ class BudTailwindOptionsApi return isFunction(value) ? value(pluginUtils) : value } - const value = this.resolvedConfig?.theme?.[key] + const value = get(this.resolveConfig()?.theme, key) + if (!value) { throw new Error( `@roots/bud-tailwindcss: ${key} is not a valid tailwind theme key.`, @@ -251,7 +258,6 @@ class BudTailwindOptionsApi ...config, plugins, })) - this.resolveConfig() return this } @@ -271,7 +277,6 @@ class BudTailwindOptionsApi ...config, theme: {...(config.theme ?? {}), ...value}, })) - this.resolveConfig() return this } @@ -280,7 +285,6 @@ class BudTailwindOptionsApi ...config, theme: {...(config.theme ?? {}), [key]: value}, })) - this.resolveConfig() return this } diff --git a/tests/integration/webpack-plugin.test.ts b/tests/integration/webpack-plugin.test.ts index d2767cdf83..445f5db46a 100644 --- a/tests/integration/webpack-plugin.test.ts +++ b/tests/integration/webpack-plugin.test.ts @@ -40,9 +40,10 @@ describe(`examples/webpack-plugin`, () => { ).toEqual(`inline-plugin-test-success`) expect(await fs.read(test.getPath(`build.stdout.log`))) - .toMatch(`{ message: 'WebpackPlugin', suffix: 'applied!' } -{ message: 'inline-plugin', suffix: 'applied!' } -{ message: 'array-plugin-1', suffix: 'applied!' } -{ message: 'array-plugin-2', suffix: 'applied!' }`) + .toMatch(`\ +WebpackPlugin applied! +inline-plugin applied! +array-plugin-1 applied! +array-plugin-2 applied!`) }) })