diff --git a/config/vitest/alias.ts b/config/vitest/alias.ts index 11c4007798..6fc6f64b68 100644 --- a/config/vitest/alias.ts +++ b/config/vitest/alias.ts @@ -12,6 +12,7 @@ export default { ), '@roots/bud-cache': path(`sources/@roots/bud-cache/src`), '@roots/bud-compiler': path(`sources/@roots/bud-compiler/src`), + '@roots/bud-compress': path(`sources/@roots/bud-compress/src`), '@roots/bud-dashboard': path(`sources/@roots/bud-dashboard/src`), '@roots/bud-extensions': path(`sources/@roots/bud-extensions/src`), '@roots/bud-framework': path(`sources/@roots/bud-framework/src`), diff --git a/examples/sage/package.json b/examples/sage/package.json index 51d1aa0443..a5d778ae38 100644 --- a/examples/sage/package.json +++ b/examples/sage/package.json @@ -5,7 +5,6 @@ "type": "module", "devDependencies": { "@roots/bud": "workspace:*", - "@roots/bud-prettier": "workspace:*", "@roots/bud-tailwindcss": "workspace:*", "@roots/sage": "workspace:*" } diff --git a/examples/sage/resources/scripts/app.js b/examples/sage/resources/scripts/app.js index 68fcc884b7..60fcc861d3 100644 --- a/examples/sage/resources/scripts/app.js +++ b/examples/sage/resources/scripts/app.js @@ -7,7 +7,5 @@ const init = () => init() -if (import.meta.webpackHot) { - if (import.meta.webpackHot) - import.meta.webpackHot.accept('./components/main.js', init) -} +if (import.meta.webpackHot) + import.meta.webpackHot.accept('./components/main.js', init) diff --git a/sources/@roots/bud-babel/src/extension.ts b/sources/@roots/bud-babel/src/extension.ts index ce55996f15..7376413e28 100644 --- a/sources/@roots/bud-babel/src/extension.ts +++ b/sources/@roots/bud-babel/src/extension.ts @@ -89,7 +89,9 @@ export default class BabelExtension extends Extension { plugins: Object.values(this.plugins), presets: Object.values(this.presets), root: this.root, - targets: this.app.context.manifest?.browserslist ?? `defaults`, + targets: this.app.context.manifest?.browserslist ?? { + esmodules: true, + }, } } diff --git a/sources/@roots/bud-compress/package.json b/sources/@roots/bud-compress/package.json index f6a3f09c08..29ae8717cc 100644 --- a/sources/@roots/bud-compress/package.json +++ b/sources/@roots/bud-compress/package.json @@ -50,18 +50,10 @@ ], "type": "module", "exports": { - ".": { - "import": "./lib/index.js", - "default": "./lib/index.js" - }, - "./brotli": { - "import": "./lib/brotli.js", - "default": "./lib/brotli.js" - }, - "./gzip": { - "import": "./lib/gzip.js", - "default": "./lib/gzip.js" - } + ".": "./lib/index.js", + "./brotli": "./lib/brotli.js", + "./gzip": "./lib/gzip.js", + "./extension": "./lib/extension.js" }, "typesVersions": { "*": { @@ -73,6 +65,9 @@ ], "gzip": [ "./lib/gzip.d.ts" + ], + "extension": [ + "./lib/extension.d.ts" ] } }, diff --git a/sources/@roots/bud-compress/src/brotli.ts b/sources/@roots/bud-compress/src/brotli.ts index 6429acbee0..89cf3136f1 100644 --- a/sources/@roots/bud-compress/src/brotli.ts +++ b/sources/@roots/bud-compress/src/brotli.ts @@ -1,3 +1,7 @@ +import type {Options} from '@roots/bud-compress' + +import zlib from 'node:zlib' + import {type Bud} from '@roots/bud-framework' import {Extension} from '@roots/bud-framework/extension' import { @@ -10,8 +14,6 @@ import { import {deprecated} from '@roots/bud-support/decorators' import Plugin from 'compression-webpack-plugin' -import type {Options} from './extension.js' - /** * Brotli compression configuration */ @@ -19,12 +21,16 @@ import type {Options} from './extension.js' @plugin(Plugin) @options({ algorithm: `brotliCompress`, - compressionOptions: {level: 11}, + compressionOptions: { + params: { + [zlib.constants.BROTLI_PARAM_QUALITY]: 11, + }, + }, deleteOriginalAssets: false, - filename: `[name].br[query]`, + filename: `[path][name].gz[query]`, minRatio: 0.8, - test: /\.js$|\.css$|\.html$|\.htm$/, - threshold: 10240, + test: /\.(js|css|html?|svg)$/, + threshold: 0, }) @disabled export default class BudBrotli extends Extension { diff --git a/sources/@roots/bud-compress/src/extension.ts b/sources/@roots/bud-compress/src/extension.ts index cf2ccfc747..2b5f2d68b5 100644 --- a/sources/@roots/bud-compress/src/extension.ts +++ b/sources/@roots/bud-compress/src/extension.ts @@ -1,41 +1,29 @@ -import type {Bud} from '@roots/bud-framework' -import type {Modules} from '@roots/bud-framework' +import type {Bud, Modules} from '@roots/bud-framework' import {Extension} from '@roots/bud-framework/extension' import { bind, dependsOn, + expose, label, } from '@roots/bud-framework/extension/decorators' -/** - * Compression options - */ -export interface Options { - algorithm: string - compressionOptions: Record - deleteOriginalAssets: boolean - filename: string - minRatio: number - test: RegExp - threshold: number -} - /** * Compress static assets * * @example * ```js - * bud.compress.gzip + * bud.compress?.gzip * .enable() * .set('filename', '[name].gz[query]') * - * bud.compress.brotli + * bud.compress?.brotli * .enable() * .set('filename', '[name].br[query]') * ``` */ @label(`@roots/bud-compress`) +@expose(`compress`) @dependsOn([`@roots/bud-compress/brotli`, `@roots/bud-compress/gzip`]) export default class BudCompressionExtension extends Extension { public declare brotli: Modules[`@roots/bud-compress/brotli`] diff --git a/sources/@roots/bud-compress/src/gzip.ts b/sources/@roots/bud-compress/src/gzip.ts index 170dc27689..664c083542 100644 --- a/sources/@roots/bud-compress/src/gzip.ts +++ b/sources/@roots/bud-compress/src/gzip.ts @@ -1,3 +1,4 @@ +import type {Options} from '@roots/bud-compress' import type {Bud} from '@roots/bud-framework' import {Extension} from '@roots/bud-framework/extension' @@ -11,21 +12,19 @@ import { import {deprecated} from '@roots/bud-support/decorators' import Plugin from 'compression-webpack-plugin' -import type {Options} from './extension.js' - /** * Gzip compression configuration */ @label(`@roots/bud-compress/gzip`) @plugin(Plugin) @options({ - algorithm: `brotliCompress`, + algorithm: `gzip`, compressionOptions: {level: 11}, deleteOriginalAssets: false, - filename: `[name].br[query]`, + filename: `[path][name].gz[query]`, minRatio: 0.8, - test: /\.js$|\.css$|\.html$|\.htm$/, - threshold: 10240, + test: /\.(js|css|html?|svg)$/, + threshold: 0, }) @disabled export default class BudGzip extends Extension { diff --git a/sources/@roots/bud-compress/src/index.ts b/sources/@roots/bud-compress/src/index.ts index 5baf7db596..c5f4e43ffd 100644 --- a/sources/@roots/bud-compress/src/index.ts +++ b/sources/@roots/bud-compress/src/index.ts @@ -8,10 +8,46 @@ * @see https://github.com/roots/bud */ -import type {Options} from './extension.js' +import type BudBrotli from '@roots/bud-compress/brotli' +import type BudCompress from '@roots/bud-compress/extension' +import type BudGzip from '@roots/bud-compress/gzip' +import type {PublicExtensionApi} from '@roots/bud-framework/extension' import BudCompressionExtension from './extension.js' -import './types' + +/** + * Compression options + */ +interface Options { + algorithm: string + compressionOptions: Record + deleteOriginalAssets: boolean + filename: string + minRatio: number + test: RegExp + threshold: number +} + +interface PublicBrotliAPI extends PublicExtensionApi {} +interface PublicGzipAPI extends PublicExtensionApi {} +interface PublicCompressAPI extends PublicExtensionApi { + brotli: PublicBrotliAPI + gzip: PublicGzipAPI +} + +declare module '@roots/bud-framework' { + interface Bud { + brotli: PublicBrotliAPI + compress: PublicCompressAPI + gzip: PublicGzipAPI + } + + interface Modules { + '@roots/bud-compress': PublicCompressAPI + '@roots/bud-compress/brotli': PublicBrotliAPI + '@roots/bud-compress/gzip': PublicGzipAPI + } +} export default BudCompressionExtension export type {Options} diff --git a/sources/@roots/bud-compress/src/types.ts b/sources/@roots/bud-compress/src/types.ts deleted file mode 100644 index a646cc59b6..0000000000 --- a/sources/@roots/bud-compress/src/types.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type {PublicExtensionApi} from '@roots/bud-framework/extension' - -import type BudBrotli from './brotli.js' -import type BudCompress from './extension.js' -import type BudGzip from './gzip.js' - -interface PublicBrotliAPI extends PublicExtensionApi {} -interface PublicGzipAPI extends PublicExtensionApi {} -interface PublicCompressAPI extends PublicExtensionApi { - brotli: PublicBrotliAPI - gzip: PublicGzipAPI -} - -declare module '@roots/bud-framework' { - interface Bud { - brotli: PublicBrotliAPI - compress: PublicCompressAPI - gzip: PublicGzipAPI - } - - interface Modules { - '@roots/bud-compress': PublicCompressAPI - '@roots/bud-compress/brotli': PublicBrotliAPI - '@roots/bud-compress/gzip': PublicGzipAPI - } -} diff --git a/sources/@roots/bud-compress/src/brotli.test.ts b/sources/@roots/bud-compress/test/brotli.test.ts similarity index 76% rename from sources/@roots/bud-compress/src/brotli.test.ts rename to sources/@roots/bud-compress/test/brotli.test.ts index 954b5adeb0..435b238047 100644 --- a/sources/@roots/bud-compress/src/brotli.test.ts +++ b/sources/@roots/bud-compress/test/brotli.test.ts @@ -1,27 +1,25 @@ import {Bud, factory} from '@repo/test-kit' +import BudCompress from '@roots/bud-compress' +import BudBrotli from '@roots/bud-compress/brotli' +import BudGzip from '@roots/bud-compress/gzip' import {beforeEach, describe, expect, it, vitest} from 'vitest' -import BudBrotli from './brotli.js' -import Brotli from './brotli.js' -import Compression from './extension.js' -import BudGzip from './gzip.js' - describe(`@roots/bud-compress`, () => { let bud: Bud - let compress: Compression - let brotli: Brotli + let compress: BudCompress + let brotli: BudBrotli beforeEach(async () => { bud = await factory() - brotli = new Brotli(bud) - compress = new Compression(bud) + brotli = new BudBrotli(bud) + compress = new BudCompress(bud) await bud.extensions.add([BudBrotli, BudGzip]) await compress.register(bud) }) it(`should be constructable`, () => { - expect(brotli).toBeInstanceOf(Brotli) + expect(brotli).toBeInstanceOf(BudBrotli) }) it(`should call enabled when config is called`, () => { diff --git a/sources/@roots/bud-compress/src/extension.test.ts b/sources/@roots/bud-compress/test/extension.test.ts similarity index 74% rename from sources/@roots/bud-compress/src/extension.test.ts rename to sources/@roots/bud-compress/test/extension.test.ts index ebd124c9c6..38dce813bc 100644 --- a/sources/@roots/bud-compress/src/extension.test.ts +++ b/sources/@roots/bud-compress/test/extension.test.ts @@ -1,23 +1,22 @@ import {Bud, factory} from '@repo/test-kit' +import BudCompress from '@roots/bud-compress' +import BudBrotli from '@roots/bud-compress/brotli' +import BudGzip from '@roots/bud-compress/gzip' import {beforeEach, describe, expect, it, test} from 'vitest' -import BudBrotli from './brotli.js' -import BudGzip from './gzip.js' -import Extension from './index.js' - describe(`@roots/bud-compress`, () => { let bud: Bud - let compress: Extension + let compress: BudCompress beforeEach(async () => { bud = await factory() - compress = new Extension(bud) + compress = new BudCompress(bud) await bud.extensions.add([BudBrotli, BudGzip]) await compress.register(bud) }) it(`should be constructable`, () => { - expect(Extension).toBeInstanceOf(Function) + expect(BudCompress).toBeInstanceOf(Function) }) it(`should have gzip interface`, () => { diff --git a/sources/@roots/bud-compress/src/gzip.test.ts b/sources/@roots/bud-compress/test/gzip.test.ts similarity index 76% rename from sources/@roots/bud-compress/src/gzip.test.ts rename to sources/@roots/bud-compress/test/gzip.test.ts index 45e2b74d64..c80fb38453 100644 --- a/sources/@roots/bud-compress/src/gzip.test.ts +++ b/sources/@roots/bud-compress/test/gzip.test.ts @@ -1,25 +1,24 @@ import {Bud, factory} from '@repo/test-kit' +import BudCompress from '@roots/bud-compress' +import BudGzip from '@roots/bud-compress/gzip' import {beforeEach, describe, expect, it, vitest} from 'vitest' -import Compression from './extension.js' -import Gzip from './gzip.js' - describe(`@roots/bud-compress`, () => { let bud: Bud - let compress: Compression - let gzip: Gzip + let compress: BudCompress + let gzip: BudGzip beforeEach(async () => { bud = await factory() - gzip = new Gzip(bud) - compress = new Compression(bud) + gzip = new BudGzip(bud) + compress = new BudCompress(bud) - await bud.extensions.add([Gzip]) + await bud.extensions.add([BudGzip]) await compress.register(bud) }) it(`should be constructable`, () => { - expect(gzip).toBeInstanceOf(Gzip) + expect(gzip).toBeInstanceOf(BudGzip) }) it(`should call enabled when config is called`, () => { diff --git a/sources/@roots/bud-framework/src/notifier.ts b/sources/@roots/bud-framework/src/notifier.ts index 7dfa33cbdd..d114fceda4 100644 --- a/sources/@roots/bud-framework/src/notifier.ts +++ b/sources/@roots/bud-framework/src/notifier.ts @@ -10,10 +10,15 @@ import {fileURLToPath} from 'node:url' import isEmpty from '@roots/bud-support/lodash/isEmpty' import isString from '@roots/bud-support/lodash/isString' -import logger from '@roots/bud-support/logger' +import isUndefined from '@roots/bud-support/lodash/isUndefined' import {open, openEditor} from '@roots/bud-support/open' -import chalk from 'chalk' +/** + * Path to roots-notifier binary + * + * @description + * Used to open notifications on macOS + */ const notifierPath = resolve( dirname(fileURLToPath(import.meta.url)), `..`, // bud-framework @@ -25,17 +30,20 @@ const notifierPath = resolve( `roots-notifier`, ) +/** + * Notification + */ interface Notification extends NodeNotification { - actions?: string | string[] | undefined - closeLabel?: string | undefined - contentImage?: string | undefined - dropdownLabel?: string | undefined + actions?: string | string[] + closeLabel?: string + contentImage?: string + dropdownLabel?: string group?: string - open?: string | undefined | URL - reply?: boolean | undefined - sound?: boolean | string | undefined - subtitle?: string | undefined - timeout?: false | number | undefined + open?: string | URL + reply?: boolean + sound?: boolean | string + subtitle?: string + timeout?: false | number } /** @@ -58,12 +66,7 @@ export class Notifier { * * @see {@link https://github.com/roots/bud/issues/2041} */ - public browserOpened = false - - /** - * Editor to open on error - */ - public editor: boolean | string + public declare browserOpened: boolean /** * Node-notifier notification center instance @@ -83,6 +86,7 @@ export class Notifier { this.notify = this.notify.bind(this) this.openBrowser = this.openBrowser.bind(this) this.openEditor = this.openEditor.bind(this) + this.browserOpened = false } /** @@ -92,6 +96,29 @@ export class Notifier { return this._app() } + /** + * Editor to open on error + */ + public get editor(): boolean | string { + if (!isUndefined(this.app.context.editor)) { + return this.app.context.editor + } + + if (this.app.env.has(`BUD_EDITOR`)) { + return this.app.env.get(`BUD_EDITOR`) + } + + if (this.app.env.has(`VISUAL`)) { + return this.app.env.get(`VISUAL`) + } + + if (this.app.env.has(`EDITOR`)) { + return this.app.env.get(`EDITOR`) + } + + return false + } + /** * Make notifier */ @@ -106,16 +133,6 @@ export class Notifier { ? new NotificationCenter() : new NotificationCenter({customPath: notifierPath}) } - - if (typeof bud.context.editor === `string`) { - this.editor = bud.context.editor - } else if (bud.env.has(`BUD_EDITOR`)) { - this.editor = bud.env.get(`BUD_EDITOR`) - } else if (bud.env.has(`VISUAL`)) { - this.editor = bud.env.get(`VISUAL`) - } else if (bud.env.has(`EDITOR`)) { - this.editor = bud.env.get(`EDITOR`) - } } /** @@ -176,40 +193,21 @@ export class Notifier { if (!this.openEditorEnabled) return if (!input || isEmpty(input)) return - logger.scope(`notifier`, `openEditor`).log(`input received`, input) - const files = Array.isArray(input) ? input : [input] - files.map(file => - logger.scope(`notifier`).log(`opening`, file, `in`, this.editor), - ) - - if (typeof this.editor === `string`) + if (isString(this.editor)) return openEditor(files, {editor: this.editor}) - else return openEditor(files) + + return openEditor(files) } /** - * True if editor opening is enabled + * If --editor flag is passed */ public get openEditorEnabled(): boolean { - const enabled = - this.app.context.editor === true || // if true, fall back to default behavior - typeof this.app.context.editor === `string` // if string, opens in that editor - - if (enabled && !this.editor) { - logger - .scope(`notifier`, `editor check`) - .warn( - chalk.magenta(`\n\nEditor not defined.`), - `\n\nYou should set an editor using any of the following ENV variables:\n`, - `\n - ${chalk.blue(`BUD_EDITOR`)} (bud specific; preferred)`, - `\n - ${chalk.blue(`VISUAL`)} (unix standard)`, - `\n - ${chalk.blue(`EDITOR`)} (unix standard)`, - `\n\nAlternatively, use the ${chalk.blue(`--editor`)} flag.`, - ) - } - - return enabled + return ( + !isUndefined(this.app.context.editor) && + this.app.context.editor !== false + ) } } diff --git a/sources/@roots/bud-server/src/inject.ts b/sources/@roots/bud-server/src/inject.ts index eeddd58cd9..a71a7bb9f9 100644 --- a/sources/@roots/bud-server/src/inject.ts +++ b/sources/@roots/bud-server/src/inject.ts @@ -14,11 +14,6 @@ export const inject = async ( (entrypoints, [name, entry]) => { name = name ?? `main` - app.server.logger.info( - `injecting scripts ${name}`, - ...injection.map(fn => fn(app)).filter(Boolean), - ) - return { ...entrypoints, [name]: { diff --git a/yarn.lock b/yarn.lock index 79ab901c5e..b84b06c8d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4706,7 +4706,6 @@ __metadata: resolution: "@examples/sage@workspace:examples/sage" dependencies: "@roots/bud": "workspace:*" - "@roots/bud-prettier": "workspace:*" "@roots/bud-tailwindcss": "workspace:*" "@roots/sage": "workspace:*" languageName: unknown @@ -8175,7 +8174,7 @@ __metadata: languageName: unknown linkType: soft -"@roots/bud-prettier@workspace:*, @roots/bud-prettier@workspace:sources/@roots/bud-prettier": +"@roots/bud-prettier@workspace:sources/@roots/bud-prettier": version: 0.0.0-use.local resolution: "@roots/bud-prettier@workspace:sources/@roots/bud-prettier" dependencies: