diff --git a/examples/vue-legacy/package.json b/examples/vue-legacy/package.json index 717fd64d34..ccb086871c 100644 --- a/examples/vue-legacy/package.json +++ b/examples/vue-legacy/package.json @@ -5,12 +5,10 @@ "extends @roots/browserslist-config/current" ], "devDependencies": { - "@roots/browserslist-config": "latest", "@roots/bud": "latest", "@roots/bud-vue": "latest" }, "dependencies": { - "lodash": "4.17.21", "vue": "^2.6.14", "vue-template-compiler": "^2.6.14", "vue-loader": "^15.9.4" diff --git a/sources/@repo/docs/content/blog/6.4.0.mdx b/sources/@repo/docs/content/blog/6.4.0.mdx index adc5c1d9db..febd0cb865 100644 --- a/sources/@repo/docs/content/blog/6.4.0.mdx +++ b/sources/@repo/docs/content/blog/6.4.0.mdx @@ -12,7 +12,17 @@ tags: [release] -## bud.assets +## new: bud.sh + +bud.sh is a new config function that allows for executing arbitrary shell commands. It is a wrapper around the [execa](https://github.com/sindresorhus/execa) package. + +It's async and returns the `ExecaChildProcess` object. It will pipe the process stdout/stderr to the console automatically. + +```js title=bud.config.mjs +await bud.sh('echo "hello world"') +``` + +## improved: bud.assets You can now specify copy options to apply to all copy patterns as a second parameter. diff --git a/sources/@repo/docs/content/docs/bud.define.mdx b/sources/@repo/docs/content/docs/bud.define.mdx index 10a466c2f4..eee311edbf 100644 --- a/sources/@repo/docs/content/docs/bud.define.mdx +++ b/sources/@repo/docs/content/docs/bud.define.mdx @@ -3,7 +3,6 @@ id: bud.define title: bud.define description: Replace variables in your application code and templates at compile time. sidebar_label: bud.define -image: 'https://bud.js.org/img/share/docs/bud.define.png' --- import Tabs from '@theme/Tabs' @@ -36,11 +35,3 @@ Replacements will also be made when compiling [html templates](/docs/bud.templat ``` - -## Signature - -```ts title='@roots/bud-api/types/repository/index.d.ts' -interface Define { - (this: Bud, values: Webpack.DefinePlugin['definitions']): Bud -} -``` diff --git a/sources/@repo/docs/content/docs/bud.devtool.mdx b/sources/@repo/docs/content/docs/bud.devtool.mdx index d0806d5cab..60a18e3b38 100644 --- a/sources/@repo/docs/content/docs/bud.devtool.mdx +++ b/sources/@repo/docs/content/docs/bud.devtool.mdx @@ -37,13 +37,3 @@ Enable sourcemaps only in development (see [bud.when](bud.when) for extra clarit ```js title='bud.config.js' bud.when(bud.isDevelopment, bud => bud.devtool()) ``` - -## Signature - -```ts title='@roots/bud-api/types/repository/index.d.ts' -namespace Repository { - interface Devtool { - (this: Bud, devtool?: Webpack.Configuration['devtool']): Bud - } -} -``` diff --git a/sources/@repo/docs/content/docs/bud.entry.mdx b/sources/@repo/docs/content/docs/bud.entry.mdx index 04039180ff..1e77c6be91 100644 --- a/sources/@repo/docs/content/docs/bud.entry.mdx +++ b/sources/@repo/docs/content/docs/bud.entry.mdx @@ -37,8 +37,6 @@ bud.entry({ Bud supports the new Webpack 5 `dependOn` syntax for explicitly defining entrypoint dependencies. -Example react application: - ```ts title='bud.config.js' bud.entry({ react: ['react', 'react-dom'], @@ -58,51 +56,3 @@ You can specify assets using [fast-glob syntax](https://git.io/JkGbw). - `**` matches any number of characters, including `/`, as long as it's the only thing in a path part - `{}` allows for a comma-separated list of "or" expressions - `!` at the beginning of a pattern will negate the match - -## Specifying entrypoints with hooks - -You may also specify entrypoints using the `build/entry` [hook](/docs/bud.hooks/). - -```js title='bud.config.js' -bud.hooks.on('build.entry', { - app: ['app.js', 'app.css'], - admin: ['admin.js', 'admin.css'], -}) -``` - -This will completely override whatever is defined. If you want to augment the existing definition you can do so with spread syntax. - -```js title='bud.config.js' -bud.hooks.on('build.entry', entrypoints => ({ - ...entrypoints, - app: ['app.js', 'app.css'], - admin: ['admin.js', 'admin.css'], -}) -``` - -## Signature - -```ts title='@roots/bud-api/types/repository/index.d.ts' -namespace Repository { - interface Entry { - (this: Bud, name: string, entrypoint: Entry.Value): Bud - } - - interface Entry { - (this: Bud, entrypoints: Entry.Input): Bud - } - - namespace Entry { - interface Object { - import?: string[] - dependOn?: string[] - } - - interface Input { - [k: string]: Object | Object['import'] | GlobTask['pattern'] - } - - type Value = GlobTask['pattern'] | Array - } -} -``` diff --git a/sources/@repo/docs/content/docs/bud.experiments.mdx b/sources/@repo/docs/content/docs/bud.experiments.mdx index be6d741e62..c8cfdccf62 100644 --- a/sources/@repo/docs/content/docs/bud.experiments.mdx +++ b/sources/@repo/docs/content/docs/bud.experiments.mdx @@ -7,7 +7,7 @@ sidebar_label: bud.experiments :::warning -These settings are obviously experimental. If you're using `bud.experiments` and you bump into a problem please ensure that +These settings are flagged as experimental by Webpack. If you're using `bud.experiments` and you bump into a problem please ensure that **bud.js** is doing something wrong before opening an issue in the roots/bud repository. Consider accompanying your issue with a PR that implements the change you would like to see. diff --git a/sources/@repo/docs/content/docs/bud.externals.mdx b/sources/@repo/docs/content/docs/bud.externals.mdx index 3b54ddb0b7..d7b713e32b 100644 --- a/sources/@repo/docs/content/docs/bud.externals.mdx +++ b/sources/@repo/docs/content/docs/bud.externals.mdx @@ -3,7 +3,6 @@ id: bud.externals title: bud.externals description: Specify a non-standard resolution strategy for modules with a matching name. sidebar_label: bud.externals -image: 'https://bud.js.org/img/share/docs/bud.externals.png' --- Specify a non-standard resolution strategy for modules with a matching name. diff --git a/sources/@repo/docs/content/docs/bud.glob.mdx b/sources/@repo/docs/content/docs/bud.glob.mdx index fc13bd9b9b..f6695b6fe6 100644 --- a/sources/@repo/docs/content/docs/bud.glob.mdx +++ b/sources/@repo/docs/content/docs/bud.glob.mdx @@ -4,17 +4,17 @@ description: Globbing function sidebar_label: bud.glob --- -Glob for matching files. This function is asyncronous but there is a syncronous version provided by [bud.globSync](/docs/bud.globSync) +Glob for matching files. This function is asynchronous but there is a synchronous version provided by [bud.globSync](/docs/bud.globSync) ## Usage -To look for files relative to the project, you can simply pass the search: +To look for files relative to the project root: ```js const results = await bud.glob('**/*.json') ``` -To include additional search terms (matched as `AND`) you can either treat the function as variadic or specify with an array: +To include additional search terms you can either treat the function as variadic or specify with an array: ```js const results = await bud.glob('**/*.json', '**/*.yml') diff --git a/sources/@repo/docs/content/docs/bud.globSync.mdx b/sources/@repo/docs/content/docs/bud.globSync.mdx index cf8bd9c65f..9e6f5d8678 100644 --- a/sources/@repo/docs/content/docs/bud.globSync.mdx +++ b/sources/@repo/docs/content/docs/bud.globSync.mdx @@ -5,17 +5,17 @@ description: Globbing function sidebar_label: bud.globSync --- -Glob for matching files. This function is syncronous but there is an asyncronous version provided by [bud.glob](/docs/bud.glob) +Glob for matching files. This function is synchronous but there is an asynchronous version provided by [bud.glob](/docs/bud.glob). The asynchronous version should be preferred. ## Usage -To look for files relative to the project, you can simply pass the search: +To look for files relative to the project root: ```js const results = bud.globSync('**/*.json') ``` -To include additional search terms (matched as `AND`) you can either treat the function as variadic or specify with an array: +To include additional search terms you can either treat the function as variadic or specify with an array: ```js const results = bud.globSync('**/*.json', '**/*.yml') diff --git a/sources/@repo/docs/content/docs/bud.hooks/index.mdx b/sources/@repo/docs/content/docs/bud.hooks/index.mdx index 2beb033226..12c497bfaf 100644 --- a/sources/@repo/docs/content/docs/bud.hooks/index.mdx +++ b/sources/@repo/docs/content/docs/bud.hooks/index.mdx @@ -61,15 +61,15 @@ bud.hooks.async('build.resolve.modules', async modulePaths => [ Callbacks for asynchronous hooks should be registered as asynchronous functions. -## bud.hooks.fromMap +## bud.hooks.fromAsyncMap -Set multiple async hooks at once with `bud.hooks.fromMap`. +Set multiple async hooks at once with `bud.hooks.fromAsyncMap`. ```ts -bud.hooks.fromMap({ +bud.hooks.fromAsyncMap({ 'build.resolve.modules': async paths => [ ...paths, - await fs.promises.realpath('node_modules'), + abud.path('@modules'), ], }) ``` diff --git a/sources/@repo/docs/content/docs/bud.make.mdx b/sources/@repo/docs/content/docs/bud.make.mdx index 2c50f962a1..1e03243b12 100644 --- a/sources/@repo/docs/content/docs/bud.make.mdx +++ b/sources/@repo/docs/content/docs/bud.make.mdx @@ -17,39 +17,33 @@ For more context on how this might be useful check out [the guide on multi-compi **bud.make** is an asyncronous function that takes two parameters: -- The **name** of the new compiler, or an [**options**](#options) object to be used when constructing the new instance. +- The **name** of the new compiler, or a context to be used when constructing the new instance. - An optional callback to use for configuring the compiler. Example specified with a **name**: ```js -bud.make('scripts', async child => child.entry('app', 'app.js')) +export default async bud => { + bud.make('compiler-a', async child => child.entry('app', 'app.js')) +} ``` -Example specified with **options** object: +Example specified with context overrides: ```ts -bud.make( - { - name: 'compiler-a', - dir: bud.path('./compiler-a'), - }, - config => {}, -) +export default async bud => { + bud.make( + { + name: 'compiler-b', + basedir: bud.path('./compiler-a'), + }, + async child => { + child.entry('app', 'app.js') + }, + ) +} ``` -## Options - -| Property | Value | -| ---------- | --------------------------------------- | -| name | Compiler name | -| dir | Compiler base directory (absolute path) | -| mode | `development` or `production` | -| context | Context | -| seed | Initializing values | -| services | Service classes | -| extensions | Extension classes | - Related: - [bud.get](/docs/bud.get) diff --git a/sources/@repo/docs/content/docs/bud.path.mdx b/sources/@repo/docs/content/docs/bud.path.mdx index e6bc01253f..dda1d0ddb1 100644 --- a/sources/@repo/docs/content/docs/bud.path.mdx +++ b/sources/@repo/docs/content/docs/bud.path.mdx @@ -10,12 +10,6 @@ You can use **bud.path** to reference a file or directory's absolute path. ## Usage -```ts -bud.path('@src/scripts/components') -``` - -If you like you can use `./` to reference project root: - ```ts bud.path('./src/scripts/components') ``` @@ -23,12 +17,12 @@ bud.path('./src/scripts/components') You may also choose to deliniate directories with an `Array` of path segments, rather than a `String`: ```ts -bud.path('@src', 'scripts', 'components') +bud.path('./src', 'scripts', 'components') ``` ## Special path handles -The following is a table containing `String` values which fulfill a special role in the context of the **bud.path** function: +The following is a table containing `string` values which fulfill a special role in the context of the **bud.path** function: | handle | description | default | | ------------ | -------------------------------- | ---------------- | @@ -37,7 +31,7 @@ The following is a table containing `String` values which fulfill a special role | **@storage** | cache/artifact storage directory | `./.budfiles` | | **@modules** | modules directory | `./node_modules` | -When one of these handles is used at **the beginning of a path**, the path will be +When one of these handles is used at **the beginning of a string path** (or the first segment in a multi-segment path), the path will be prefixed with the corresponding directory. For example, to reference the `./src` directory: @@ -46,40 +40,9 @@ For example, to reference the `./src` directory: bud.path('@src/scripts/components') ``` -You can create your own handles for use in the **bud.path** function. But, the handles in this table are standard. Other parts of the bud.js framework or ecosystem may use these handles to reference project directories. So, while they may be freely modified as needed, they should not be removed. - -## Managing **bud.path** handles - -**bud.setPath** is used to add or modify path handles. There are only two real rules for path handles: - -- A path handle must be unique -- A path handle must be a `String` which begins with a `@` - -To make a reference to the `./src/scripts/components` directory we could write: - -```ts -bud.setPath('@components', '@src/scripts/components') -``` +You can create your own handles for use in the **bud.path** function. But, the handles in this table are standard. +Other parts of bud.js or its ecosystem may use these handles to reference project directories. So, while they may be freely modified as needed, they should not be removed or repurposed. -In the future we can utilize that reference: - -```ts -bud.path('@components') // => './src/scripts/components' -``` - -We can redefine the path to source assets like so: - -```ts -bud.setPath('@src', 'sources') -``` - -Lastly, we can define multiple paths in a single call by using an object: - -```ts -bud.setPath({ - '@src': 'sources', - '@components': '@src/scripts/components', -}) -``` +## Setting **bud.path** handles -Note that if we were to change `@src` again that `@components` path would still reference the old value. This is something to be aware of. +Use [bud.setPath](/docs/bud.setPath) to define or override a handle value. diff --git a/sources/@repo/docs/content/docs/bud.serve.mdx b/sources/@repo/docs/content/docs/bud.serve.mdx index 2430bfacad..f93d0a1d36 100644 --- a/sources/@repo/docs/content/docs/bud.serve.mdx +++ b/sources/@repo/docs/content/docs/bud.serve.mdx @@ -19,13 +19,6 @@ By default bud will serve at the following address: If port 3000 is already used a new port will be dynamically selected. -## Usage - -There is no need to call this function in order to use the development server. Development server functionality is automatically enabled when -the `bud serve` cli command is invoked. - -This function is used to configure the development server to run at a specific hostname or port, and/or serve over SSL. - ## Specifying server address :::warning diff --git a/sources/@repo/docs/content/docs/bud.setPath.mdx b/sources/@repo/docs/content/docs/bud.setPath.mdx index 43754b5b43..34742649b3 100644 --- a/sources/@repo/docs/content/docs/bud.setPath.mdx +++ b/sources/@repo/docs/content/docs/bud.setPath.mdx @@ -6,66 +6,14 @@ sidebar_label: bud.setPath image: 'https://bud.js.org/img/share/docs/bud.setPath.png' --- -You can use **bud.setPath** to set a [bud.path](/docs/bud.path) handle. +You can use **bud.setPath** to set a [bud.path](/docs/bud.path) handle. This documentation probably makes more sense if you've read the [bud.path](/docs/bud.path) documentation. -## Usage +## Defining new handles -```ts -bud.path('@src/scripts/components') -``` - -Use `./` to reference project root: - -```ts -bud.path('./src/scripts/components') -``` - -You may deliniate directories with an `Array` of path segments, rather than a `String`: - -```ts -bud.path('@src', 'scripts', 'components') -``` - -## Special path handles - -The following is a table containing `String` values which fulfill a special role in the context of the **bud.path** function: - -| handle | description | default | -| ------------ | -------------------------------- | ---------------- | -| **@src** | source directory | `./src` | -| **@dist** | destination directory | `./dist` | -| **@storage** | cache/artifact storage directory | `./.budfiles` | -| **@modules** | modules directory | `./node_modules` | - -When one of these handles is used at **the beginning of a path**, the path will be -prefixed with the corresponding directory. - -For example, to reference the `@src` directory: - -```ts -bud.path('@src/scripts/components') -``` - -You can create your own handles for use in the **bud.path** function. But, the handles in this table are standard. -Other parts of the bud.js framework or ecosystem may use these handles to reference project directories. -So, while they may be freely modified as needed, they should not be removed. - -### `@file` handle - -You may use `@file` anywhere in a bud path to reference the an output filename. - -By default the string will resolve to either `[path][name].[contenthash:6][ext]` or `[path][name][ext]`, depending on if hashing is enabled. - -### `@name` handle - -To reference only the filename, you may use `@name` instead of `@file`. - -## Managing **bud.path** handles - -**bud.setPath** is used to add or modify path handles. There are only two real rules for path handles: +There are only two real rules for defining custom path handles: - A path handle must be unique -- A path handle must be a `String` which begins with a `@` +- A path handle must be a `string` which begins with a `@` To make a reference to the `./src/scripts/components` directory we could write: @@ -79,13 +27,15 @@ In the future we can utilize that reference: bud.path('@components') // => './src/scripts/components' ``` +## Overriding existing handles + We can redefine the path to source assets like so: ```ts bud.setPath('@src', 'sources') ``` -Lastly, we can define multiple paths in a single call by using an object: +Lastly, we can define multiple paths (built-in or custom) in a single call by using an object: ```ts bud.setPath({ @@ -93,3 +43,5 @@ bud.setPath({ '@components': '@src/scripts/components', }) ``` + +Note that if we were to change `@src` again that `@components` path would still reference the old value. This is something to be aware of. diff --git a/sources/@repo/docs/content/docs/bud.sh.mdx b/sources/@repo/docs/content/docs/bud.sh.mdx new file mode 100644 index 0000000000..cccca9fb02 --- /dev/null +++ b/sources/@repo/docs/content/docs/bud.sh.mdx @@ -0,0 +1,36 @@ +--- +slug: bud.sh +title: bud.sh +description: Access the bud object through a callback +sidebar_label: bud.sh +--- + +bud.sh is used to execute arbitrary shell commands. It is a wrapper around the [execa](https://github.com/sindresorhus/execa) package. + +It's async and returns the `ExecaChildProcess` object. It will pipe the process stdout/stderr to the console automatically. + +## Usage + +```js title=bud.config.mjs +export default async bud => { + await bud.sh(`ls -la`) +} +``` + +You may use an array of arguments instead of a string: + +```js +export default async bud => { + await bud.sh([`ls`, `-la`]) +} +``` + +Additionally, you can pass on configuration options to the underlying package: + +```js +export default async bud => { + await bud.sh([`ls`, `-la`], { + shell: true, + }) +} +``` diff --git a/sources/@repo/docs/content/docs/bud.splitChunks.mdx b/sources/@repo/docs/content/docs/bud.splitChunks.mdx index 011d8433c2..5bbd45a6af 100644 --- a/sources/@repo/docs/content/docs/bud.splitChunks.mdx +++ b/sources/@repo/docs/content/docs/bud.splitChunks.mdx @@ -3,7 +3,6 @@ slug: bud.splitChunks title: bud.splitChunks description: Separate vendor code from application code sidebar_label: bud.splitChunks -image: 'https://bud.js.org/img/share/docs/bud.splitChunks.png' --- Separate vendor code from application code. diff --git a/sources/@repo/docs/content/docs/bud.tap.mdx b/sources/@repo/docs/content/docs/bud.tap.mdx index 1cde4d9a5e..03d60ece11 100644 --- a/sources/@repo/docs/content/docs/bud.tap.mdx +++ b/sources/@repo/docs/content/docs/bud.tap.mdx @@ -3,29 +3,18 @@ slug: bud.tap title: bud.tap description: Access the bud object through a callback sidebar_label: bud.tap -image: 'https://bud.js.org/img/share/docs/bud.tap.png' --- Access the bud object through a callback. Useful to maintain a function chain. ## Usage -```js -bud.tap(({entry}) => entry('app', ['app.js'])) +```js title=bud.config.mjs +export default async bud => { + bud.tap(bud => { + bud.entry('index.js') + }) +} ``` -Using a regular function (as opposed to an arrow function), you may use **bud** using a contextual binding: - -```js -bud.tap(function () { - this.entry('app', ['app.js']) -}) -``` - -If you wish to use a non-arrow function while preserving its context, a second parameter will ensure your existing lexical scope is respected. You may still access **bud** via parameter. - -```js -bud.tap(function (bud) { - bud.entry('app', ['app.js']) -}, false) -``` +It may be helpful to consider that the bud.config.mjs export is esssentially just a bud.tap callback. diff --git a/sources/@repo/docs/content/docs/bud.template.mdx b/sources/@repo/docs/content/docs/bud.template.mdx index 8145ad0e87..878fda9809 100644 --- a/sources/@repo/docs/content/docs/bud.template.mdx +++ b/sources/@repo/docs/content/docs/bud.template.mdx @@ -3,25 +3,9 @@ slug: bud.template title: bud.template description: Configure your application's html templates. sidebar_label: bud.template -image: 'https://bud.js.org/img/share/docs/bud.template.png' --- -Configure your application's html templates. - -## Signature - -```ts title='template.d.ts' -type Template = ( - this: Bud, - options?: { - enabled?: boolean - template?: string - replace?: { - [key: string]: string - } - }, -) => Bud -``` +Configure your app's html wrapper ## Usage @@ -31,16 +15,13 @@ This method can be called without passing any options. bud.template() ``` -## Explicitly enabling or disabling +The default template will source a couple variables from `.env`, you'll probably want to make sure they are set. -You may use `enabled` to explicitly disable or enable the html generation. - -```js title='bud.config.js' -bud.template({enabled: false}) +```env title='.env' +PUBLIC_APP_TITLE='My App' +PUBLIC_APP_DESCRIPTION='My App Description' ``` -Useful in the event that an overeager extension is adding a template you do not have use for. - ## Using a custom template ```js title='bud.config.js' @@ -65,38 +46,8 @@ bud.template({ You may use any of these variables in the template by surrounding the variable name with `%` characters. -```html {2} title='public/index.html' +```html title='public/index.html' %APP_NAME% ``` - -You may use [**bud.define**](/docs/bud.define) should you need to access defined variables from your application code as well. - -Lastly, any variables defined in an `.env` file are also made available to the template automatically. - -## Default template reference - -```html - - - - - - - - %APP_NAME% - - - - - - -
- - - -``` diff --git a/sources/@repo/docs/content/docs/bud.use.mdx b/sources/@repo/docs/content/docs/bud.use.mdx index 54c0f5d226..bf8d0272d0 100644 --- a/sources/@repo/docs/content/docs/bud.use.mdx +++ b/sources/@repo/docs/content/docs/bud.use.mdx @@ -3,7 +3,6 @@ slug: bud.use title: bud.use description: Register an extension or set of extensions sidebar_label: bud.use -image: 'https://bud.js.org/img/share/docs/bud.use.png' --- Register an extension or set of extensions. diff --git a/sources/@repo/docs/content/docs/bud.watch/index.mdx b/sources/@repo/docs/content/docs/bud.watch/index.mdx index a29846eb7a..4c4f4b1d71 100644 --- a/sources/@repo/docs/content/docs/bud.watch/index.mdx +++ b/sources/@repo/docs/content/docs/bud.watch/index.mdx @@ -7,42 +7,22 @@ sidebar_label: bud.watch Specify files which trigger a full page reload in development mode. -## Signature - -```ts -(...files: Array>): Bud -``` - ## Usage -Specify a file to watch using a string: +It is preferred to specify files using [bud.path](/docs/bud.path) or [bud.glob](/docs/bud.glob). ```ts -bud.watch('pages/page.php') +bud.watch(bud.path(`@src/pages/page.php`)) ``` You can use glob syntax to specify multiple files using pattern matching: ```ts -bud.watch('pages/**/*') +bud.watch(await bud.glob(`@src/pages/**/*`)) ``` -You can add additional watch patterns using additional parameters: - -```ts -bud.watch('pages/**/*', 'package.json') -``` - -It is fine to express multiple patterns with an array, if preferred: - -```ts -bud.watch(['pages/**/*', 'package.json']) -``` - -## Resolving paths - -All watch parameters are resolved as project relative paths. You may use `node:path` or [bud.path](https://bud.js.org/docs/bud.path) to specify absolute directories, if preferred: +You can add additional watch patterns using an `array`: ```ts -bud.watch(bud.path('pages/**/*'), bud.path('package.json')) +bud.watch([bud.path('@src/pages/**/*'), bud.path('package.json')]) ``` diff --git a/sources/@repo/docs/content/docs/bud.when.mdx b/sources/@repo/docs/content/docs/bud.when.mdx index c5234371b4..139fadcbd6 100644 --- a/sources/@repo/docs/content/docs/bud.when.mdx +++ b/sources/@repo/docs/content/docs/bud.when.mdx @@ -3,7 +3,6 @@ slug: bud.when title: bud.when description: Conditionally execute a function based on conditions sidebar_label: bud.when -image: 'https://bud.js.org/img/share/docs/bud.when.png' --- Executes a function if a given test is `true`. diff --git a/sources/@repo/docs/content/docs/index.mdx b/sources/@repo/docs/content/docs/index.mdx index 141ad6a63b..419c6df288 100644 --- a/sources/@repo/docs/content/docs/index.mdx +++ b/sources/@repo/docs/content/docs/index.mdx @@ -1,7 +1,6 @@ --- title: Configuration reference description: Register shorthand for resolving modules. -image: 'https://bud.js.org/img/share/docs/bud.alias.png' slug: '/' --- @@ -159,6 +158,14 @@ Configure the development server Read documentation +### bud.sh + +Execute arbitrary commands + + + Read documentation + + ### bud.setPath Set application filesystem paths diff --git a/sources/@repo/docs/content/guides/general-use/customizing-loaders.mdx b/sources/@repo/docs/content/guides/general-use/customizing-loaders.mdx index 08dd7976f2..4420b0757e 100644 --- a/sources/@repo/docs/content/guides/general-use/customizing-loaders.mdx +++ b/sources/@repo/docs/content/guides/general-use/customizing-loaders.mdx @@ -29,12 +29,34 @@ Modify the source path of a given loader using **Loader[\`setSrc\`]** bud.build.loaders.babel.setSrc('example') ``` -### Registering new loaders +### Examples -Register a new loader using **Build[\`addLoader\`]**. The first parameter is a friendly handle for the loader, and the second is the path to the loader module. +With automatic resolution: -```ts -bud.build.setLoader(`example`, bud.module.resolve(`example`)) +```js title=bud.config.mjs +export default async bud => { + bud.build.setLoader(`babel-loader`) +} +``` + +With explicit resolution: + +```js title=bud.config.mjs +export default async bud => { + bud.build.setLoader( + `babel-loader`, + await bud.module.resolve(`babel-loader`), + ) +``` + +Using the callback API: + +```js title=bud.config.mjs +export default async bud => { + bud.build.setLoader( + `babel-loader`, + loader => loader.setSrc(`babel-loader`) + ) ``` ## Items @@ -61,13 +83,31 @@ The value given references the handle of a registered [loader](#loaders). bud.build.items.example.setLoader(`example`) ``` -### Registering new items +### Examples -```ts -bud.build.setItem(`example`, { - loader: `example`, - options: {}, -}) +Declaratively: + +```js title=bud.config.mjs +export default async bud => { + bud.build.setItem(`babel`, { + loader: `babel-loader`, + options: { + presets: [`@babel/preset-env`], + }, + }) +} +``` + +Using the callback API: + +```js title=bud.config.mjs +export default async bud => { + bud.build.setItem(`babel`, item => + item.setLoader(`babel-loader`).setOptions({ + presets: [`@babel/preset-env`], + }), + ) +} ``` ## Rules @@ -119,30 +159,27 @@ The value given references the handle of a registered [item](#items). bud.build.rules.js.setUse(items => [...items, 'babel']) ``` -### Registering new rules +### Examples -New rules can be registered using `bud.build.setRule`: +Declaratively: -```ts -bud.build.setRule('app.ts', { - test: /\.app.tsx?$/, - use: [`ts`], -}) +```js title=bud.config.mjs +export default async bud => { + bud.build.setRule(`js`, { + test: /\.js$/, + use: [`babel`], + }) +} ``` -New rules can be made (but not registered) using `bud.build.makeRule`: - -```ts -const rule = bud.build - .makeRule() - .setTest(/\.app.tsx?$/) - .setUse([`ts`]) +Using the callback API: -// Later this could be registered: -bud.build.setRule(`app.ts`, rule) +```js title=bud.config.mjs +export default async bud => + bud.build.setRule(`js`, rule => rule.setTest(/\.js$/).setUse([`babel`])) ``` -## Examples +## In practice ### @roots/bud-typescript diff --git a/sources/@repo/docs/content/guides/general-use/development-server.mdx b/sources/@repo/docs/content/guides/general-use/development-server.mdx index aa1e5c659c..943fa60a0c 100644 --- a/sources/@repo/docs/content/guides/general-use/development-server.mdx +++ b/sources/@repo/docs/content/guides/general-use/development-server.mdx @@ -15,7 +15,7 @@ export default async bud => { } ``` -That said, you can use a `string``: +That said, you can use a `string`: ```js title='bud.config.mjs' export default async bud => { diff --git a/sources/@repo/docs/content/guides/general-use/managing-dependencies.mdx b/sources/@repo/docs/content/guides/general-use/managing-dependencies.mdx new file mode 100644 index 0000000000..d0c77494af --- /dev/null +++ b/sources/@repo/docs/content/guides/general-use/managing-dependencies.mdx @@ -0,0 +1,63 @@ +--- +title: Managing dependencies +description: Managing dependencies +slug: managing-dependencies +sidebar_label: Managing dependencies +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +From the yarn docs: + +> If your package is a meta-package of utilities [...], the situation is a bit complicated and you have two different options: +> +> - The preferred one is to list the dependency [...] as both a regular dependency and a peer dependency. Yarn will interpret this pattern as "peer dependency with a default", meaning that your users will be able to take ownership of the Webpack package if they need to, while still giving the package manager the ability to emit a warning if the provided version is incompatible with the one your package expects. +> +> ⸺ [Packages should only ever require what they formally list in their dependencies](https://yarnpkg.com/advanced/rulebook#packages-should-only-ever-require-what-they-formally-list-in-their-dependencies) + +bud.js extensions usually come with everything you need to use a particular tool in your application. But, sometimes your application's needs will be in conflict with the defaults that ship with bud.js. + +A common example of this is Vue 2 vs Vue 3. **@roots/bud-vue** supports Vue 3 by default, but if you need/want to use Vue 2, you can. You'll just need to override some of the peer dependencies in order to do so. + +Likewise, in **@roots/bud-tailwindcss** we will update TailwindCSS when it is safe to do so. If there is a version mismatch between TailwindCSS and something in postcss-preset-env, you'll need to override the version of TailwindCSS in your project in order to use the latest version. Once the conflict is resolved, we'll do the same. + +:::info Be careful + +Once you start overriding dependencies, you're on your own. It's hard enough to manage dependencies in a single project, let alone a monorepo, so our bandwidth to help will be limited. + +::: + +## Overriding peer dependencies + +There isn't an API to manage dependency overrides per se, we just use the peer dependency features built into npm and yarn to make it possible for you to customize your dependencies as needed. To do so you will just install the needed overrides in your project. + +Nearly all of the popular dependencies listed by bud.js and its extensions (vue, react, tailwindcss, typescript, swc, et al) are listed as peer dependencies. Their accepted versions are all very loose. + +## In practice + +A Vue 3 project can just install **@roots/bud** and **@roots/bud-vue** and everything should be perfectly set up. But, at least for now, in order to use Vue 2, you'll need to override: + +- vue (^2.6.14) +- vue-template-compiler (^2.6.14) +- vue-loader (^15.9.4) + +Once installed **@roots/bud-vue** will recognize the version of vue you've installed is for Vue 2 and will configure the project accordingly. + +```ts +class BudVueExtension { + // ... + /** + * Returns true if user has installed a 2.x.x version of vue + * + * @public + * @decorator `@bind` + */ + @bind + protected async isVue2() { + const manifest = await this.app.module.readManifest(`vue`) + this.logger.log(`vue manifest:`, manifest) + return parseSemver(`vue@${manifest.version}`).version.startsWith(`2`) + } +} +``` diff --git a/sources/@repo/docs/content/guides/general-use/transpiler-sources.mdx b/sources/@repo/docs/content/guides/general-use/transpiler-sources.mdx index 0d2a172e11..42fb3f736d 100644 --- a/sources/@repo/docs/content/guides/general-use/transpiler-sources.mdx +++ b/sources/@repo/docs/content/guides/general-use/transpiler-sources.mdx @@ -28,6 +28,12 @@ bud.build.rules.js.setInclude([ ]) ``` +:::info + +`@modules` is a bud.path built-in handle referencing `node_modules` + +::: + Or, you can be broad: ```ts diff --git a/sources/@repo/docs/sidebars/guides.js b/sources/@repo/docs/sidebars/guides.js index 611c0aff67..f08397eb46 100644 --- a/sources/@repo/docs/sidebars/guides.js +++ b/sources/@repo/docs/sidebars/guides.js @@ -21,6 +21,7 @@ module.exports = { }, `cli/clean`, `cli/doctor`, + `cli/repl`, ], }, { @@ -37,6 +38,7 @@ module.exports = { `general-use/node-api`, `general-use/esmodules`, `general-use/remote-sources`, + `general-use/managing-dependencies`, ], }, { diff --git a/sources/@repo/docs/src/components/cli-output/doctor.help.md b/sources/@repo/docs/src/components/cli-output/doctor.help.md index 84fbbbf448..6c16207b32 100644 --- a/sources/@repo/docs/src/components/cli-output/doctor.help.md +++ b/sources/@repo/docs/src/components/cli-output/doctor.help.md @@ -4,22 +4,26 @@ Check project for common errors $ bud doctor +━━━ Options ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + --notify Enable notfication center messages + ━━━ Details ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ The `bud doctor` command will: 1. validate the `production` configuration with `webpack` -`webpack` exports a `validate` function which is used by this command to verify +`webpack` exports a `validate` function which is used by this command to verify that the configuration matches the `webpack` configuration schema. 2. check the `dependencies` and `devDependencies` in the `package.json` file. -In general, `bud.js` dependencies should be kept at the same version. This -script doesn't account for a lot of edge cases so it might return a false +In general, `bud.js` dependencies should be kept at the same version. This +script doesn't account for a lot of edge cases so it might return a false positive. ━━━ Examples ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Check compiled configuration against webpack -$ bud doctor + $ bud doctor \ No newline at end of file diff --git a/sources/@repo/docs/src/components/cli-output/help.md b/sources/@repo/docs/src/components/cli-output/help.md index b4e28c8bfa..49db6af114 100644 --- a/sources/@repo/docs/src/components/cli-output/help.md +++ b/sources/@repo/docs/src/components/cli-output/help.md @@ -4,7 +4,7 @@ ━━━ General commands ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - bud doctor + bud doctor [--notify] Check project for common errors bud repl [--color,-c] [--indent,-i #0] [--depth,-d #0] diff --git a/sources/@roots/bud-api/src/methods/watch/index.ts b/sources/@roots/bud-api/src/methods/watch/index.ts index 0f64a0f876..5836bcdda9 100644 --- a/sources/@roots/bud-api/src/methods/watch/index.ts +++ b/sources/@roots/bud-api/src/methods/watch/index.ts @@ -12,6 +12,8 @@ export interface watch { export const watch: watch = function (...input) { const app = this as Bud + if (!app.isDevelopment) return app + app.hooks.on(`dev.watch.files`, files => { if (!files) files = new Set() input.flat().forEach((file: string) => files.add(file)) diff --git a/sources/@roots/bud-babel/package.json b/sources/@roots/bud-babel/package.json index 9e2751a3da..706dc23560 100644 --- a/sources/@roots/bud-babel/package.json +++ b/sources/@roots/bud-babel/package.json @@ -69,16 +69,15 @@ "webpack": "5.73.0" }, "dependencies": { - "@babel/core": "7.18.10", + "@babel/core": "7.19.1", "@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-proposal-object-rest-spread": "7.18.9", "@babel/plugin-syntax-dynamic-import": "7.8.3", - "@babel/plugin-transform-runtime": "7.18.10", - "@babel/preset-env": "7.19.0", + "@babel/plugin-transform-runtime": "7.19.1", + "@babel/preset-env": "7.19.1", "@roots/bud-framework": "workspace:sources/@roots/bud-framework", "@roots/bud-support": "workspace:sources/@roots/bud-support", "babel-loader": "8.2.5", - "lodash-es": "4.17.21", "tslib": "2.4.0" }, "peerDependencies": { diff --git a/sources/@roots/bud-babel/src/extension.ts b/sources/@roots/bud-babel/src/extension.ts index 10527a9889..35652c46b8 100644 --- a/sources/@roots/bud-babel/src/extension.ts +++ b/sources/@roots/bud-babel/src/extension.ts @@ -61,23 +61,66 @@ export default class BabelExtension extends Extension { */ @bind public async register() { - this.app.babel - .setPreset(`@babel/preset-env`) - .setPlugin([`@babel/plugin-transform-runtime`, {helpers: false}]) - .setPlugin(`@babel/plugin-proposal-object-rest-spread`) - .setPlugin(`@babel/plugin-proposal-class-properties`) - .setPlugin(`@babel/plugin-syntax-dynamic-import`) + this.app.babel = new Config() + + const presetEnv = await this.resolve(`@babel/preset-env`) + if (presetEnv) this.app.babel.setPreset(`@babel/preset-env`, presetEnv) + + const transformRuntime = await this.resolve( + `@babel/plugin-transform-runtime`, + ) + transformRuntime && + this.app.babel.setPlugin(`@babel/plugin-transform-runtime`, [ + transformRuntime, + {helpers: false}, + ]) - this.app.build.setLoader(`babel-loader`).setItem(`babel`, item => - item.setLoader(`babel-loader`).setOptions(() => ({ + const objectRestSpread = await this.resolve( + `@babel/plugin-proposal-object-rest-spread`, + ) + objectRestSpread && + this.app.babel.setPlugin( + `@babel/plugin-proposal-object-rest-spread`, + objectRestSpread, + ) + + const classProperties = await this.resolve( + `@babel/plugin-proposal-class-properties`, + ) + classProperties && + this.app.babel.setPlugin( + `@babel/plugin-proposal-class-properties`, + classProperties, + ) + + const dynamicImport = await this.resolve( + `@babel/plugin-syntax-dynamic-import`, + ) + dynamicImport && + this.app.babel.setPlugin( + `@babel/plugin-syntax-dynamic-import`, + dynamicImport, + ) + + const loader = await this.resolve(`babel-loader`, import.meta.url) + if (!loader) { + return this.logger.error(`Babel loader not found`) + } + + this.app.build.setLoader(`babel`, loader).setItem(`babel`, { + loader: `babel`, + options: () => ({ cacheDirectory: this.cacheDirectory, presets: Object.values(this.app.babel.presets), plugins: Object.values(this.app.babel.plugins), env: this.env, root: this.root, - })), - ) + }), + }) - this.app.build.rules.js.setUse(items => [`babel`, ...items]) + this.app.build.rules.js.setUse(items => [ + this.app.build.items.babel, + ...(items ?? []), + ]) } } diff --git a/sources/@roots/bud-build/src/handlers/items.ts b/sources/@roots/bud-build/src/handlers/items.ts index e13f55344e..03aa43cd4c 100644 --- a/sources/@roots/bud-build/src/handlers/items.ts +++ b/sources/@roots/bud-build/src/handlers/items.ts @@ -6,9 +6,10 @@ import type {Item} from '@roots/bud-framework/services/build' * * @public */ -export const css = async (app: Bud): Promise => +export const css = (app: Bud): Item => app.build .makeItem() + .setIdent(`css`) .setLoader(`css`) .setOptions(() => ({ importLoaders: app.build.rules.css.getUse().length - 2, @@ -21,9 +22,10 @@ export const css = async (app: Bud): Promise => * * @public */ -export const cssModule = async (app: Bud): Promise => +export const cssModule = (app: Bud): Item => app.build .makeItem() + .setIdent(`cssModule`) .setLoader(`css`) .setOptions(({build, hooks}) => ({ esModule: true, @@ -38,7 +40,7 @@ export const cssModule = async (app: Bud): Promise => * * @public */ -export const csv = async (app: Bud): Promise => +export const csv = (app: Bud): Item => app.build.makeItem().setLoader(`csv`) /** @@ -46,34 +48,35 @@ export const csv = async (app: Bud): Promise => * * @public */ -export const html = async (app: Bud): Promise => - app.build.makeItem().setLoader(`html`) +export const html = (app: Bud): Item => + app.build.makeItem().setLoader(`html`).setIdent(`html`) /** * Style loader * * @public */ -export const style = async (app: Bud): Promise => - app.build.makeItem().setLoader(`style`) +export const style = (app: Bud): Item => + app.build.makeItem().setLoader(`style`).setIdent(`style`) /** * Markdown loader * * @public */ -export const md = async (app: Bud): Promise => - app.build.makeItem({loader: `md`}) +export const md = (app: Bud): Item => + app.build.makeItem().setIdent(`md`).setLoader(`md`) /** * MiniCss loader * * @public */ -export const minicss = async (app: Bud): Promise => +export const minicss = (app: Bud): Item => app.build .makeItem() .setLoader(`minicss`) + .setIdent(`minicss`) .setOptions(app => ({ publicPath: app.hooks.filter(`build.output.publicPath`), })) @@ -83,15 +86,15 @@ export const minicss = async (app: Bud): Promise => * * @public */ -export const raw = async ({build}: Bud): Promise => - build.makeItem().setLoader(`raw`) +export const raw = ({build}: Bud): Item => + build.makeItem().setLoader(`raw`).setIdent(`raw`) /** * File loader * * @public */ -export const file = async (app: Bud): Promise => +export const file = (app: Bud): Item => app.build .makeItem() .setLoader(`file`) @@ -100,19 +103,20 @@ export const file = async (app: Bud): Promise => ? app.hooks.filter(`value.hashFormat`).concat(`.[ext]`) : app.hooks.filter(`value.fileFormat`).concat(`.[ext]`), })) + .setIdent(`file`) /** * Xml loader * * @public */ -export const xml = async (app: Bud): Promise => - app.build.makeItem().setLoader(`xml`) +export const xml = (app: Bud): Item => + app.build.makeItem().setLoader(`xml`).setIdent(`xml`) /** * Yml loader * * @public */ -export const yml = async (app: Bud): Promise => - app.build.makeItem().setLoader(`yml`) +export const yml = (app: Bud): Item => + app.build.makeItem().setLoader(`yml`).setIdent(`yml`) diff --git a/sources/@roots/bud-build/src/handlers/loaders.ts b/sources/@roots/bud-build/src/handlers/loaders.ts index 6f66b6fe0f..3f996d68dc 100644 --- a/sources/@roots/bud-build/src/handlers/loaders.ts +++ b/sources/@roots/bud-build/src/handlers/loaders.ts @@ -7,8 +7,8 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin' * * @public */ -export const css = async (app: Bud): Promise => { - const loader = await app.module.resolve(`css-loader`) +export const css = (app: Bud): Loader => { + const loader = `css-loader` return app.build.makeLoader().setSrc(loader) } @@ -17,8 +17,8 @@ export const css = async (app: Bud): Promise => { * * @public */ -export const csv = async (app: Bud): Promise => { - const loader = await app.module.resolve(`csv-loader`) +export const csv = (app: Bud): Loader => { + const loader = `csv-loader` return app.build.makeLoader().setSrc(loader) } @@ -27,8 +27,8 @@ export const csv = async (app: Bud): Promise => { * * @public */ -export const file = async (app: Bud): Promise => { - const loader = await app.module.resolve(`file-loader`) +export const file = (app: Bud): Loader => { + const loader = `file-loader` return app.build.makeLoader().setSrc(loader) } @@ -37,8 +37,8 @@ export const file = async (app: Bud): Promise => { * * @public */ -export const html = async (app: Bud): Promise => { - const loader = await app.module.resolve(`html-loader`) +export const html = (app: Bud): Loader => { + const loader = `html-loader` return app.build.makeLoader().setSrc(loader) } @@ -47,8 +47,8 @@ export const html = async (app: Bud): Promise => { * * @public */ -export const remark = async (app: Bud): Promise => { - const loader = await app.module.resolve(`remark-loader`) +export const remark = (app: Bud): Loader => { + const loader = `remark-loader` return app.build.makeLoader().setSrc(loader) } @@ -57,7 +57,7 @@ export const remark = async (app: Bud): Promise => { * * @public */ -export const minicss = async (app: Bud): Promise => { +export const minicss = (app: Bud): Loader => { return app.build.makeLoader().setSrc(MiniCssExtractPlugin.loader) } @@ -66,8 +66,8 @@ export const minicss = async (app: Bud): Promise => { * * @public */ -export const style = async (app: Bud): Promise => { - const loader = await app.module.resolve(`style-loader`) +export const style = (app: Bud): Loader => { + const loader = `style-loader` return app.build.makeLoader().setSrc(loader) } @@ -76,8 +76,8 @@ export const style = async (app: Bud): Promise => { * * @public */ -export const xml = async (app: Bud): Promise => { - const loader = await app.module.resolve(`xml-loader`) +export const xml = (app: Bud): Loader => { + const loader = `xml-loader` return app.build.makeLoader().setSrc(loader) } @@ -86,7 +86,7 @@ export const xml = async (app: Bud): Promise => { * * @public */ -export const yml = async (app: Bud): Promise => { - const loader = await app.module.resolve(`yml-loader`) +export const yml = (app: Bud): Loader => { + const loader = `yml-loader` return app.build.makeLoader().setSrc(loader) } diff --git a/sources/@roots/bud-build/src/handlers/rules.ts b/sources/@roots/bud-build/src/handlers/rules.ts deleted file mode 100644 index 775c7e2d34..0000000000 --- a/sources/@roots/bud-build/src/handlers/rules.ts +++ /dev/null @@ -1,203 +0,0 @@ -import * as json5Parser from 'json5' -import * as tomlParser from 'toml' - -import type * as Rule from '../rule/rule.js' -import type Build from '../service.js' - -/** - * .js rule - * - * @public - */ -export const js = async (build: Build): Promise => - build - .makeRule() - .setTest(({hooks}) => hooks.filter(`pattern.js`)) - .setInclude([app => app.path(`@src`)]) - .setUse(() => []) - -/** - * .css rule - * - * @public - */ -export const css = async (build: Build): Promise => - build - .makeRule() - .setTest(({hooks}) => hooks.filter(`pattern.css`)) - .setInclude([app => app.path(`@src`)]) - .setUse([`precss`, `css`]) - -/** - * .module.css rule - * - * @public - */ -export const cssModule = async (build: Build): Promise => - build - .makeRule() - .setTest(({hooks}) => hooks.filter(`pattern.cssModule`)) - .setInclude([app => app.path(`@src`)]) - .setUse([`precss`, `cssModule`]) - -/** - * .jpg, .jpeg, .png, .gif rule - * - * @public - */ -export const image = async (build: Build): Promise => - build - .makeRule() - .setTest(({hooks}) => hooks.filter(`pattern.image`)) - .setInclude([app => app.path(`@src`)]) - .setType(`asset/resource`) - .setGenerator(app => ({ - filename: app.hooks.filter(`feature.hash`) - ? `images/` - .concat(app.hooks.filter(`value.hashFormat`)) - .concat(`[ext]`) - : `images/` - .concat(app.hooks.filter(`value.fileFormat`)) - .concat(`[ext]`), - })) - -/** - * .webp assets factorry - * - * @remarks - * Returns {@link Rule} for `asset/resource` - * - * @public - */ -export const webp = async (build: Build): Promise => - build - .makeRule() - .setTest(({hooks}) => hooks.filter(`pattern.webp`)) - .setInclude([app => app.path(`@src`)]) - .setType(`asset/resource`) - .setGenerator(app => ({ - filename: app.hooks.filter(`feature.hash`) - ? `images/` - .concat(app.hooks.filter(`value.hashFormat`)) - .concat(`[ext]`) - : `images/` - .concat(app.hooks.filter(`value.fileFormat`)) - .concat(`[ext]`), - })) - -/** - * Returns {@link Rule} for `.woff`/`.otf` handling - * .svg rule - * - * @public - */ -export const svg = async (build: Build): Promise => - build - .makeRule() - .setTest(({hooks}) => hooks.filter(`pattern.svg`)) - .setInclude([app => app.path(`@src`)]) - .setType(`asset/resource`) - .setGenerator(app => ({ - filename: app.hooks.filter(`feature.hash`) - ? `svg/` - .concat(app.hooks.filter(`value.hashFormat`)) - .concat(`[ext]`) - : `svg/` - .concat(app.hooks.filter(`value.fileFormat`)) - .concat(`[ext]`), - })) - -/** - * .woff, .woff2, .otf rule - * - * @public - */ -export const font = async (build: Build): Promise => - build - .makeRule() - .setType(`asset`) - .setTest(({hooks}) => hooks.filter(`pattern.font`)) - .setInclude([app => app.path(`@src`)]) - .setGenerator(app => ({ - filename: app.hooks.filter(`feature.hash`) - ? `fonts/` - .concat(app.hooks.filter(`value.hashFormat`)) - .concat(`[ext]`) - : `fonts/` - .concat(app.hooks.filter(`value.fileFormat`)) - .concat(`[ext]`), - })) - -/** - * Returns {@link Rule} for `.jsonc` handling - * - * @public - */ -export const json = async (build: Build): Promise => - build - .makeRule() - .setType(`json`) - .setInclude([app => app.path()]) - .setTest(({hooks}) => hooks.filter(`pattern.json`)) - .setParser({parse: json5Parser.parse}) - -/** - * Returns {@link Rule} for `.yml` / `.yaml` handling - * - * @public - */ -export const yml = async (build: Build): Promise => - build - .makeRule() - .setInclude([app => app.path()]) - .setTest(({hooks}) => hooks.filter(`pattern.yml`)) - .setUse([`yml`]) - -/** - * Returns {@link Rule} for `.html` handling - * - * @public - */ -export const html = async (build: Build): Promise => - build - .makeRule() - .setInclude([app => app.path()]) - .setTest(({hooks}) => hooks.filter(`pattern.html`)) - .setUse([`html`]) - -/** - * Returns {@link Rule} for `.csv` handling - * - * @public - */ -export const csv = async (build: Build): Promise => - build - .makeRule() - .setInclude([app => app.path()]) - .setTest(({hooks}) => hooks.filter(`pattern.csv`)) - .setUse([`csv`]) - -/** - * Returns {@link Rule} for `.xml` handling - * - * @public - */ -export const xml = async (build: Build): Promise => - build - .makeRule() - .setInclude([app => app.path()]) - .setTest(({hooks}) => hooks.filter(`pattern.xml`)) - .setUse([`xml`]) - -/** - * Returns {@link Rule} for `.toml` handling - * - * @public - */ -export const toml = async (build: Build): Promise => - build - .makeRule() - .setType(`json`) - .setInclude([app => app.path()]) - .setTest(({hooks}) => hooks.filter(`pattern.html`)) - .setParser({parse: tomlParser.parse}) diff --git a/sources/@roots/bud-build/src/handlers/rules/csv.ts b/sources/@roots/bud-build/src/handlers/rules/csv.ts new file mode 100644 index 0000000000..eeb1476233 --- /dev/null +++ b/sources/@roots/bud-build/src/handlers/rules/csv.ts @@ -0,0 +1,15 @@ +import type {Bud} from '@roots/bud-framework/src/bud.js' + +import type * as Rule from '../../rule/rule.js' + +/** + * Returns {@link Rule} for `.csv` handling + * + * @public + */ +export const csv = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setInclude([app => app.path()]) + .setTest(({hooks}) => hooks.filter(`pattern.csv`)) + .setUse([`csv`]) diff --git a/sources/@roots/bud-build/src/handlers/rules/rules.ts b/sources/@roots/bud-build/src/handlers/rules/rules.ts new file mode 100644 index 0000000000..a7faddaad2 --- /dev/null +++ b/sources/@roots/bud-build/src/handlers/rules/rules.ts @@ -0,0 +1,162 @@ +import type {Bud} from '@roots/bud-framework/src/bud.js' +import * as json5Parser from 'json5' +import {join} from 'path' + +import type * as Rule from '../../rule/rule.js' + +/** + * Returns {@link Rule} for js + * + * @public + */ +export const js = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setTest(({hooks}) => hooks.filter(`pattern.js`)) + .setInclude([app => app.path(`@src`)]) + .setUse(() => []) + +/** + * Returns {@link Rule} for css + * + * @public + */ +export const css = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setTest(({hooks}) => hooks.filter(`pattern.css`)) + .setInclude([app => app.path(`@src`)]) + .setUse([`precss`, `css`]) + +/** + * Returns {@link Rule} for module.css + * + * @public + */ +export const cssModule = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setTest(({hooks}) => hooks.filter(`pattern.cssModule`)) + .setInclude([app => app.path(`@src`)]) + .setUse([`precss`, `cssModule`]) + +/** + * Returns {@link Rule} for svg + * + * @public + */ +export const svg = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setTest(({hooks}) => hooks.filter(`pattern.svg`)) + .setInclude([app => app.path(`@src`)]) + .setType(`asset/resource`) + .setGenerator(app => ({ + filename: join( + `svg`, + (app.hooks.filter(`feature.hash`) + ? app.hooks.filter(`value.hashFormat`) + : app.hooks.filter(`value.fileFormat`) + ).concat(`[ext]`), + ), + })) + +/** + * Returns {@link Rule} for webp + * + * @public + */ +export const webp = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setTest(({hooks}) => hooks.filter(`pattern.webp`)) + .setInclude([app => app.path(`@src`)]) + .setType(`asset/resource`) + .setGenerator(app => ({ + filename: join( + `images`, + (app.hooks.filter(`feature.hash`) + ? app.hooks.filter(`value.hashFormat`) + : app.hooks.filter(`value.fileFormat`) + ).concat(`[ext]`), + ), + })) + +/** + * Returns {@link Rule} for images + * + * @public + */ +export const image = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setTest(({hooks}) => hooks.filter(`pattern.image`)) + .setInclude([app => app.path(`@src`)]) + .setType(`asset/resource`) + .setGenerator(app => ({ + filename: join( + `images`, + (app.hooks.filter(`feature.hash`) + ? app.hooks.filter(`value.hashFormat`) + : app.hooks.filter(`value.fileFormat`) + ).concat(`[ext]`), + ), + })) + +/** + * Returns {@link Rule} for fonts + * + * @public + */ +export const font = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setType(`asset`) + .setTest(({hooks}) => hooks.filter(`pattern.font`)) + .setInclude([app => app.path(`@src`)]) + .setGenerator(app => ({ + filename: join( + `fonts`, + (app.hooks.filter(`feature.hash`) + ? app.hooks.filter(`value.hashFormat`) + : app.hooks.filter(`value.fileFormat`) + ).concat(`[ext]`), + ), + })) + +/** + * Returns {@link Rule} for json + * + * @public + */ +export const json = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setType(`json`) + .setInclude([app => app.path()]) + .setTest(({hooks}) => hooks.filter(`pattern.json`)) + .setParser({parse: json5Parser.parse}) + +/** + * Returns {@link Rule} for yml + * + * @public + */ +export const yml = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setInclude([app => app.path()]) + .setTest(({hooks}) => hooks.filter(`pattern.yml`)) + .setUse([`yml`]) + +/** + * Returns {@link Rule} for html + * + * @public + */ +export const html = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setInclude([app => app.path()]) + .setTest(({hooks}) => hooks.filter(`pattern.html`)) + .setUse([`html`]) diff --git a/sources/@roots/bud-build/src/handlers/rules/toml.ts b/sources/@roots/bud-build/src/handlers/rules/toml.ts new file mode 100644 index 0000000000..71ec0f2672 --- /dev/null +++ b/sources/@roots/bud-build/src/handlers/rules/toml.ts @@ -0,0 +1,17 @@ +import type {Bud} from '@roots/bud-framework/src/bud.js' +import * as tomlParser from 'toml' + +import type * as Rule from '../../rule/rule.js' + +/** + * Returns {@link Rule} for `.toml` handling + * + * @public + */ +export const toml = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setType(`json`) + .setInclude([app => app.path()]) + .setTest(({hooks}) => hooks.filter(`pattern.toml`)) + .setParser({parse: tomlParser.parse}) diff --git a/sources/@roots/bud-build/src/handlers/rules/xml.ts b/sources/@roots/bud-build/src/handlers/rules/xml.ts new file mode 100644 index 0000000000..831062ec57 --- /dev/null +++ b/sources/@roots/bud-build/src/handlers/rules/xml.ts @@ -0,0 +1,15 @@ +import type {Bud} from '@roots/bud-framework/src/bud.js' + +import type * as Rule from '../../rule/rule.js' + +/** + * Returns {@link Rule} for `.xml` handling + * + * @public + */ +export const xml = ({build}: Bud): Rule.Interface => + build + .makeRule() + .setInclude([app => app.path()]) + .setTest(({hooks}) => hooks.filter(`pattern.xml`)) + .setUse([`xml`]) diff --git a/sources/@roots/bud-build/src/item/item.ts b/sources/@roots/bud-build/src/item/item.ts index 0ed43593a0..2b53ecee03 100644 --- a/sources/@roots/bud-build/src/item/item.ts +++ b/sources/@roots/bud-build/src/item/item.ts @@ -1,7 +1,11 @@ import type {Bud} from '@roots/bud-framework/bud' import type * as Build from '@roots/bud-framework/services/build' +import type {Loaders} from '@roots/bud-framework/src/types/services/build/registry.js' import {bind} from '@roots/bud-support/decorators' +import {isString} from '@roots/bud-support/lodash-es' +import {basename} from 'path' +import Loader from '../loader/loader.js' import Base from '../shared/base.js' export type ConstructorOptions = Build.Item.ConstructorOptions @@ -11,13 +15,19 @@ export type ConstructorOptions = Build.Item.ConstructorOptions * * @public */ -class Item extends Base { +class Item extends Base implements Build.Item { + /** + * Identifier + * @public + */ + public ident: string + /** * Loader * * @public */ - public loader: Build.Item['loader'] + public loader: Loader | `${keyof Loaders & string}` /** * Loader options @@ -29,19 +39,42 @@ class Item extends Base { /** * Class constructor * - * @param options - {@link Build.Item.Options} + * @public */ public constructor( protected _app: () => Bud, - options?: { - loader?: Item['loader'] + constructorParams?: { + ident?: string + loader?: Loader | `${keyof Loaders & string}` options?: Item['options'] }, ) { super(_app) - options?.loader && this.setLoader(options.loader) - options?.options && this.setOptions(options.options) + constructorParams?.ident && this.setIdent(constructorParams.ident) + constructorParams?.loader && this.setLoader(constructorParams.loader) + + !constructorParams?.ident && + constructorParams?.loader && + this.setIdent( + isString(constructorParams.loader) + ? constructorParams.loader + : basename(constructorParams.loader.getSrc()), + ) + + constructorParams?.options && + this.setOptions(constructorParams.options) + } + + @bind + public getIdent(): Build.Item['ident'] { + return this.ident + } + + @bind + public setIdent(ident: Build.Item['ident']): this { + this.ident = ident + return this } /** @@ -51,8 +84,10 @@ class Item extends Base { * @decorator `@bind` */ @bind - public getLoader(): Build.Loader { - return this.app.build.loaders[this.unwrap(this.loader)] + public getLoader(): Loader { + return this.loader instanceof Loader + ? this.loader + : this.app.build.loaders[this.loader] } /** @@ -62,8 +97,10 @@ class Item extends Base { * @decorator `@bind` */ @bind - public setLoader(loader: Build.Item['loader']): this { + public setLoader(loader: Loader | `${keyof Loaders & string}`): this { this.loader = loader + if (!this.ident) + this.setIdent(basename(isString(loader) ? loader : loader.getSrc())) return this } @@ -114,17 +151,22 @@ class Item extends Base { */ @bind public toWebpack(): Build.Item.Output { - const loader = this.getLoader() - if (!loader) this.app.error(`missing loader ${loader}`) - const output: Build.Item.Output = { - loader: this.getLoader().getSrc(), + loader: this.getLoader()?.getSrc(), } if (this.options) { output.options = this.getOptions() } + if (this.ident) { + output.ident = this.getIdent() + } + + if (!output.loader) { + this.app.error(`error in ${this.ident}`, `no loader registered`) + } + return output } } diff --git a/sources/@roots/bud-build/src/loader/loader.ts b/sources/@roots/bud-build/src/loader/loader.ts index c6bcd5b76b..d1e45eaa9a 100644 --- a/sources/@roots/bud-build/src/loader/loader.ts +++ b/sources/@roots/bud-build/src/loader/loader.ts @@ -1,4 +1,5 @@ import type {Bud} from '@roots/bud-framework' +import type {Loaders} from '@roots/bud-framework/src/types/services/build/registry' import Base from '../shared/base.js' @@ -13,7 +14,7 @@ export default class Loader extends Base { * * @public */ - public src: string + public src: `${keyof Loaders & string}` /** * Class constructor diff --git a/sources/@roots/bud-build/src/rule/rule.interface.ts b/sources/@roots/bud-build/src/rule/rule.interface.ts deleted file mode 100644 index 5971a2812d..0000000000 --- a/sources/@roots/bud-build/src/rule/rule.interface.ts +++ /dev/null @@ -1,223 +0,0 @@ -import type {Bud} from '@roots/bud-framework/lib/bud' -import type {RuleSetUseItem} from 'webpack' - -import type Build from '../service.js' -import type Base from '../shared/base.js' - -/** - * File parser interface - * - * @public - */ -export interface Parser extends Record {} - -/** - * Options interface - * - * @public - */ -export interface Options { - test?: Instance['test'] - use?: Instance['use'] | ((use: Instance['use']) => Instance['use']) - include?: Instance['include'] - exclude?: Instance['exclude'] - type?: Instance['type'] - parser?: Instance['parser'] - generator?: Instance['generator'] -} - -/** - * Output - * - * @public - */ -export interface Output { - test?: RegExp - use?: { - loader: string - options?: {[key: string]: any} - }[] - include?: Array - exclude?: Array - type?: string - parser?: Parser - generator?: any -} - -export interface Instance extends Base { - /** - * Test pattern - * - * @public - */ - test: ((app: Bud) => RegExp) | RegExp - - /** - * Get the value of `test` - * - * @public - */ - getTest(): RegExp - - /** - * Set the value of `test` - * - * @public - */ - setTest(test: Instance['test']): this - - /** - * Use item - * - * @public - */ - use?: Array<(keyof Build['items'] & string) | RuleSetUseItem> - - /** - * Get the value of `use` - * - * @public - */ - getUse(): Array<(keyof Build['items'] & string) | RuleSetUseItem> - - /** - * Set the value of `use` - * - * @public - */ - setUse( - use: - | (( - use: Array<(keyof Build['items'] & string) | RuleSetUseItem>, - ) => Array<(keyof Build['items'] & string) | RuleSetUseItem>) - | Array<(keyof Build['items'] & string) | RuleSetUseItem>, - ): this - - /** - * Use item - * - * @public - */ - exclude?: Array string | RegExp)> - - /** - * Get the value of `exclude` - * - * @public - */ - getExclude(): Array string | RegExp)> - - /** - * Set the value of `exclude` - * - * @public - */ - setExclude( - excludes: - | (( - excludes: Array< - string | RegExp | ((app: Bud) => string | RegExp) - >, - ) => Array string | RegExp)>) - | Array string | RegExp)>, - ): this - - /** - * Include paths - * - * @public - */ - include?: Array string | RegExp)> - - /** - * Get the value of `include` - * - * @public - */ - getInclude(): this['include'] - - /** - * Set the value of `include` - * - * @public - */ - setInclude( - value: - | ((includes: Instance['include']) => Instance['include']) - | Instance['include'], - ): this - - /** - * Type - * - * @public - */ - type?: ((app: Bud) => string) | string - - /** - * Get the value of `type` - * - * @public - */ - getType(): ((app: Bud) => string) | string - - /** - * Set the value of `type` - * - * @public - */ - setType(type: Instance['type']): this - - /** - * Parser - * - * @public - */ - parser?: ((app: Bud) => Parser) | Parser - - /** - * Get the value of `parser` - * - * @public - */ - getParser(): Parser - - /** - * Set the value of `parser` - * - * @public - */ - setParser(parser: ((app: Bud) => Parser) | Parser): this - - /** - * Generator - * - * @public - */ - generator?: (app: Bud) => any - - /** - * Get the value of `generator` - * - * @public - */ - getGenerator(): any - - /** - * Set the value of `generator` - * - * @public - */ - setGenerator( - Generator: - | ((app: Bud) => Instance['generator']) - | Instance['generator'], - ): this - - /** - * Returns final RuleSetRule - * - * @public - */ - toWebpack(): Output -} diff --git a/sources/@roots/bud-build/src/rule/rule.ts b/sources/@roots/bud-build/src/rule/rule.ts index d13168e288..01fbc36ad3 100644 --- a/sources/@roots/bud-build/src/rule/rule.ts +++ b/sources/@roots/bud-build/src/rule/rule.ts @@ -1,67 +1,71 @@ import type {Bud} from '@roots/bud-framework/bud' +import type { + Interface, + Options, + Output, + Parser, +} from '@roots/bud-framework/services/build/rule' +import type {Item} from '@roots/bud-framework/src/types/services/build/item.js' +import type {Items} from '@roots/bud-framework/src/types/services/build/registry.js' import {bind} from '@roots/bud-support/decorators' import {isFunction, isString} from '@roots/bud-support/lodash-es' -import type {RuleSetUseItem} from 'webpack' -import Item from '../item/item.js' -import type Build from '../service' import Base from '../shared/base.js' -import type {Instance, Options, Output, Parser} from './rule.interface' -export {Instance, Options, Output, Parser} +export {Interface, Options, Output, Parser} /** * Bud Rule * * @public */ -export default class extends Base implements Instance { +export default class Rule extends Base implements Interface { /** * Rule test * * @public */ - public test: Instance['test'] + public test: Interface['test'] /** * {@inheritDoc @roots/bud-framework#Rule.Abstract.use} * * @public */ - public use?: Array<(keyof Build['items'] & string) | RuleSetUseItem> + public use?: Array<`${keyof Items & string}` | Item> /** * Include paths */ - public include?: Instance['include'] + public include?: Options['include'] /** * {@inheritDoc @roots/bud-framework#Rule.Abstract.exclude} * * @public */ - public exclude?: Instance['exclude'] + public exclude?: Options['exclude'] /** * {@inheritDoc @roots/bud-framework#Rule.Abstract."type"} * * @public */ - public type?: Instance['type'] + public type?: Interface['type'] /** * Generator factory * * @public */ - public parser?: Instance['parser'] + public parser?: Interface['parser'] /** * Generator factory * * @public */ - public generator?: Instance['generator'] + public generator?: Interface['generator'] /** * Class constructor @@ -92,7 +96,7 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public getTest(): RegExp { + public getTest(): Output['test'] { return this.unwrap(this.test) } @@ -103,7 +107,7 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public setTest(test: Instance['test']): this { + public setTest(test: Interface['test']): this { this.test = this.wrap(test) return this } @@ -115,7 +119,7 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public getParser(): Parser { + public getParser(): Output['parser'] { return this.unwrap(this.parser) } @@ -126,7 +130,7 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public setParser(parser: Instance['parser']): this { + public setParser(parser: Interface['parser']): this { this.parser = this.wrap(parser) return this } @@ -138,10 +142,8 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public getUse(): Array< - `${`${keyof Build['items'] & string}`}` | RuleSetUseItem - > { - return this.unwrap(this.use)?.filter(Boolean) ?? [] + public getUse(): Array<`${keyof Items & string}` | Item> { + return this.use } /** @@ -153,13 +155,12 @@ export default class extends Base implements Instance { @bind public setUse( input: - | Array<(keyof Build['items'] & string) | RuleSetUseItem> + | Array<`${keyof Items & string}` | Item> | (( - use: Array<(keyof Build['items'] & string) | RuleSetUseItem>, - ) => Array<(keyof Build['items'] & string) | RuleSetUseItem>), + use: Array<`${keyof Items & string}` | Item>, + ) => Array<`${keyof Items & string}` | Item>), ): this { - this.use = isFunction(input) ? input(this.getUse()) : input - + this.use = isFunction(input) ? input(this.getUse() ?? []) : input return this } @@ -170,7 +171,7 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public getInclude(): Instance['include'] { + public getInclude(): Options['include'] { return this.include.map(this.unwrap) } @@ -181,16 +182,10 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public setInclude( - includes: - | ((includes: Instance['include']) => Instance['include']) - | Instance['include'], - ): this { + public setInclude(includes: Options['include']): this { if (!this.include) this.include = [] - if (typeof includes === `function`) - this.include = includes(this.include) - else this.include = includes + this.include = isFunction(includes) ? includes(this.include) : includes return this } @@ -202,7 +197,7 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public getExclude(): Instance['exclude'] { + public getExclude(): Interface['exclude'] { return this.exclude.map(this.unwrap) } @@ -215,13 +210,12 @@ export default class extends Base implements Instance { @bind public setExclude( excludes: - | ((excludes: Instance['exclude']) => Instance['exclude']) - | Instance['exclude'], + | ((excludes: Interface['exclude']) => Interface['exclude']) + | Interface['exclude'], ): this { if (!this.exclude) this.exclude = [] - if (typeof excludes === `function`) - this.exclude = excludes(this.exclude) + if (isFunction(excludes)) this.exclude = excludes(this.exclude) else this.exclude = excludes return this @@ -268,7 +262,7 @@ export default class extends Base implements Instance { * @decorator `@bind` */ @bind - public setGenerator(generator: Instance['generator']): this { + public setGenerator(generator: Interface['generator']): this { this.generator = this.wrap(generator) return this } @@ -293,15 +287,17 @@ export default class extends Base implements Instance { this.generator && Object.assign(output, {generator: this.getGenerator()}) - this.use && + if (this.getUse()) { Object.assign(output, { use: this.getUse() .map(item => isString(item) ? this.app.build.items[item] : item, ) - .map(item => (item instanceof Item ? item.toWebpack() : item)), + .map(item => item.toWebpack()), }) + } + this.app.info(output) return output } } diff --git a/sources/@roots/bud-build/src/service.ts b/sources/@roots/bud-build/src/service.ts index 748a914a92..0a7758a700 100644 --- a/sources/@roots/bud-build/src/service.ts +++ b/sources/@roots/bud-build/src/service.ts @@ -1,5 +1,10 @@ import * as Service from '@roots/bud-framework/service' import type * as Base from '@roots/bud-framework/services/build' +import type { + Items, + Loaders, + Rules, +} from '@roots/bud-framework/src/types/services/build/registry.js' import {bind} from '@roots/bud-support/decorators' import {isFunction, isUndefined} from '@roots/bud-support/lodash-es' import type {Configuration} from 'webpack' @@ -7,7 +12,7 @@ import type {Configuration} from 'webpack' import type {ValueFactory} from './config/builder.js' import * as items from './handlers/items.js' import * as loaders from './handlers/loaders.js' -import * as rules from './handlers/rules.js' +import * as rules from './handlers/rules/rules.js' import Item from './item/item.js' import Loader from './loader/loader.js' import * as Rule from './rule/rule.js' @@ -18,6 +23,9 @@ import * as Rule from './rule/rule.js' * @public */ export default class Build extends Service.Base implements Base.Service { + /** + * @public + */ public static label = `build` /** @@ -30,21 +38,21 @@ export default class Build extends Service.Base implements Base.Service { * * @public */ - public loaders: Record = {} + public loaders: Record<`${keyof Loaders & string}`, Loader> = {} /** * Registered rules * * @public */ - public rules: Record = {} + public rules: Record<`${keyof Rules & string}`, Rule.Interface> = {} /** * Registered items * * @public */ - public items: Record = {} + public items: Record<`${keyof Items & string}`, Item> = {} /** * Make webpack configuration @@ -94,30 +102,25 @@ export default class Build extends Service.Base implements Base.Service { */ @bind public async register() { - await Promise.all( - Object.entries(rules).map(async ([key, ruleFactory]) => { - const value = await ruleFactory(this) - this.rules[key] = value - }), - ) + Object.entries(loaders).map(([key, loaderFactory]) => { + const value = loaderFactory(this.app) + this.setLoader(key, value) + }) - await Promise.all( - Object.entries(items).map(async ([key, itemFactory]) => { - const value = await itemFactory(this.app) - this.items[key] = value as Item - }), - ) + Object.entries(items).map(([key, itemFactory]) => { + const value = itemFactory(this.app) + this.setItem(key, value as any) + }) this.items.precss = this.app.isProduction ? this.items.minicss : this.items.style - await Promise.all( - Object.entries(loaders).map(async ([key, loaderFactory]) => { - const value = await loaderFactory(this.app) - this.loaders[key] = value as Loader - }), - ) + Object.entries(rules) + .reverse() + .map(([key, ruleFactory]) => { + this.setRule(key, ruleFactory(this.app)) + }) } /** @@ -131,12 +134,20 @@ export default class Build extends Service.Base implements Base.Service { * @decorator `@bind` */ @bind - public setRule(name: string, options?: Rule.Options): this { - const processedOptions = isFunction(options) - ? options(this.makeRule()) - : this.makeRule(options) + public setRule( + name: K, + options?: Rule.Options | Rule.Interface, + ): this { + if (options instanceof Rule.default) { + this.rules[name] = options + this.logger.info(`set rule`, name, this.rules[name]) + return this + } - Object.assign(this.rules, {[name]: processedOptions}) + this.rules[name] = isFunction(options) + ? options(this.makeRule()) + : this.makeRule(options as any) + this.logger.info(`set rule`, name, this.rules[name]) return this } @@ -151,23 +162,43 @@ export default class Build extends Service.Base implements Base.Service { * @decorator `@bind` */ @bind - public makeRule(options?: Rule.Options): Rule.Instance { + public makeRule(options?: Rule.Options): Rule.Interface { return new Rule.default(() => this.app, options) } + @bind + public getLoader(name: string): Loader { + if (!this.loaders[name]) + this.logger.error( + `loader ${name} was requested but is not registered`, + ) + + return this.loaders[name] + } + /** * Set Loader * * @param name - Loader key - * @param options - Loader constructor properties + * @param definition - Loader constructor properties * @returns the Loader * * @public * @decorator `@bind` */ @bind - public setLoader(name: string, options?: string): this { - Object.assign(this.loaders, {[name]: this.makeLoader(options ?? name)}) + public setLoader( + name: K, + definition?: string | Loader, + ): this { + const loader = isUndefined(definition) + ? this.makeLoader(name) + : definition instanceof Loader + ? definition + : this.makeLoader(definition) + + this.loaders[name] = loader + this.logger.info(`set loader`, loader) return this } @@ -182,8 +213,18 @@ export default class Build extends Service.Base implements Base.Service { * @decorator `@bind` */ @bind - public makeLoader(options: string): Loader { - return new Loader(() => this.app, options) + public makeLoader(src: string): Loader { + return new Loader(() => this.app, src) + } + + @bind + public getItem(name: `${keyof Items & string}`): Item { + if (!this.items[name]) + this.logger.error( + `loader ${name} was requested but is not registered`, + ) + + return this.items[name] } /** @@ -197,19 +238,20 @@ export default class Build extends Service.Base implements Base.Service { * @decorator `@bind` */ @bind - public setItem( - name: string, + public setItem( + name: K, options?: Item | ((item: Item) => Item), ): this { const maybeOptionsCallback = isUndefined(options) - ? {loader: name} + ? {ident: name, loader: name} : options const item = isFunction(maybeOptionsCallback) ? maybeOptionsCallback(this.makeItem()) : this.makeItem(maybeOptionsCallback) - Object.assign(this.items, {[name]: item}) + this.items[name] = item + this.logger.info(`set item`, item) return this } diff --git a/sources/@roots/bud-cache/src/invalidate-cache-extension/index.ts b/sources/@roots/bud-cache/src/invalidate-cache-extension/index.ts index c2198a300e..61c21af9be 100644 --- a/sources/@roots/bud-cache/src/invalidate-cache-extension/index.ts +++ b/sources/@roots/bud-cache/src/invalidate-cache-extension/index.ts @@ -34,8 +34,9 @@ export default class InvalidateCacheExtension extends Extension { @bind public async register() { const invalidate = await fs.pathExists(this.file) - if (this.app.context.args.flush === true || invalidate) { + if (invalidate || this.app.context.args.flush) { await fs.remove(this.file) + await fs.remove(this.app.path(`@storage`, this.app.label, `cache`)) } this.app.hooks.action(`compiler.after`, async () => { diff --git a/sources/@roots/bud-emotion/package.json b/sources/@roots/bud-emotion/package.json index cb187fbfc4..0c8043096c 100644 --- a/sources/@roots/bud-emotion/package.json +++ b/sources/@roots/bud-emotion/package.json @@ -61,7 +61,7 @@ } }, "devDependencies": { - "@babel/core": "7.18.10", + "@babel/core": "7.19.1", "@jest/globals": "29.0.1", "@skypack/package-check": "0.2.2", "@types/node": "16.11.48", diff --git a/sources/@roots/bud-emotion/src/extension.ts b/sources/@roots/bud-emotion/src/extension.ts index d90a7adabf..d0240a36f6 100644 --- a/sources/@roots/bud-emotion/src/extension.ts +++ b/sources/@roots/bud-emotion/src/extension.ts @@ -23,7 +23,6 @@ export default class BudEmotion extends Extension { */ @bind public async buildBefore() { - const plugin = await this.resolve(`@emotion/babel-plugin`) - this.app.babel.setPlugin(`@emotion/babel-plugin`, plugin) + this.app.babel.setPlugin(`@emotion/babel-plugin`) } } diff --git a/sources/@roots/bud-eslint/src/extension.ts b/sources/@roots/bud-eslint/src/extension.ts index 9bcf33716a..d7d004d373 100644 --- a/sources/@roots/bud-eslint/src/extension.ts +++ b/sources/@roots/bud-eslint/src/extension.ts @@ -24,8 +24,9 @@ import EslintPlugin from 'eslint-webpack-plugin' @options({ extensions: [`js`, `jsx`, `ts`, `tsx`, `vue`], cacheLocation: app => app.path(`@storage`, app.label, `cache`, `eslint`), - cwd: app => app.path(), - resolvePluginsRelativeTo: app => app.path(), + fix: false, + cwd: app => app.context.basedir, + resolvePluginsRelativeTo: app => app.context.basedir, threads: false, }) export default class BudEslint extends Extension { diff --git a/sources/@roots/bud-framework/src/bud.ts b/sources/@roots/bud-framework/src/bud.ts index 5d8745a2da..d04a1d5976 100644 --- a/sources/@roots/bud-framework/src/bud.ts +++ b/sources/@roots/bud-framework/src/bud.ts @@ -6,8 +6,8 @@ import { isUndefined, } from '@roots/bud-support/lodash-es' +import {override} from './lifecycle/args.js' import {bootstrap, LIFECYCLE_EVENT_MAP} from './lifecycle/bootstrap.js' -import {override} from './lifecycle/init.js' import type {Logger} from './logger' import type * as methods from './methods/index.js' import type {Module} from './module' @@ -188,6 +188,8 @@ export class Bud { public sequenceSync: methods.sequenceSync + public sh: methods.sh + public tap: methods.tap public tapAsync: methods.tapAsync @@ -289,7 +291,8 @@ export class Bud { .finally(() => logger.success(event)) }, Promise.resolve()) - this.hooks.action(`config.after`, override) + this.hooks.action(`booted`, override) + this.hooks.action(`build.before`, override) return this } diff --git a/sources/@roots/bud-framework/src/lifecycle/args.ts b/sources/@roots/bud-framework/src/lifecycle/args.ts index 2a53da7c90..e6b5423f83 100644 --- a/sources/@roots/bud-framework/src/lifecycle/args.ts +++ b/sources/@roots/bud-framework/src/lifecycle/args.ts @@ -2,22 +2,6 @@ import {isUndefined} from '@roots/bud-support/lodash-es' import type {Bud} from '../bud' -/** - * --target override - * - * @remarks - * This override should always be first. - * - * No reason to handle child instances which are slated - * to be discarded. - * - * @public - */ -const target = (app: Bud) => - Object.keys(app.children).reduce((state, name) => { - return !app.context.args.target.includes(name) ? false : state - }, true) - /** * Returns true if the given value is neither null nor undefined. * @@ -30,8 +14,52 @@ const isset = (value: unknown): boolean => !isUndefined(value) * * @public */ -export const buildBefore = async (app: Bud) => { - if (isset(app.context.args.target) && !target(app)) return +export const override = async (app: Bud) => { + if (app.isRoot && isset(app.context.args.target)) + Object.keys(app.children) + .filter(name => !app.context.args.target.includes(name)) + .map(name => delete app.children[name]) + + if (isset(app.context.args.publicPath)) + app.hooks.on(`build.output.publicPath`, app.context.args.publicPath) + else if (isset(app.context.manifest?.bud?.publicPath)) + app.hooks.on( + `build.output.publicPath`, + app.context.manifest.bud.publicPath, + ) + + if (isset(app.context.args.input)) + app.hooks.on(`location.@src`, app.context.args.input) + else if (isset(app.context.manifest?.bud?.paths?.[`@src`])) + app.hooks.on(`location.@src`, app.context.manifest.bud.paths[`@src`]) + + if (isset(app.context.args.output)) + app.hooks.on(`location.@dist`, app.context.args.output) + else if (isset(app.context.manifest?.bud?.paths?.[`@dist`])) + app.hooks.on(`location.@dist`, app.context.manifest.bud.paths[`@dist`]) + + if (isset(app.context.args.storage)) + app.hooks.on(`location.@storage`, app.context.args.storage) + else if (isset(app.context.manifest?.bud?.paths?.[`@storage`])) + app.hooks.on( + `location.@storage`, + app.context.manifest?.bud.paths[`@storage`], + ) + + if (isset(app.context.args.mode)) + app.hooks.on(`build.mode`, app.context.args.mode) + + if (isset(app.context.args.clean)) + app.hooks.on(`feature.clean`, app.context.args.clean) + else if (isset(app.context.manifest?.bud?.clean)) + app.hooks.on(`feature.clean`, app.context.manifest?.bud.clean) + + if (isset(app.context.args.minimize)) + app.api.call(`minimize`, app.context.args.minimize) + + if (isset(app.context.args.html)) { + await app.api.call(`template`) + } if (isset(app.context.args.input)) { app.setPath(`@src`, app.context.args.input) diff --git a/sources/@roots/bud-framework/src/lifecycle/init.ts b/sources/@roots/bud-framework/src/lifecycle/init.ts index 7f7433b99a..b1c8512140 100644 --- a/sources/@roots/bud-framework/src/lifecycle/init.ts +++ b/sources/@roots/bud-framework/src/lifecycle/init.ts @@ -1,5 +1,5 @@ -import {isUndefined} from '@roots/bud-support/lodash-es' import {cpus} from 'os' +import {join} from 'path' import type {Bud} from '../bud' @@ -23,7 +23,7 @@ export const initialize = (app: Bud): Bud => 'value.fileFormat': `[name]`, 'value.hashFormat': `[name].[contenthash:6]`, - 'pattern.js': /\.(cjs|mjs|jsx?)$/, + 'pattern.js': /\.(mjs|jsx?)$/, 'pattern.ts': /\.(tsx?)$/, 'pattern.sass': /\.(scss|sass)$/, 'pattern.sassModule': /\.module\.(scss|sass)$/, @@ -44,10 +44,10 @@ export const initialize = (app: Bud): Bud => 'pattern.json': /\.json$/, 'pattern.json5': /\.json5$/, - 'location.@src': `src`, - 'location.@dist': `dist`, - 'location.@storage': `.budfiles`, - 'location.@modules': `node_modules`, + 'location.@src': app.context.args.input ?? `src`, + 'location.@dist': app.context.args.output ?? `dist`, + 'location.@storage': app.context.args.storage ?? `.budfiles`, + 'location.@modules': app.context.args.modules ?? `node_modules`, 'build.bail': app.isProduction, 'build.cache': () => app.cache.configuration, @@ -57,7 +57,7 @@ export const initialize = (app: Bud): Bud => 'build.module.rules.before': () => [ { test: app.hooks.filter(`pattern.js`), - include: [app.path(`@src`)], + include: [app.context.basedir], parser: {requireEnsure: false}, }, ], @@ -74,7 +74,7 @@ export const initialize = (app: Bud): Bud => 'build.optimization.minimize': false, 'build.optimization.removeEmptyChunks': true, 'build.output.chunkFilename': () => `js/dynamic/[id].js`, - 'build.output.filename': () => `js/${filenameFormat(app)}`, + 'build.output.filename': () => join(`js`, filenameFormat(app)), 'build.output.path': () => app.path(`@dist`), 'build.output.publicPath': `auto`, 'build.parallelism': 10 * Math.max(cpus().length - 1, 1), @@ -83,32 +83,18 @@ export const initialize = (app: Bud): Bud => app.path(`@storage`, app.label, `modules.json`), 'build.resolve.extensions': new Set([ `.mjs`, - `.cjs`, `.js`, `.jsx`, `.css`, `.json`, `.wasm`, `.yml`, - `.toml`, ]), 'build.stats': {preset: `errors-only`}, 'build.target': () => app.context.manifest?.browserslist ? `browserslist:${app.context.config[`package.json`]?.path}` : `web`, - 'dev.middleware.dev.options.writeToDisk': true, - 'dev.middleware.dev.options.publicPath': () => - app.hooks.filter(`build.output.publicPath`), - 'dev.middleware.dev.options.headers': { - 'Access-Control-Allow-Origin': `*`, - 'Access-Control-Allow-Headers': `*`, - 'x-powered-by': `@roots/bud`, - }, - 'dev.middleware.enabled': [`dev`, `hot`], - 'dev.url': new URL(`http://0.0.0.0:3000`), - 'dev.watch.files': new Set([]), - 'dev.watch.options': {}, }) .hooks.fromAsyncMap({ 'build.plugins': async () => await app.extensions.make(), @@ -121,67 +107,23 @@ export const initialize = (app: Bud): Bud => app.hooks.filter(`location.@modules`), ], }) - -export const override = async (app: Bud): Promise => { - if (app.isRoot && isset(app.context.args.target)) - Object.keys(app.children) - .filter(name => !app.context.args.target.includes(name)) - .map(name => delete app.children[name]) - - if (isset(app.context.args.publicPath)) - app.hooks.on(`build.output.publicPath`, app.context.args.publicPath) - else if (isset(app.context.manifest?.bud?.publicPath)) - app.hooks.on( - `build.output.publicPath`, - app.context.manifest.bud.publicPath, - ) - - if (isset(app.context.args.input)) - app.hooks.on(`location.@src`, app.context.args.input) - else if (isset(app.context.manifest?.bud?.paths?.[`@src`])) - app.hooks.on(`location.@src`, app.context.manifest.bud.paths[`@src`]) - - if (isset(app.context.args.output)) - app.hooks.on(`location.@dist`, app.context.args.output) - else if (isset(app.context.manifest?.bud?.paths?.[`@dist`])) - app.hooks.on(`location.@dist`, app.context.manifest.bud.paths[`@dist`]) - - if (isset(app.context.args.storage)) - app.hooks.on(`location.@storage`, app.context.args.storage) - else if (isset(app.context.manifest?.bud?.paths?.[`@storage`])) - app.hooks.on( - `location.@storage`, - app.context.manifest?.bud.paths[`@storage`], + .when(app.isDevelopment, ({hooks}) => + hooks.fromMap({ + 'dev.middleware.dev.options.writeToDisk': true, + 'dev.middleware.dev.options.publicPath': () => + app.hooks.filter(`build.output.publicPath`), + 'dev.middleware.dev.options.headers': { + 'Access-Control-Allow-Origin': `*`, + 'Access-Control-Allow-Headers': `*`, + 'x-powered-by': `@roots/bud`, + }, + 'dev.middleware.enabled': [`dev`, `hot`], + 'dev.url': new URL(`http://0.0.0.0:3000`), + 'dev.watch.files': new Set([]), + 'dev.watch.options': {}, + }), ) - if ( - isset(app.context.manifest?.bud?.cache) && - isUndefined(app.context.args.cache) - ) - app.context.args.cache = app.context.manifest?.bud.cache - - if (isset(app.context.args.mode)) - app.hooks.on(`build.mode`, app.context.args.mode) - - if (isset(app.context.args.clean)) - app.hooks.on(`feature.clean`, app.context.args.clean) - else if (isset(app.context.manifest?.bud?.clean)) - app.hooks.on(`feature.clean`, app.context.manifest?.bud.clean) - - if (isset(app.context.args.html)) { - await app.api.call(`template`) - } - - return app -} - -/** - * Returns true if the given value is neither null nor undefined. - * - * @public - */ -const isset = (value: unknown): boolean => !isUndefined(value) - /** * Filename * diff --git a/sources/@roots/bud-framework/src/logger/logger.constants.ts b/sources/@roots/bud-framework/src/logger/logger.constants.ts index 92130d1f7a..5fb150ffca 100644 --- a/sources/@roots/bud-framework/src/logger/logger.constants.ts +++ b/sources/@roots/bud-framework/src/logger/logger.constants.ts @@ -11,7 +11,7 @@ export const configDefaults: SignaleConfig = { displayBadge: true, displayDate: false, displayFilename: false, - displayLabel: false, + displayLabel: true, displayTimestamp: false, underlineLabel: false, underlineMessage: false, @@ -46,28 +46,28 @@ export const types = { label: `warning`, logLevel: LEVEL[`vv`], }, - info: { - badge: figures.info, - color: `magenta`, - label: `log`, - logLevel: LEVEL[`vvvv`], - }, success: { badge: figures.tick, color: `green`, label: `success`, logLevel: LEVEL[`vvv`], }, - debug: { - badge: figures.circleFilled, - color: `red`, - label: `log`, - logLevel: LEVEL[`vvvv`], - }, log: { badge: ``, color: `blue`, label: `log`, logLevel: LEVEL[`vvv`], }, + info: { + badge: figures.info, + color: `magenta`, + label: `log`, + logLevel: LEVEL[`vvvv`], + }, + debug: { + badge: figures.circleFilled, + color: `red`, + label: `log`, + logLevel: LEVEL[`vvvv`], + }, } diff --git a/sources/@roots/bud-framework/src/methods/index.ts b/sources/@roots/bud-framework/src/methods/index.ts index c46ed3050e..889f0d9d89 100644 --- a/sources/@roots/bud-framework/src/methods/index.ts +++ b/sources/@roots/bud-framework/src/methods/index.ts @@ -12,6 +12,7 @@ import {run} from './run.js' import {sequence, sequenceSync} from './sequence.js' import {setPath} from './setPath.js' import {setPublicPath} from './setPublicPath.js' +import {sh} from './sh.js' import {tap, tapAsync} from './tap.js' import {when} from './when.js' @@ -32,6 +33,7 @@ export { sequenceSync, setPath, setPublicPath, + sh, tap, tapAsync, when, diff --git a/sources/@roots/bud-framework/src/methods/sh.ts b/sources/@roots/bud-framework/src/methods/sh.ts new file mode 100644 index 0000000000..692bfeb9ea --- /dev/null +++ b/sources/@roots/bud-framework/src/methods/sh.ts @@ -0,0 +1,36 @@ +import execa, {ExecaChildProcess, Options} from '@roots/bud-support/execa' + +import type {Bud} from '../bud' + +export interface sh { + (command: string | Array, options?: Options): ExecaChildProcess +} + +/** + * Execute a shell command + * + * @example + * ```js + * bud.sh(`ls -la`) + * ``` + * + * @public + */ +export const sh: sh = function ( + command: string | Array, + options = {}, +) { + const bud = this as Bud + const commandInput = (Array.isArray(command) ? command : [command]) + .map(str => str.split(` `)) + .flat() + + const child = execa(commandInput.shift(), commandInput.filter(Boolean), { + cwd: bud.context.basedir, + ...options, + }) + + child.stdout?.pipe(process.stdout) + child.stderr?.pipe(process.stderr) + return child +} diff --git a/sources/@roots/bud-framework/src/types/services/build/index.ts b/sources/@roots/bud-framework/src/types/services/build/index.ts index 29f0d81fe3..b06c1b2716 100644 --- a/sources/@roots/bud-framework/src/types/services/build/index.ts +++ b/sources/@roots/bud-framework/src/types/services/build/index.ts @@ -43,21 +43,21 @@ export interface Service extends BaseService { * * @public */ - loaders: Record + loaders: Record<`${keyof Loaders & string}`, Loader> /** * Arrayed {@link Item} instances * * @public */ - items: Record + items: Record<`${keyof Items & string}`, Item> /** * Arrayed {@link Rule} instances * * @public */ - rules: Record + rules: Record<`${keyof Rules & string}`, Rule.Interface> /** * Compiler configuration @@ -78,7 +78,17 @@ export interface Service extends BaseService { * * @public */ - setLoader(name: string, options?: string): Service + getLoader(name: K): Loaders[K] + + /** + * Set a {@link Loader} instance + * + * @public + */ + setLoader( + name: K, + options?: string | Loader, + ): Service /** * Make a {@link Loader} instance @@ -92,27 +102,32 @@ export interface Service extends BaseService { * * @public */ - setRule( - name: string, - options?: - | Partial - | ((item: Rule.Interface) => Rule.Interface), - ): Service + setRule( + name: K, + options?: Rule.Options | Rule.Interface, + ): this /** * Make a new {@link Rule} instance * * @public */ - makeRule(options?: Partial): Rule.Interface + makeRule(options?: Partial | Rule.Output): Rule.Interface + + /** + * Get a {@link Item} instance + * + * @public + */ + getItem(name: K): Items[K] /** * Set a {@link Item} instance * * @public */ - setItem( - name: string, + setItem( + name: K, options?: Partial | ((item: Item) => Item), ): Service diff --git a/sources/@roots/bud-framework/src/types/services/build/item.ts b/sources/@roots/bud-framework/src/types/services/build/item.ts index eb3c2b767f..94dd6e8e50 100644 --- a/sources/@roots/bud-framework/src/types/services/build/item.ts +++ b/sources/@roots/bud-framework/src/types/services/build/item.ts @@ -9,6 +9,12 @@ import type {Loaders} from './registry' * @public */ export interface Item extends Base { + /** + * identifier + * @public + */ + ident: string + /** * Key from {@link Loaders} registry * @@ -17,16 +23,14 @@ export interface Item extends Base { * * @public */ - loader: - | `${keyof Loaders & string}` - | ((app: Bud) => `${keyof Loaders & string}`) + loader: `${keyof Loaders & string}` | Loader /** * Set the {@link Loaders} key * * @public */ - setLoader(loader: Item['loader']): this + setLoader(loader: `${keyof Loaders & string}` | Loader): this /** * Get the associated {@link Loader} instance @@ -35,6 +39,20 @@ export interface Item extends Base { */ getLoader(): Loader + /** + * Set the {@link Loaders} key + * + * @public + */ + setIdent(ident: string): this + + /** + * Get the associated {@link Ident} instance + * + * @public + */ + getIdent(): string + /** * Associated {@link Loader} options * @@ -101,17 +119,16 @@ export namespace Item { */ export interface Output { /** - * Finalized loader - * - * @public + * Unique loader options identifier. */ - loader: string - + ident?: string /** - * Finalized options - * - * @public + * Loader name. */ - options?: Item.Options + loader?: string + /** + * Loader options. + */ + options?: string | {[index: string]: any} } } diff --git a/sources/@roots/bud-framework/src/types/services/build/loader.ts b/sources/@roots/bud-framework/src/types/services/build/loader.ts index 19126b019e..9f022559b3 100644 --- a/sources/@roots/bud-framework/src/types/services/build/loader.ts +++ b/sources/@roots/bud-framework/src/types/services/build/loader.ts @@ -1,5 +1,6 @@ import type {Bud} from '../../../bud' import type {Base} from './base' +import type {Loaders} from './registry' /** * Loader interface @@ -17,7 +18,7 @@ export interface Loader extends Base { * Loader source factory * @public */ - src: string | ((app: Bud) => string) + src: `${keyof Loaders & string}` /** * Set src diff --git a/sources/@roots/bud-framework/src/types/services/build/rule.ts b/sources/@roots/bud-framework/src/types/services/build/rule.ts index 96954a6dc0..62554febdf 100644 --- a/sources/@roots/bud-framework/src/types/services/build/rule.ts +++ b/sources/@roots/bud-framework/src/types/services/build/rule.ts @@ -1,7 +1,8 @@ -import type {RuleSetUseItem} from 'webpack' +import type {RuleSetRule} from 'webpack' import type {Bud} from '../../../bud' import type {Base} from './base' +import type {Item} from './item' import type * as Build from './registry' /** @@ -17,13 +18,17 @@ export interface Parser extends Record {} * @public */ export interface Options { - test?: Interface['test'] - use?: Interface['use'] | ((use: Interface['use']) => Interface['use']) - include?: Interface['include'] - exclude?: Interface['exclude'] - type?: Interface['type'] - parser?: Interface['parser'] - generator?: Interface['generator'] + test?: ((app: Bud) => Output['test']) | Output['test'] + use?: + | (( + loaders: Array, + ) => Array) + | Array + include?: Array<((app: Bud) => string | RegExp) | string | RegExp> + exclude?: Array<((app: Bud) => string | RegExp) | string | RegExp> + type?: ((app: Bud) => Output['type']) | Output['type'] + parser?: ((app: Bud) => Output['parser']) | Output['parser'] + generator?: ((app: Bud) => Output['generator']) | Output['generator'] } /** @@ -31,17 +36,9 @@ export interface Options { * * @public */ -export interface Output { - test?: RegExp - use?: { - loader: string - options?: {[key: string]: any} - }[] +export interface Output extends RuleSetRule { include?: Array exclude?: Array - type?: string - parser?: Parser - generator?: any } export interface Interface extends Base { @@ -50,35 +47,35 @@ export interface Interface extends Base { * * @public */ - test: ((app: Bud) => RegExp) | RegExp + test: Options['test'] /** * Get the value of `test` * * @public */ - getTest(): RegExp + getTest(): Options['test'] /** * Set the value of `test` * * @public */ - setTest(test: Interface['test']): this + setTest(test: Options['test']): this /** * Use item * * @public */ - use?: Array<(keyof Build.Items & string) | RuleSetUseItem> + use?: Array<`${keyof Build.Items & string}` | Item> /** * Get the value of `use` * * @public */ - getUse(): Array<(keyof Build.Items & string) | RuleSetUseItem> + getUse(): Array<`${keyof Build.Items & string}` | Item> /** * Set the value of `use` @@ -87,10 +84,10 @@ export interface Interface extends Base { */ setUse( use: + | Array<`${keyof Build.Items & string}` | Item> | (( - use: Array<(keyof Build.Items & string) | RuleSetUseItem>, - ) => Array<(keyof Build.Items & string) | RuleSetUseItem>) - | Array<(keyof Build.Items & string) | RuleSetUseItem>, + use: Array<`${keyof Build.Items & string}` | Item>, + ) => Array<`${keyof Build.Items & string}` | Item>), ): this /** @@ -98,121 +95,105 @@ export interface Interface extends Base { * * @public */ - exclude?: Array string | RegExp)> + exclude?: Options['exclude'] /** * Get the value of `exclude` * * @public */ - getExclude(): Array string | RegExp)> + getExclude(): Options['exclude'] /** * Set the value of `exclude` * * @public */ - setExclude( - excludes: - | (( - excludes: Array< - string | RegExp | ((app: Bud) => string | RegExp) - >, - ) => Array string | RegExp)>) - | Array string | RegExp)>, - ): this + setExclude(excludes: Options['exclude']): this /** * Include paths * * @public */ - include?: Array string | RegExp)> + include?: Options['include'] /** * Get the value of `include` * * @public */ - getInclude(): this['include'] + getInclude(): Options['include'] /** * Set the value of `include` * * @public */ - setInclude( - value: - | ((includes: Interface['include']) => Interface['include']) - | Interface['include'], - ): this + setInclude(value: Options['include']): this /** * Type * * @public */ - type?: ((app: Bud) => string) | string + type?: Options['type'] /** * Get the value of `type` * * @public */ - getType(): ((app: Bud) => string) | string + getType(): Options['type'] /** * Set the value of `type` * * @public */ - setType(type: Interface['type']): this + setType(type: Options['type']): this /** * Parser * * @public */ - parser?: ((app: Bud) => Parser) | Parser + parser?: Options['parser'] /** * Get the value of `parser` * * @public */ - getParser(): Parser + getParser(): Options['parser'] /** * Set the value of `parser` * * @public */ - setParser(parser: ((app: Bud) => Parser) | Parser): this + setParser(parser: Options['parser']): this /** * Generator * * @public */ - generator?: (app: Bud) => any + generator?: Options['generator'] /** * Get the value of `generator` * * @public */ - getGenerator(): any + getGenerator(): Options['generator'] /** * Set the value of `generator` * * @public */ - setGenerator( - Generator: - | ((app: Bud) => Interface['generator']) - | Interface['generator'], - ): this + setGenerator(Generator: Options['generator']): this /** * Returns final RuleSetRule diff --git a/sources/@roots/bud-framework/src/types/services/hooks.ts b/sources/@roots/bud-framework/src/types/services/hooks.ts index 228d39325b..d68e19ca3e 100644 --- a/sources/@roots/bud-framework/src/types/services/hooks.ts +++ b/sources/@roots/bud-framework/src/types/services/hooks.ts @@ -31,12 +31,29 @@ import type * as Hooks from '../registry' * @public */ export interface Service extends BaseService { + /** + * Async hooks value store + * @public + */ asyncStore: any + /** + * Sync hooks value store + * @public + */ syncStore: any + + /** + * Events value store + * @public + */ events: any hasSyncHook: (hook: keyof Hooks.SyncStore) => boolean + hasAsyncHook: (hook: keyof Hooks.AsyncStore) => boolean + + hasEvent: (hook: keyof Hooks.EventsStore) => boolean + /** * Register a function or value to modify or replace a filtered value * diff --git a/sources/@roots/bud-hooks/src/index.ts b/sources/@roots/bud-hooks/src/index.ts index 8231e274a8..5518c62c13 100644 --- a/sources/@roots/bud-hooks/src/index.ts +++ b/sources/@roots/bud-hooks/src/index.ts @@ -11,4 +11,5 @@ */ import Hooks from './service.js' -export {Hooks as default} + +export default Hooks diff --git a/sources/@roots/bud-hooks/src/service.ts b/sources/@roots/bud-hooks/src/service.ts index 0024cec11b..ac2b7d1284 100644 --- a/sources/@roots/bud-hooks/src/service.ts +++ b/sources/@roots/bud-hooks/src/service.ts @@ -73,6 +73,10 @@ export default class Hooks extends Service implements HooksInterface { public hasSyncHook: SyncHooks['has'] + public hasAsyncHook: AsyncHooks['has'] + + public hasEvent: EventHooks['has'] + public async: AsyncHooks['set'] public filterAsync: AsyncHooks['get'] diff --git a/sources/@roots/bud-postcss/src/extension.ts b/sources/@roots/bud-postcss/src/extension.ts index c112dec603..9db7f1529e 100644 --- a/sources/@roots/bud-postcss/src/extension.ts +++ b/sources/@roots/bud-postcss/src/extension.ts @@ -329,10 +329,12 @@ export default class BudPostCss extends Extension { @once public async register() { this.setPlugins({ - import: `postcss-import`, - nesting: `postcss-nested`, + import: await this.resolve(`postcss-import`), + nesting: await this.resolve(`postcss-nested`), env: [ - `postcss-preset-env`, + await this.resolve(`postcss-preset-env`).then(path => + path.replace(`.mjs`, `.cjs`), + ), { stage: 1, features: { @@ -342,18 +344,17 @@ export default class BudPostCss extends Extension { ], }) - this.app.build.setLoader(`postcss-loader`).setItem(`postcss`, { - loader: `postcss-loader`, - options: () => ({ - sourceMap: this.sourceMap, - postcssOptions: this.postcssOptions, - }), - }) + this.app.build + .setLoader(`postcss`, await this.resolve(`postcss-loader`)) + .setItem(`postcss`, { + loader: `postcss`, + options: () => ({ + sourceMap: this.sourceMap, + postcssOptions: this.postcssOptions, + }), + }) - this.app.build.rules.css?.setUse(items => [ - ...(items ?? []), - `postcss`, - ]) + this.app.build.rules.css.setUse(items => [...(items ?? []), `postcss`]) this.app.build.rules.cssModule?.setUse(items => [ ...(items ?? []), `postcss`, diff --git a/sources/@roots/bud-react/package.json b/sources/@roots/bud-react/package.json index 3aeb9c133b..b80ca8cdb5 100644 --- a/sources/@roots/bud-react/package.json +++ b/sources/@roots/bud-react/package.json @@ -78,7 +78,7 @@ } }, "devDependencies": { - "@babel/core": "7.18.10", + "@babel/core": "7.19.1", "@jest/globals": "29.0.1", "@roots/bud-api": "workspace:sources/@roots/bud-api", "@roots/bud-swc": "workspace:sources/@roots/bud-swc", diff --git a/sources/@roots/bud-solid/package.json b/sources/@roots/bud-solid/package.json index 761291e525..92cbba51f4 100644 --- a/sources/@roots/bud-solid/package.json +++ b/sources/@roots/bud-solid/package.json @@ -51,7 +51,7 @@ } }, "devDependencies": { - "@babel/core": "7.18.10", + "@babel/core": "7.19.1", "@jest/globals": "29.0.1", "@roots/bud-api": "workspace:sources/@roots/bud-api", "@skypack/package-check": "0.2.2", diff --git a/sources/@roots/bud-support/README.md b/sources/@roots/bud-support/README.md index 9019788a39..a403761e1b 100644 --- a/sources/@roots/bud-support/README.md +++ b/sources/@roots/bud-support/README.md @@ -1,53 +1,74 @@ -

- Bud -

+

bud.js

- MIT License npm Follow Roots + MIT License + npm + Follow Roots

-

- @roots/bud-support -

+

@roots/bud-support

👨🏽‍🍳 Internal packages for @roots/bud

+--- + ## Installation Install **@roots/bud-support** to your project. -```shell +Yarn: + +```sh yarn add @roots/bud-support --dev ``` -## Documentation +npm: + +```sh +npm install @roots/bud-support --save-dev +``` + +## Usage + +## Contributing + +Contributions are welcome from everyone. + +We have [contribution guidelines](https://github.com/roots/guidelines/blob/master/CONTRIBUTING.md) to help you get started. -For more information on utilizing this package [check out our dedicated docs](https://bud.js.org) +## License + +@roots/bud-support is licensed under MIT. ## Community Keep track of development and community news. -- Join us on Roots Slack by becoming a [GitHub sponsor](https://github.com/sponsors/roots) +- Join us on Roots Slack by becoming a [GitHub + sponsor](https://github.com/sponsors/roots) - Participate on the [Roots Discourse](https://discourse.roots.io/) - Follow [@rootswp on Twitter](https://twitter.com/rootswp) - Read and subscribe to the [Roots Blog](https://roots.io/blog/) - Subscribe to the [Roots Newsletter](https://roots.io/subscribe/) -## Contributing - -Contributions are welcome from everyone. - -We have [contribution guidelines](https://github.com/roots/guidelines/blob/master/CONTRIBUTING.md) to help you get started. - ## Sponsors Help support our open-source development efforts by [becoming a patron](https://www.patreon.com/rootsdev). -KM Digital -Carrot -C21 Redwood Realty -WordPress.com -Pantheon + +KM Digital + + +Carrot + + +C21 Redwood Realty + + +WordPress.com + + +Pantheon + diff --git a/sources/@roots/bud-support/src/execa/index.js b/sources/@roots/bud-support/src/execa/index.js index aa9039a5fd..5c7404a721 100644 --- a/sources/@roots/bud-support/src/execa/index.js +++ b/sources/@roots/bud-support/src/execa/index.js @@ -1,2 +1,4 @@ -import {execa} from 'execa' +import {execa, ExecaChildProcess, Options} from 'execa' + export default execa +export {ExecaChildProcess, Options} diff --git a/sources/@roots/bud-swc/src/extension.ts b/sources/@roots/bud-swc/src/extension.ts index 46b35b6666..4504449207 100644 --- a/sources/@roots/bud-swc/src/extension.ts +++ b/sources/@roots/bud-swc/src/extension.ts @@ -70,9 +70,9 @@ export default class BudSWC extends Extension { }, })) }) - .finally(async () => { + .finally(() => { bud.build - .setLoader(`swc`, await this.resolve(`swc-loader`)) + .setLoader(`swc`, `swc-loader`) .setItem(`swc`, { loader: `swc`, options: this.options, diff --git a/sources/@roots/bud-tailwindcss/src/extension.ts b/sources/@roots/bud-tailwindcss/src/extension.ts index ec74aad586..be28a85642 100644 --- a/sources/@roots/bud-tailwindcss/src/extension.ts +++ b/sources/@roots/bud-tailwindcss/src/extension.ts @@ -26,10 +26,11 @@ export default class BudTailwindCss extends Extension { @bind public async configAfter() { try { - this.app.postcss.setPlugins({ - nesting: `tailwindcss/nesting`, - tailwindcss: `tailwindcss`, - }) + const tailwindcss = await this.resolve(`tailwindcss`) + const nesting = await this.resolve(`tailwindcss/nesting/index.js`) + + this.app.postcss.setPlugins({nesting, tailwindcss}) + this.logger.success(`postcss configured for tailwindcss`) } catch (message) { this.logger.error(message) diff --git a/sources/@roots/bud/package.json b/sources/@roots/bud/package.json index c4a8c5b924..3ea2c8ddbe 100644 --- a/sources/@roots/bud/package.json +++ b/sources/@roots/bud/package.json @@ -136,7 +136,6 @@ "node-notifier": "10.0.1", "open": "8.4.0", "open-editor": "4.0.0", - "signale": "1.4.0", "tslib": "2.4.0", "typanion": "3.9.0", "webpack": "5.73.0", diff --git a/sources/@roots/bud/src/notifier/index.ts b/sources/@roots/bud/src/notifier/index.ts index ec7743f4c9..c37b9e2ea1 100644 --- a/sources/@roots/bud/src/notifier/index.ts +++ b/sources/@roots/bud/src/notifier/index.ts @@ -92,7 +92,9 @@ export class Notifier { * @public */ public get open(): string { - return this.app.hooks.filter(`dev.url`).origin + return this.app.isDevelopment + ? this.app.hooks.filter(`dev.url`).origin + : null } /** @@ -195,7 +197,7 @@ export class Notifier { message: this.message, // @ts-ignore group: this.group, - open: this.open, + open: this.app.isDevelopment ? this.open : undefined, }, this.callback, ) diff --git a/sources/@roots/eslint-config/package.json b/sources/@roots/eslint-config/package.json index c2e14d7d4d..819b73f09e 100644 --- a/sources/@roots/eslint-config/package.json +++ b/sources/@roots/eslint-config/package.json @@ -55,7 +55,7 @@ "./sage": "./sage.cjs" }, "devDependencies": { - "@babel/core": "7.18.10", + "@babel/core": "7.19.1", "@jest/globals": "29.0.1", "@skypack/package-check": "0.2.2", "@types/babel__core": "7.1.19", diff --git a/tests/unit/bud-postcss/extension.test.ts b/tests/unit/bud-postcss/extension.test.ts index 7bea011152..af9b0bcdbe 100644 --- a/tests/unit/bud-postcss/extension.test.ts +++ b/tests/unit/bud-postcss/extension.test.ts @@ -1,170 +1,164 @@ -import {beforeAll, describe, expect, it} from '@jest/globals' -import {Bud, factory} from '@repo/test-kit/bud' -import BudPostCss from '@roots/bud-postcss' +import { beforeAll, describe, expect, it } from "@jest/globals"; +import { Bud, factory } from "@repo/test-kit/bud"; +import BudPostCss from "@roots/bud-postcss"; describe(`@roots/bud-postcss`, () => { - let bud: Bud + let bud: Bud; beforeAll(async () => { - bud = await factory() - await bud.extensions.add(BudPostCss) - }) + bud = await factory(); + await bud.extensions.add(BudPostCss); + }); it(`label`, () => { - expect(bud.postcss.label).toBe(`@roots/bud-postcss`) - }) + expect(bud.postcss.label).toBe(`@roots/bud-postcss`); + }); it(`getPlugins`, () => { - expect(bud.postcss.getPlugins()).toBe(bud.postcss.plugins) - }) + expect(bud.postcss.getPlugins()).toBe(bud.postcss.plugins); + }); it(`setPlugins from obj`, () => { - bud.postcss.setPlugins({foo: [`bar`]}) + bud.postcss.setPlugins({ foo: [`bar`] }); - expect(bud.postcss.getPlugins()).toStrictEqual( - new Map([[`foo`, [`bar`]]]), - ) - }) + expect(bud.postcss.getPlugins()).toStrictEqual(new Map([[`foo`, [`bar`]]])); + }); it(`setPlugins from map`, () => { - bud.postcss.plugins.clear() - bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])) + bud.postcss.plugins.clear(); + bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])); expect(bud.postcss.getPlugins()).toStrictEqual( - new Map([[`bang`, [`bop`]]]), - ) - }) + new Map([[`bang`, [`bop`]]]) + ); + }); it(`getPluginOptions`, () => { - bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])) + bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])); - const options = bud.postcss.getPluginOptions(`bang`) - expect(options).toStrictEqual({}) - }) + const options = bud.postcss.getPluginOptions(`bang`); + expect(options).toStrictEqual({}); + }); it(`setPluginOptions`, () => { - bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])) + bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])); - bud.postcss.setPluginOptions(`bang`, {}) - expect(bud.postcss.plugins.get(`bang`)?.pop()).toStrictEqual({}) - }) + bud.postcss.setPluginOptions(`bang`, {}); + expect(bud.postcss.plugins.get(`bang`)?.pop()).toStrictEqual({}); + }); it(`setPluginOptions (callback)`, () => { - bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])) + bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])); - bud.postcss.setPluginOptions(`bang`, {foo: `bar`}) + bud.postcss.setPluginOptions(`bang`, { foo: `bar` }); - bud.postcss.setPluginOptions(`bang`, options => { - expect(options).toStrictEqual({foo: `bar`}) - return options - }) - }) + bud.postcss.setPluginOptions(`bang`, (options) => { + expect(options).toStrictEqual({ foo: `bar` }); + return options; + }); + }); it(`getPluginPath`, () => { - bud.postcss.setPlugins(new Map([[`bang`, [`setPluginPath test`]]])) + bud.postcss.setPlugins(new Map([[`bang`, [`setPluginPath test`]]])); expect(bud.postcss.getPluginPath(`bang`)).toStrictEqual( - `setPluginPath test`, - ) - }) + `setPluginPath test` + ); + }); it(`setPluginPath`, () => { - bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])) + bud.postcss.setPlugins(new Map([[`bang`, [`bop`]]])); - bud.postcss.setPluginPath(`bang`, `newPath`) + bud.postcss.setPluginPath(`bang`, `newPath`); - expect(bud.postcss.plugins.get(`bang`)?.shift()).toStrictEqual( - `newPath`, - ) - }) + expect(bud.postcss.plugins.get(`bang`)?.shift()).toStrictEqual(`newPath`); + }); it(`unsetPlugin`, () => { bud.postcss.setPlugins( new Map([ [`bang`, [`bop`]], [`bong`, [`gong`]], - ]), - ) - }) + ]) + ); + }); it(`unsetPlugin return bud.postcss`, () => { const returnValue = bud.postcss.setPlugins( new Map([ [`bang`, [`bop`]], [`bong`, [`gong`]], - ]), - ) + ]) + ); - expect(returnValue).toBeInstanceOf(BudPostCss) - }) + expect(returnValue).toBeInstanceOf(BudPostCss); + }); it(`setPlugins return bud.postcss`, () => { const returnValue = bud.postcss.setPlugins( new Map([ [`bang`, [`bop`]], [`bong`, [`gong`]], - ]), - ) + ]) + ); - expect(returnValue).toBeInstanceOf(BudPostCss) - }) + expect(returnValue).toBeInstanceOf(BudPostCss); + }); it(`setPlugin`, () => { - bud.postcss.plugins.clear() + bud.postcss.plugins.clear(); - bud.postcss.setPlugin(`boop`) + bud.postcss.setPlugin(`boop`); expect(bud.postcss.plugins.get(`boop`)).toEqual( - expect.arrayContaining([expect.stringContaining(`boop`)]), - ) - }) + expect.arrayContaining([expect.stringContaining(`boop`)]) + ); + }); it(`setPlugin (arr)`, () => { - const signifier = `postcss-preset-env` + const signifier = `postcss-preset-env`; - bud.postcss.plugins.clear() - bud.postcss.setPlugin(`env`, signifier) + bud.postcss.plugins.clear(); + bud.postcss.setPlugin(`env`, signifier); expect(bud.postcss.plugins.get(`env`)).toEqual( - expect.arrayContaining([expect.stringContaining(signifier)]), - ) - }) + expect.arrayContaining([expect.stringContaining(signifier)]) + ); + }); it(`setPlugin (arr w/options)`, () => { - const signifier = `postcss-preset-env` + const signifier = `postcss-preset-env`; - bud.postcss.plugins.clear() - bud.postcss.setPlugin(`env`, [signifier, {option: `value`}]) + bud.postcss.plugins.clear(); + bud.postcss.setPlugin(`env`, [signifier, { option: `value` }]); expect(bud.postcss.plugins.get(`env`)).toEqual( expect.arrayContaining([ expect.stringContaining(signifier), - expect.objectContaining({option: `value`}), - ]), - ) - }) + expect.objectContaining({ option: `value` }), + ]) + ); + }); it(`throws when plugin doesn't exist`, () => { - bud.postcss.plugins.clear() + bud.postcss.plugins.clear(); try { - expect(bud.postcss.getPluginOptions(`no-exist`)).toThrow() + expect(bud.postcss.getPluginOptions(`no-exist`)).toThrow(); } catch (err) {} - }) + }); it(`registers loader`, () => { - expect(bud.build.loaders[`postcss-loader`].getSrc()).toEqual( - `postcss-loader`, - ) - }) + expect(bud.build.loaders.postcss.getSrc()).toContain(`postcss-loader`); + }); it(`registers item`, () => { expect(bud.build.items.postcss?.getLoader().getSrc()).toContain( - `postcss-loader`, - ) - }) + `postcss-loader` + ); + }); it(`added to css rule`, () => { - expect(bud.build.rules.css?.getUse()).toContain(`postcss`) - }) -}) + expect(bud.build.rules.css?.getUse()).toContain(`postcss`); + }); +}); diff --git a/tests/unit/bud-terser/extension.test.ts b/tests/unit/bud-terser/extension.test.ts index 862b71675a..1fc88a2d32 100644 --- a/tests/unit/bud-terser/extension.test.ts +++ b/tests/unit/bud-terser/extension.test.ts @@ -20,7 +20,7 @@ describe(`@roots/bud-terser`, () => { it(`has options prop`, () => { expect(bud.terser.options).toStrictEqual({ extractComments: false, - include: /\.(cjs|mjs|jsx?)$/, + include: /\.(mjs|jsx?)$/, exclude: /(node_modules|bower_components)/, parallel: true, terserOptions: { diff --git a/tests/util/project/src/scripts/app.js b/tests/util/project/src/scripts/app.js index 57838aede5..57bfe085d8 100644 --- a/tests/util/project/src/scripts/app.js +++ b/tests/util/project/src/scripts/app.js @@ -1,7 +1,5 @@ import {main} from './components/main' -const foo = 'bar' - const init = () => window.requestAnimationFrame(function ready() { return document.body ? main() : window.requestAnimationFrame(ready) diff --git a/yarn.lock b/yarn.lock index dcdc47dd7e..b76f3b63b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -213,6 +213,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.19.1": + version: 7.19.1 + resolution: "@babel/compat-data@npm:7.19.1" + checksum: f985887ea08a140e4af87a94d3fb17af0345491eb97f5a85b1840255c2e2a97429f32a8fd12a7aae9218af5f1024f1eb12a5cd280d2d69b2337583c17ea506ba + languageName: node + linkType: hard + "@babel/core@npm:7.12.9": version: 7.12.9 resolution: "@babel/core@npm:7.12.9" @@ -237,7 +244,30 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:7.18.10, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.15.5, @babel/core@npm:^7.18.6": +"@babel/core@npm:7.19.1": + version: 7.19.1 + resolution: "@babel/core@npm:7.19.1" + dependencies: + "@ampproject/remapping": ^2.1.0 + "@babel/code-frame": ^7.18.6 + "@babel/generator": ^7.19.0 + "@babel/helper-compilation-targets": ^7.19.1 + "@babel/helper-module-transforms": ^7.19.0 + "@babel/helpers": ^7.19.0 + "@babel/parser": ^7.19.1 + "@babel/template": ^7.18.10 + "@babel/traverse": ^7.19.1 + "@babel/types": ^7.19.0 + convert-source-map: ^1.7.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.1 + semver: ^6.3.0 + checksum: 941c8c119b80bdba5fafc80bbaa424d51146b6d3c30b8fae35879358dd37c11d3d0926bc7e970a0861229656eedaa8c884d4a3a25cc904086eb73b827a2f1168 + languageName: node + linkType: hard + +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.15.5, @babel/core@npm:^7.18.6": version: 7.18.10 resolution: "@babel/core@npm:7.18.10" dependencies: @@ -343,6 +373,20 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.19.1": + version: 7.19.1 + resolution: "@babel/helper-compilation-targets@npm:7.19.1" + dependencies: + "@babel/compat-data": ^7.19.1 + "@babel/helper-validator-option": ^7.18.6 + browserslist: ^4.21.3 + semver: ^6.3.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: c2d3039265e498b341a6b597f855f2fcef02659050fefedf36ad4e6815e6aafe1011a761214cc80d98260ed07ab15a8cbe959a0458e97bec5f05a450e1b1741b + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-create-class-features-plugin@npm:7.18.6" @@ -400,6 +444,22 @@ __metadata: languageName: node linkType: hard +"@babel/helper-define-polyfill-provider@npm:^0.3.3": + version: 0.3.3 + resolution: "@babel/helper-define-polyfill-provider@npm:0.3.3" + dependencies: + "@babel/helper-compilation-targets": ^7.17.7 + "@babel/helper-plugin-utils": ^7.16.7 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 + semver: ^6.1.2 + peerDependencies: + "@babel/core": ^7.4.0-0 + checksum: 8e3fe75513302e34f6d92bd67b53890e8545e6c5bca8fe757b9979f09d68d7e259f6daea90dc9e01e332c4f8781bda31c5fe551c82a277f9bc0bec007aed497c + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.18.6, @babel/helper-environment-visitor@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-environment-visitor@npm:7.18.9" @@ -632,6 +692,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.19.0": + version: 7.19.0 + resolution: "@babel/helpers@npm:7.19.0" + dependencies: + "@babel/template": ^7.18.10 + "@babel/traverse": ^7.19.0 + "@babel/types": ^7.19.0 + checksum: e50e78e0dbb0435075fa3f85021a6bcae529589800bca0292721afd7f7c874bea54508d6dc57eca16e5b8224f8142c6b0e32e3b0140029dc09865da747da4623 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.18.6": version: 7.18.6 resolution: "@babel/highlight@npm:7.18.6" @@ -670,6 +741,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.19.1": + version: 7.19.1 + resolution: "@babel/parser@npm:7.19.1" + bin: + parser: ./bin/babel-parser.js + checksum: b1e0acb346b2a533c857e1e97ac0886cdcbd76aafef67835a2b23f760c10568eb53ad8a27dd5f862d8ba4e583742e6067f107281ccbd68959d61bc61e4ddaa51 + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.18.6" @@ -708,9 +788,9 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-async-generator-functions@npm:^7.19.0": - version: 7.19.0 - resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.19.0" +"@babel/plugin-proposal-async-generator-functions@npm:^7.19.1": + version: 7.19.1 + resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.19.1" dependencies: "@babel/helper-environment-visitor": ^7.18.9 "@babel/helper-plugin-utils": ^7.19.0 @@ -718,7 +798,7 @@ __metadata: "@babel/plugin-syntax-async-generators": ^7.8.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f1876286d608650928f60ac6091b9a6e7839e005941be483df47693b98c90649202aa1793f28f6e9b4ce69bf0773552144fa40f38751f56dc5d02051a8ee0461 + checksum: f101555b00aee6ee0107c9e40d872ad646bbd3094abdbeda56d17b107df69a0cb49e5d02dcf5f9d8753e25564e798d08429f12d811aaa1b307b6a725c0b8159c languageName: node linkType: hard @@ -1408,15 +1488,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.19.0": - version: 7.19.0 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.19.0" +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.19.1": + version: 7.19.1 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.19.1" dependencies: "@babel/helper-create-regexp-features-plugin": ^7.19.0 "@babel/helper-plugin-utils": ^7.19.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: 60f7b2c537fa3e8392f19b1f1026ba68844c5dc7942867e7a96a636d8a52d4766629b898e59aa690d3806bf02a7fa52e12d1f7c1ca2ef4fa2b53f3fe0a835117 + checksum: 8a40f5d04f2140c44fe890a5a3fd72abc2a88445443ac2bd92e1e85d9366d3eb8f1ebb7e2c89d2daeaf213d9b28cb65605502ac9b155936d48045eeda6053494 languageName: node linkType: hard @@ -1548,7 +1628,23 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-runtime@npm:7.18.10, @babel/plugin-transform-runtime@npm:^7.18.6": +"@babel/plugin-transform-runtime@npm:7.19.1": + version: 7.19.1 + resolution: "@babel/plugin-transform-runtime@npm:7.19.1" + dependencies: + "@babel/helper-module-imports": ^7.18.6 + "@babel/helper-plugin-utils": ^7.19.0 + babel-plugin-polyfill-corejs2: ^0.3.3 + babel-plugin-polyfill-corejs3: ^0.6.0 + babel-plugin-polyfill-regenerator: ^0.4.1 + semver: ^6.3.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d9f693003a546b380a7322087490a51e8c6cd47b44e654f5030f96088cf7888b6c746d6335f723581154aaceed4ef0877acfa642f054ce3beb6ba9bb970987f4 + languageName: node + linkType: hard + +"@babel/plugin-transform-runtime@npm:^7.18.6": version: 7.18.10 resolution: "@babel/plugin-transform-runtime@npm:7.18.10" dependencies: @@ -1668,17 +1764,17 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:7.19.0": - version: 7.19.0 - resolution: "@babel/preset-env@npm:7.19.0" +"@babel/preset-env@npm:7.19.1": + version: 7.19.1 + resolution: "@babel/preset-env@npm:7.19.1" dependencies: - "@babel/compat-data": ^7.19.0 - "@babel/helper-compilation-targets": ^7.19.0 + "@babel/compat-data": ^7.19.1 + "@babel/helper-compilation-targets": ^7.19.1 "@babel/helper-plugin-utils": ^7.19.0 "@babel/helper-validator-option": ^7.18.6 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.18.6 "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.18.9 - "@babel/plugin-proposal-async-generator-functions": ^7.19.0 + "@babel/plugin-proposal-async-generator-functions": ^7.19.1 "@babel/plugin-proposal-class-properties": ^7.18.6 "@babel/plugin-proposal-class-static-block": ^7.18.6 "@babel/plugin-proposal-dynamic-import": ^7.18.6 @@ -1726,7 +1822,7 @@ __metadata: "@babel/plugin-transform-modules-commonjs": ^7.18.6 "@babel/plugin-transform-modules-systemjs": ^7.19.0 "@babel/plugin-transform-modules-umd": ^7.18.6 - "@babel/plugin-transform-named-capturing-groups-regex": ^7.19.0 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.19.1 "@babel/plugin-transform-new-target": ^7.18.6 "@babel/plugin-transform-object-super": ^7.18.6 "@babel/plugin-transform-parameters": ^7.18.8 @@ -1742,14 +1838,14 @@ __metadata: "@babel/plugin-transform-unicode-regex": ^7.18.6 "@babel/preset-modules": ^0.1.5 "@babel/types": ^7.19.0 - babel-plugin-polyfill-corejs2: ^0.3.2 - babel-plugin-polyfill-corejs3: ^0.5.3 - babel-plugin-polyfill-regenerator: ^0.4.0 - core-js-compat: ^3.22.1 + babel-plugin-polyfill-corejs2: ^0.3.3 + babel-plugin-polyfill-corejs3: ^0.6.0 + babel-plugin-polyfill-regenerator: ^0.4.1 + core-js-compat: ^3.25.1 semver: ^6.3.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ae1866b9a6c9749d52618f39aab8c369e0d6dc88e327341fae932411a0d51db2ec51b882cebc62ff3d49443261a6940e3fc03762ff3925d165884e7990eb612c + checksum: 3fcd4f3e768b8b0c9e8f9fb2b23d694d838d3cc936c783aaa9c436b863ae24811059b6ffed80e2ac7d54e7d2c18b0a190f4de05298cf461d27b2817b617ea71f languageName: node linkType: hard @@ -1948,6 +2044,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.19.1": + version: 7.19.1 + resolution: "@babel/traverse@npm:7.19.1" + dependencies: + "@babel/code-frame": ^7.18.6 + "@babel/generator": ^7.19.0 + "@babel/helper-environment-visitor": ^7.18.9 + "@babel/helper-function-name": ^7.19.0 + "@babel/helper-hoist-variables": ^7.18.6 + "@babel/helper-split-export-declaration": ^7.18.6 + "@babel/parser": ^7.19.1 + "@babel/types": ^7.19.0 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: 9d782b5089ebc989e54c2406814ed1206cb745ed2734e6602dee3e23d4b6ebbb703ff86e536276630f8de83fda6cde99f0634e3c3d847ddb40572d0303ba8800 + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.7, @babel/types@npm:^7.15.6, @babel/types@npm:^7.16.0, @babel/types@npm:^7.18.10, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.18.10 resolution: "@babel/types@npm:7.18.10" @@ -4733,12 +4847,12 @@ __metadata: version: 0.0.0-use.local resolution: "@roots/bud-babel@workspace:sources/@roots/bud-babel" dependencies: - "@babel/core": 7.18.10 + "@babel/core": 7.19.1 "@babel/plugin-proposal-class-properties": 7.18.6 "@babel/plugin-proposal-object-rest-spread": 7.18.9 "@babel/plugin-syntax-dynamic-import": 7.8.3 - "@babel/plugin-transform-runtime": 7.18.10 - "@babel/preset-env": 7.19.0 + "@babel/plugin-transform-runtime": 7.19.1 + "@babel/preset-env": 7.19.1 "@jest/globals": 29.0.1 "@roots/bud-api": "workspace:sources/@roots/bud-api" "@roots/bud-build": "workspace:sources/@roots/bud-build" @@ -4747,7 +4861,6 @@ __metadata: "@skypack/package-check": 0.2.2 "@types/node": 16.11.48 babel-loader: 8.2.5 - lodash-es: 4.17.21 tslib: 2.4.0 webpack: 5.73.0 peerDependencies: @@ -4908,7 +5021,7 @@ __metadata: version: 0.0.0-use.local resolution: "@roots/bud-emotion@workspace:sources/@roots/bud-emotion" dependencies: - "@babel/core": 7.18.10 + "@babel/core": 7.19.1 "@emotion/babel-plugin": ^11.9.2 "@emotion/css": ^11.9.0 "@emotion/react": ^11.9.0 @@ -5285,7 +5398,7 @@ __metadata: version: 0.0.0-use.local resolution: "@roots/bud-react@workspace:sources/@roots/bud-react" dependencies: - "@babel/core": 7.18.10 + "@babel/core": 7.19.1 "@babel/preset-react": ^7.17.12 "@jest/globals": 29.0.1 "@pmmmwh/react-refresh-webpack-plugin": ^0.5.7 @@ -5390,7 +5503,7 @@ __metadata: version: 0.0.0-use.local resolution: "@roots/bud-solid@workspace:sources/@roots/bud-solid" dependencies: - "@babel/core": 7.18.10 + "@babel/core": 7.19.1 "@babel/plugin-syntax-jsx": 7.18.6 "@jest/globals": 29.0.1 "@roots/bud-api": "workspace:sources/@roots/bud-api" @@ -5710,7 +5823,6 @@ __metadata: node-notifier: 10.0.1 open: 8.4.0 open-editor: 4.0.0 - signale: 1.4.0 tslib: 2.4.0 typanion: 3.9.0 webpack: 5.73.0 @@ -5800,7 +5912,7 @@ __metadata: version: 0.0.0-use.local resolution: "@roots/eslint-config@workspace:sources/@roots/eslint-config" dependencies: - "@babel/core": 7.18.10 + "@babel/core": 7.19.1 "@babel/eslint-parser": 7.18.9 "@jest/globals": 29.0.1 "@skypack/package-check": 0.2.2 @@ -9990,6 +10102,19 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs2@npm:^0.3.3": + version: 0.3.3 + resolution: "babel-plugin-polyfill-corejs2@npm:0.3.3" + dependencies: + "@babel/compat-data": ^7.17.7 + "@babel/helper-define-polyfill-provider": ^0.3.3 + semver: ^6.1.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7db3044993f3dddb3cc3d407bc82e640964a3bfe22de05d90e1f8f7a5cb71460011ab136d3c03c6c1ba428359ebf635688cd6205e28d0469bba221985f5c6179 + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs3@npm:^0.5.3": version: 0.5.3 resolution: "babel-plugin-polyfill-corejs3@npm:0.5.3" @@ -10002,6 +10127,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs3@npm:^0.6.0": + version: 0.6.0 + resolution: "babel-plugin-polyfill-corejs3@npm:0.6.0" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.3.3 + core-js-compat: ^3.25.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 470bb8c59f7c0912bd77fe1b5a2e72f349b3f65bbdee1d60d6eb7e1f4a085c6f24b2dd5ab4ac6c2df6444a96b070ef6790eccc9edb6a2668c60d33133bfb62c6 + languageName: node + linkType: hard + "babel-plugin-polyfill-regenerator@npm:^0.4.0": version: 0.4.0 resolution: "babel-plugin-polyfill-regenerator@npm:0.4.0" @@ -10013,6 +10150,17 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-regenerator@npm:^0.4.1": + version: 0.4.1 + resolution: "babel-plugin-polyfill-regenerator@npm:0.4.1" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.3.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ab0355efbad17d29492503230387679dfb780b63b25408990d2e4cf421012dae61d6199ddc309f4d2409ce4e9d3002d187702700dd8f4f8770ebbba651ed066c + languageName: node + linkType: hard + "babel-preset-current-node-syntax@npm:^1.0.0": version: 1.0.1 resolution: "babel-preset-current-node-syntax@npm:1.0.1" @@ -11994,6 +12142,15 @@ __metadata: languageName: node linkType: hard +"core-js-compat@npm:^3.25.1": + version: 3.25.1 + resolution: "core-js-compat@npm:3.25.1" + dependencies: + browserslist: ^4.21.3 + checksum: 34dbec657adc2f660f4cd701709c9c5e27cbd608211c65df09458f80f3e357b9492ba1c5173e17cca72d889dcc6da01268cadf88fb407cf1726e76d301c6143e + languageName: node + linkType: hard + "core-js-pure@npm:^3.20.2, core-js-pure@npm:^3.8.1": version: 3.20.3 resolution: "core-js-pure@npm:3.20.3"