diff --git a/.env b/.env index f6d9c44c98..3d4a7c141a 100644 --- a/.env +++ b/.env @@ -1,4 +1,5 @@ # All bud installs in the repository will find this env file # Easier to debug if cache is local to each project -APP_STORAGE_PATH=.storage +BUD_PATH_STORAGE=.storage +BUD_UPDATE_BROWSERSLIST=false \ No newline at end of file diff --git a/examples/sage/package.json b/examples/sage/package.json index a5d778ae38..1e1e10a527 100644 --- a/examples/sage/package.json +++ b/examples/sage/package.json @@ -3,6 +3,9 @@ "$schema": "https://bud.js.org/bud.package.json", "private": true, "type": "module", + "browserslist": [ + "extends @roots/browserslist-config" + ], "devDependencies": { "@roots/bud": "workspace:*", "@roots/bud-tailwindcss": "workspace:*", diff --git a/examples/tailwindcss/colors.js b/examples/tailwindcss/colors.js new file mode 100644 index 0000000000..7c05df58b1 --- /dev/null +++ b/examples/tailwindcss/colors.js @@ -0,0 +1,9 @@ +export default { + blue: { + 100: '#ebf8ff', + 200: '#bee3f8', + 300: '#90cdf4', + 400: '#63b3ed', + 500: '#4299e1', + } +} diff --git a/examples/tailwindcss/tailwind.config.js b/examples/tailwindcss/tailwind.config.js index 05ccb7e2b7..c08a4466db 100644 --- a/examples/tailwindcss/tailwind.config.js +++ b/examples/tailwindcss/tailwind.config.js @@ -1,12 +1,13 @@ -export default { - content: ['src/**/*.{js,css,html}'], +import colors from './colors.js' + +const config = { + content: ['./src/**/*.js'], theme: { extend: { - colors: {}, + colors, // Extend Tailwind's default colors }, }, - variants: { - extend: {}, - }, plugins: [], } + +export default config diff --git a/sources/@repo/docs/content/learn/config/files/env.mdx b/sources/@repo/docs/content/learn/config/files/env.mdx index 835c106741..5c5dbd4490 100644 --- a/sources/@repo/docs/content/learn/config/files/env.mdx +++ b/sources/@repo/docs/content/learn/config/files/env.mdx @@ -4,3 +4,77 @@ sidebar_label: .env --- You can access environment variables set in a `.env` file in your project root using [bud.env](/reference/bud.env). + +## Precedence + +Environment variables are sourced from `.env` files recursively, starting with the project root directory. The closer the file is to the project root, the higher priority it has. + +So, if you have an `.env` file in your project root and another in the parent directory, and both contain a value for the same key, the value from the project root will be used. + +## Expansion + +bud.js supports expansion of environment variables. For example: + +```bash +PUBLIC_API_ORIGIN=https://api.example.com +PUBLIC_API_URL=${PUBLIC_API_URL}/endpoint +``` + +## Public variables + +Any environment variables that are prefixed with `PUBLIC_` will be available to your application code. When using variable values in your application you +must remove the `PUBLIC_` prefix. + +For example, setting `PUBLIC_API_URL`: + +```bash +PUBLIC_API_URL=https://api.example.com +``` + +Means `API_URL` can be used in your application code: + +```js +const request = fetch(`${API_URL}/endpoint`) +``` + +The replacement is static and happens at build time. It is not the same as defining a global. + +For example, attempting to redefine it will cause a type error: + +```js +/** + * Don't do this + */ +API_URL = 'https://api.example.com' +``` + +## Configurable environment variables + +| Variable | Description | Related argument | +| ------------------------- | ----------------------------------------------------------------------------------- | ----------------------- | +| `BUD_CACHE` | Enable or disable bud.js caching | `--cache` | +| `BUD_DEVTOOL` | The devtool to use for builds | `--devtool` | +| `BUD_ESM` | Enable or disable bud.js ESM output (experimental) | `--esm` | +| `BUD_HASH` | Enable or disable output file hashing | `--hash` | +| `BUD_HTML` | Enable HTML templating; set to a string to specify the path to a template | `--html` | +| `BUD_HOT` | Enable or disable bud.js hot reloading | `--hot` | +| `BUD_IMMUTABLE` | Enable or disable automated updates of dependencies when using remote modules | `--immutable` | +| `BUD_LAZY` | Enable or disable lazy compilation of modules in development | `--lazy` | +| `BUD_MINIMIZE` | Enable or disable code minimization | `--minimize` | +| `BUD_PATH_BASE` | The path to the root directory of the bud.js project | `--basedir` | +| `BUD_PATH_STORAGE` | The path to the directory where bud.js stores its data and caches | `--storage` | +| `BUD_PATH_INPUT` | The path to the directory where bud.js looks for source files | `--input` | +| `BUD_PATH_OUTPUT` | The path to the directory where bud.js outputs build files | `--output` | +| `BUD_PATH_PUBLIC` | The path to the directory where bud.js outputs public files | `--publicPath` | +| `BUD_PROXY_URL` | The URL of the proxy server to use | `--proxy` | +| `BUD_RUNTIME` | Enable or disable generation of a runtime module | `--runtime` | +| `BUD_SPLIT_CHUNKS` | Enable or disable splitting of modules into discrete chunks (`vendor`, `app`, etc.) | `--split-chunks` | +| `BUD_UPDATE_BROWSERSLIST` | Set to `false` in order to disable automatic updating of the browserslist database. | `--update-browserslist` | + +## CLI + +You can verify what environment variables are available to bud.js using the `bud env` command: + +```bash npm2yarn +npm run bud env +``` diff --git a/sources/@repo/test-kit/integration-test.ts b/sources/@repo/test-kit/integration-test.ts index 5501488507..a8048a8559 100644 --- a/sources/@repo/test-kit/integration-test.ts +++ b/sources/@repo/test-kit/integration-test.ts @@ -81,6 +81,7 @@ class Project { `--basedir`, this.options.label.replace(`@examples/`, `examples/`), `build`, + `--no-update-browserslist`, ]) } diff --git a/sources/@roots/bud-api/docs/define/usage.md b/sources/@roots/bud-api/docs/define/usage.md index dca18b5151..469c8ff5a5 100644 --- a/sources/@roots/bud-api/docs/define/usage.md +++ b/sources/@roots/bud-api/docs/define/usage.md @@ -24,3 +24,9 @@ Replacements will also be made when compiling [html templates](/reference/bud.ht ``` + +## Caveats + +This replacement is static and happens at build time. It is not the same as a runtime variable. + +Doing things like attempting to reassign its value in your application code will not work. diff --git a/sources/@roots/bud-api/src/methods/splitChunks/index.ts b/sources/@roots/bud-api/src/methods/splitChunks/index.ts index 039ea8cbeb..4813b5b160 100644 --- a/sources/@roots/bud-api/src/methods/splitChunks/index.ts +++ b/sources/@roots/bud-api/src/methods/splitChunks/index.ts @@ -45,7 +45,7 @@ export interface splitChunks { */ export const splitChunks: splitChunks = async function (this: Bud, value) { /** - * For `true` and `undefined` options the default + * For true and undefined options the default * cache groups are added to the build */ if (isUndefined(value) || value === true) { @@ -54,9 +54,9 @@ export const splitChunks: splitChunks = async function (this: Bud, value) { return { automaticNameDelimiter: sep, - ...options, + ...(options ?? {}), cacheGroups: { - ...(options.cacheGroups ?? {}), + ...(options?.cacheGroups ?? {}), default: false, vendor: { chunks: `all`, diff --git a/sources/@roots/bud-api/test/define.test.ts b/sources/@roots/bud-api/test/define.test.ts index c001c80adf..bbf95697fe 100644 --- a/sources/@roots/bud-api/test/define.test.ts +++ b/sources/@roots/bud-api/test/define.test.ts @@ -23,18 +23,21 @@ describe(`bud.define`, function () { it(`adds definitions`, () => { define({DEFINED_KEY: `DEFINED_VALUE`}) - expect( - bud.extensions.get(`@roots/bud-extensions/webpack-define-plugin`) - .options.DEFINED_KEY, - ).toEqual(`DEFINED_VALUE`) + const {options} = bud.extensions.get( + `@roots/bud-extensions/webpack-define-plugin`, + ) + + expect(options.DEFINED_KEY).toEqual(`DEFINED_VALUE`) }) it(`adds PUBLIC_APP_TITLE from env`, async () => { await bud.run() - expect( - bud.extensions.get(`@roots/bud-extensions/webpack-define-plugin`) - .options.APP_TITLE, - ).toBeDefined() + + const {options} = bud.extensions.get( + `@roots/bud-extensions/webpack-define-plugin`, + ) + + expect(options.APP_TITLE).toBeDefined() }) it(`matches snapshot`, () => { diff --git a/sources/@roots/bud-framework/src/context.ts b/sources/@roots/bud-framework/src/context.ts index 854e8441ec..a03798705c 100644 --- a/sources/@roots/bud-framework/src/context.ts +++ b/sources/@roots/bud-framework/src/context.ts @@ -1,4 +1,5 @@ import type {Bud} from '@roots/bud-framework' +import type {PackageManager} from '@roots/bud-support/which-pm' import type {parse} from 'node:path' @@ -402,6 +403,14 @@ export interface Context { storage: string } + /** + * Package manager option + * + * @remarks + * Set with the `--pm` CLI flag. + */ + pm?: PackageManager + /** * Port option * @@ -506,6 +515,14 @@ export interface Context { */ target?: Array + /** + * Update browserslist option + * + * @remarks + * Set with the `--update-browserslist-check` CLI flag. + */ + updateBrowserslistCheck?: boolean + /** * Use option * diff --git a/sources/@roots/bud-framework/src/env.ts b/sources/@roots/bud-framework/src/env.ts index 680af9446c..ac8625809a 100644 --- a/sources/@roots/bud-framework/src/env.ts +++ b/sources/@roots/bud-framework/src/env.ts @@ -12,7 +12,19 @@ export default class Env extends ServiceContainer { */ @bind public override async bootstrap(bud: Bud) { - this.setStore(bud.context.env) + const records = bud.context?.env ?? {} + const coerce = (a: Record, [k, v]) => { + switch (v) { + case `true`: + return {...a, [k]: true} + case `false`: + return {...a, [k]: false} + default: + return {...a, [k]: v} + } + } + + this.setStore(Object.entries(records).reduce(coerce, {})) } /** diff --git a/sources/@roots/bud-framework/src/methods/when.ts b/sources/@roots/bud-framework/src/methods/when.ts index b9c3710dd1..9f0f65cd11 100644 --- a/sources/@roots/bud-framework/src/methods/when.ts +++ b/sources/@roots/bud-framework/src/methods/when.ts @@ -17,12 +17,12 @@ export interface when { } /** - * Executes a function if a given test is `true`. + * Executes a function if a given test is true * * @remarks * - The first parameter is the conditional check. - * - The second parameter is the function to run if `true`. - * - The third parameter is optional; executed if the conditional is not `true`. + * - The second parameter is the function to run if true. + * - The third parameter is optional; executed if the conditional is not true. * * @example * Only produce a vendor bundle when running in `production`: diff --git a/sources/@roots/bud-stylelint/test/stylelintrc-no-extension.test.ts b/sources/@roots/bud-stylelint/test/stylelintrc-no-extension.test.ts index d78e5898eb..fab39d4777 100644 --- a/sources/@roots/bud-stylelint/test/stylelintrc-no-extension.test.ts +++ b/sources/@roots/bud-stylelint/test/stylelintrc-no-extension.test.ts @@ -1,6 +1,6 @@ +import stripAnsi from '@roots/bud-support/strip-ansi' import {execa} from 'execa' import {describe, expect, it} from 'vitest' -import stripAnsi from '@roots/bud-support/strip-ansi' describe(`bud build with extensionless stylelintrc`, () => { it(`should build with expected stdout`, async () => { @@ -10,9 +10,11 @@ describe(`bud build with extensionless stylelintrc`, () => { `run`, `bud`, `build`, + `--no-update-browserslist`, ]) - const [_s, title, _s2, entry, runtime, css, js, _s3, timings] = stripAnsi(result.stdout).split(`\n`) + const [_s, title, _s2, entry, runtime, css, js, _s3, timings] = + stripAnsi(result.stdout).split(`\n`) expect(title).toMatch(/╭ stylelintrc-no-extension \[.*\].*\.\/dist/) expect(entry).toMatch(/│ app/) diff --git a/sources/@roots/bud-support/src/utilities/paths.ts b/sources/@roots/bud-support/src/utilities/paths.ts index 91384af970..f6f40deedc 100644 --- a/sources/@roots/bud-support/src/utilities/paths.ts +++ b/sources/@roots/bud-support/src/utilities/paths.ts @@ -76,7 +76,8 @@ This is most likely a problem with the internals of bud.js.`, let hash: string let env = envBootstrap.get(basedir) - const specified = args.basedir ?? env.APP_BASE_PATH + const specified = args.basedir ?? env.BUD_PATH_BASE ?? env.APP_BASE_PATH + if (specified && !basedir.endsWith(specified)) { logger.scope(`paths`).log(`using specified basedir:`, specified) @@ -89,14 +90,14 @@ This is most likely a problem with the internals of bud.js.`, } hash = sha1.digest(`base64url`) - let storage: string = join(systemPaths.cache, hash) - - if (args.storage || args[`@storage`] || env.APP_STORAGE_PATH) { - storage = join( - basedir, - args.storage ?? args[`@storage`] ?? env.APP_STORAGE_PATH, - ) - } + let storage: string = + args.storage ?? + args[`@storage`] ?? + env.BUD_PATH_STORAGE ?? + env.APP_STORAGE_PATH ?? + join(systemPaths.cache, hash) + + storage = join(basedir, storage) paths = { ...Object.entries(systemPaths).reduce( diff --git a/sources/@roots/bud-support/src/which-pm/index.ts b/sources/@roots/bud-support/src/which-pm/index.ts index 4bfebb1d4c..9101263bd3 100644 --- a/sources/@roots/bud-support/src/which-pm/index.ts +++ b/sources/@roots/bud-support/src/which-pm/index.ts @@ -5,9 +5,15 @@ import * as file from './file.js' import * as manifest from './manifest.js' import * as pmString from './pmString.js' -export default async function ( - basedir: string = cwd, -): Promise<`npm` | `pnpm` | `yarn-classic` | `yarn` | false> { +export type PackageManager = + | `bun` + | `npm` + | `pnpm` + | `yarn-classic` + | `yarn` +export type Responses = false | PackageManager + +export default async function (basedir: string = cwd): Promise { /** * If set, it will be something like: `npm/7.20.3 node/v14.17.3 darwin x64` */ @@ -25,17 +31,20 @@ export default async function ( if (manager) return manager } + /** This config file is only present in bun projects */ + if (await file.exists(basedir, `bun.lockb`)) return `bun` + + /** This config file is only present in pnpm projects */ + if (await file.exists(basedir, `pnpm-lock.yaml`)) return `pnpm` + /** This config file is only present in Yarn 3 projects. */ if (await file.exists(basedir, `.yarnrc.yml`)) return `yarn` - /** If there is a `yarn.lock` file and no `.yarnrc.yml`, it's a Yarn Classic project. */ + /** If there is a `yarn.lock` file it's a Yarn Classic project. */ if (await file.exists(basedir, `yarn.lock`)) return `yarn-classic` /** If there is a `package-lock.json` file, it's an npm project. */ if (await file.exists(basedir, `package-lock.json`)) return `npm` - /** If there is a `pnpm-lock.yaml` file, it's a pnpm project. */ - if (await file.exists(basedir, `pnpm-lock.yaml`)) return `pnpm` - return false } diff --git a/sources/@roots/bud-support/src/which-pm/pmString.ts b/sources/@roots/bud-support/src/which-pm/pmString.ts index 1966f65f87..9f3878b341 100644 --- a/sources/@roots/bud-support/src/which-pm/pmString.ts +++ b/sources/@roots/bud-support/src/which-pm/pmString.ts @@ -1,10 +1,13 @@ +import type { Responses } from "./index.js" + export const parse = ( pmString?: string, -): `npm` | `pnpm` | `yarn-classic` | `yarn` | false => { +): Responses => { if (!pmString) return false if (pmString.match(/yarn(\/|@)(3|4).*/)) return `yarn` if (pmString.includes(`yarn`)) return `yarn-classic` + if (pmString.includes(`bun`)) return `bun` if (pmString.includes(`npm`)) return `npm` if (pmString.includes(`pnpm`)) return `pnpm` diff --git a/sources/@roots/bud/src/cli/commands/build/index.tsx b/sources/@roots/bud/src/cli/commands/build/index.tsx index 2a4bd5adda..a3826dc02a 100644 --- a/sources/@roots/bud/src/cli/commands/build/index.tsx +++ b/sources/@roots/bud/src/cli/commands/build/index.tsx @@ -24,7 +24,10 @@ import runtime from '@roots/bud/cli/flags/runtime' import silent from '@roots/bud/cli/flags/silent' import splitChunks from '@roots/bud/cli/flags/splitChunks' import storage from '@roots/bud/cli/flags/storage' +import updateCheck from '@roots/bud/cli/flags/updateCheck' +import browserslistUpdateCheck from '@roots/bud/cli/helpers/browserslistUpdate' import isBoolean from '@roots/bud-support/lodash/isBoolean' +import logger from '@roots/bud-support/logger' /** * `bud build` command @@ -94,6 +97,8 @@ export default class BudBuildCommand extends BudCommand { public runtime = runtime + public updateCheck = updateCheck + public override silent = silent(false) public splitChunks = splitChunks @@ -110,6 +115,12 @@ export default class BudBuildCommand extends BudCommand { this.bud.entrypoints.set(`emitHtml`, this[`entrypoints.html`]) } + try { + if (this.updateCheck) await browserslistUpdateCheck(this.bud) + } catch (error) { + logger.error(error) + } + await this.bud.run() } } diff --git a/sources/@roots/bud/src/cli/commands/index.tsx b/sources/@roots/bud/src/cli/commands/index.tsx index c4ca8a426e..575209a504 100644 --- a/sources/@roots/bud/src/cli/commands/index.tsx +++ b/sources/@roots/bud/src/cli/commands/index.tsx @@ -33,9 +33,9 @@ import * as Ink from '@roots/bud-support/ink' import isNumber from '@roots/bud-support/lodash/isNumber' import noop from '@roots/bud-support/lodash/noop' import logger from '@roots/bud-support/logger' -import args from '@roots/bud-support/utilities/args' import {Menu} from '../components/Menu.js' +import argumentOverride from '../helpers/argumentOverride.js' export type {BaseContext, Context} export {Option} @@ -159,6 +159,7 @@ export default class BudCommand extends Command { cwd: this.bud.path(), encoding: `utf8`, env: {NODE_ENV: `development`}, + extendEnv: true, stdio: `inherit`, ...options, }) @@ -183,7 +184,7 @@ export default class BudCommand extends Command { * - when children: all children but not the parent * - when no children: the parent; */ - const override = async (fn: (bud: Bud) => Promise) => { + const overrideChildren = async (fn: (bud: Bud) => Promise) => { bud.hasChildren ? await Promise.all( [bud, ...Object.values(bud.children)].map( @@ -193,69 +194,133 @@ export default class BudCommand extends Command { : await fn(bud) } - isset(args.input) && bud.setPath(`@src`, args.input) - isset(args.output) && bud.setPath(`@dist`, args.output) - isset(args.publicPath) && bud.setPublicPath(args.publicPath) - isset(args.modules) && bud.setPath(`@modules`, args.modules) + await argumentOverride( + bud, + `input`, + `BUD_PATH_INPUT`, + value => async bud => bud.setPath(`@src`, value), + ) + + await argumentOverride( + bud, + `output`, + `BUD_PATH_OUTPUT`, + value => async bud => bud.setPath(`@dist`, value), + ) + + await argumentOverride( + bud, + `publicPath`, + `BUD_PUBLIC_PATH`, + value => async bud => bud.hooks.on(`build.output.publicPath`, value), + ) + + await argumentOverride( + bud, + `modules`, + `BUD_PATH_MODULES`, + value => async bud => bud.setPath(`@modules`, value), + ) - isset(args.hot) && + await argumentOverride(bud, `hot`, `BUD_HOT`, value => async bud => { bud.hooks.on(`dev.middleware.enabled`, (middleware = []) => middleware.filter(key => - args.hot === false ? key !== `hot` : args.hot, + value === false ? key !== `hot` : value, ), ) + }) - isset(args.proxy) && - bud.hooks.on( - `dev.middleware.proxy.options.target`, - new URL(args.proxy), - ) - - isset(args.cache) && - (await override(async bud => bud.persist(args.cache))) + await argumentOverride( + bud, + `proxy`, + `BUD_PROXY_URL`, + value => async bud => { + bud.hooks.on(`dev.middleware.proxy.options.target`, new URL(value)) + }, + ) - isset(args.minimize) && - (await override(async bud => bud.minimize(args.minimize))) + await argumentOverride( + bud, + `cache`, + `BUD_CACHE`, + value => async () => await overrideChildren(async bud => bud.persist(value)), + ) - isset(args.devtool) && - (await override(async bud => bud.devtool(args.devtool))) + await argumentOverride( + bud, + `minimize`, + `BUD_MINIMIZE`, + value => async () => await overrideChildren(async bud => bud.minimize(value)), + ) - isset(args.esm) && - (await override(async bud => bud.esm.enable(args.esm))) + await argumentOverride( + bud, + `devtool`, + `BUD_DEVTOOL`, + value => async () => await overrideChildren(async bud => bud.devtool(value)), + ) - isset(args.html) && - (await override(async bud => { - typeof args.html === `string` - ? bud.html({template: args.html}) - : bud.html(args.html) - })) + await argumentOverride( + bud, + `esm`, + `BUD_ESM`, + value => async () => await overrideChildren(async bud => bud.esm.enable(value)), + ) - isset(args.immutable) && - (await override(async bud => bud.cdn.freeze(args.immutable))) + await argumentOverride( + bud, + `hash`, + `BUD_HASH`, + value => async () => await overrideChildren(async bud => bud.hash(value)), + ) - if (isset(args.hash)) { - await override(async bud => { - bud.context.hash = args.hash - logger.log(`hash set from --hash flag`, `value:`, args.hash) + await argumentOverride( + bud, + `html`, + `BUD_HTML`, + value => async () => await overrideChildren(async bud => { + typeof value === `string` + ? bud.html({template: value}) + : bud.html(value) }) - } + ) - if (isset(args.lazy)) { - await override(async bud => { - bud.lazy(args.lazy) - logger.log(`lazy set from --lazy flag`, `value:`, args.lazy) - }) - } + await argumentOverride( + bud, + `immutable`, + `BUD_IMMUTABLE`, + value => async () => await overrideChildren(async bud => bud.cdn.freeze(value)), + ) + + await argumentOverride( + bud, + `lazy`, + `BUD_LAZY`, + value => async () => await overrideChildren(async bud => bud.lazy(value)), + ) - isset(args.runtime) && - (await override(async bud => bud.runtime(args.runtime))) + await argumentOverride( + bud, + `runtime`, + `BUD_RUNTIME`, + value => async () => await overrideChildren(async bud => bud.runtime(value)), + ) - isset(args.splitChunks) && - (await override(async bud => bud.splitChunks(args.splitChunks))) + await argumentOverride( + bud, + `splitChunks`, + `BUD_SPLIT_CHUNKS`, + value => async () => await overrideChildren(async bud => bud.splitChunks(value)), + ) - isset(args.use) && (await bud.extensions.add(args.use as any)) + await argumentOverride( + bud, + `use`, + `BUD_USE`, + value => async () => await overrideChildren(async bud => await bud.extensions.add(value)), + ) - await override(async bud => await bud.promise()) + await overrideChildren(async bud => await bud.promise()) } /** diff --git a/sources/@roots/bud/src/cli/commands/upgrade/index.tsx b/sources/@roots/bud/src/cli/commands/upgrade/index.tsx index 33b24117bb..cdb5797dfe 100644 --- a/sources/@roots/bud/src/cli/commands/upgrade/index.tsx +++ b/sources/@roots/bud/src/cli/commands/upgrade/index.tsx @@ -1,4 +1,5 @@ import BudCommand from '@roots/bud/cli/commands' +import {updateBrowserslist} from '@roots/bud/cli/helpers/browserslistUpdate' import axios from '@roots/bud-support/axios' import {Command, Option} from '@roots/bud-support/clipanion' import {bind} from '@roots/bud-support/decorators/bind' @@ -7,7 +8,6 @@ import isString from '@roots/bud-support/lodash/isString' import logger from '@roots/bud-support/logger' import semver from '@roots/bud-support/semver' import {isLiteral, isOneOf} from '@roots/bud-support/typanion' -import whichPm from '@roots/bud-support/which-pm' type Type = `dependencies` | `devDependencies` @@ -75,6 +75,7 @@ export default class BudUpgradeCommand extends BudCommand { public pm = Option.String(`--pm`, undefined, { description: `Package manager to use. One of: \`npm\`, \`yarn-classic\`, \`pnpm\` (experimental), or \`yarn\` (experimental)`, validator: isOneOf([ + isLiteral(`bun`), isLiteral(`npm`), isLiteral(`pnpm`), isLiteral(`yarn`), @@ -101,7 +102,7 @@ export default class BudUpgradeCommand extends BudCommand { /** * Package manager bin */ - public get bin(): `npm` | `pnpm` | `yarn` { + public get bin(): `bun` | `npm` | `pnpm` | `yarn` { if (this.pm === `yarn-classic`) { return `yarn` } @@ -166,29 +167,8 @@ export default class BudUpgradeCommand extends BudCommand { const basedir = this.bud?.context?.basedir ?? process.cwd() logger.log(`Using basedir:`, basedir) - if (!this.pm) { - await whichPm(basedir) - .catch(thrownError => { - const error = BudError.normalize(thrownError) - error.details = error.message - error.thrownBy = `@roots/bud-support/which-pm` - throw error - }) - .then(pm => { - if (pm === false) { - logger.info(`No package manager could be detected.`) - this.pm = `npm` - return - } - - this.pm = pm - }) - .catch(e => { - logger.info(`Error getting package manager`, `\n`, e) - this.pm = `npm` - }) - } - logger.log(`Using package manager:`, this.pm) + this.pm = this.pm ?? this.bud.context.pm + logger.log(`using package manager:`, this.pm) if (this.pm === `yarn`) { if (this.registry !== `https://registry.npmjs.org`) { @@ -198,24 +178,26 @@ export default class BudUpgradeCommand extends BudCommand { this.registry = `https://registry.npmjs.org` } - await this.bud.fs.yml - .read(this.bud.path(`.yarnrc.yml`)) - .then(yarnrc => { - if (!yarnrc) return - - if (yarnrc[`npmRegistryServer`]) { - this.registry = yarnrc[`npmRegistryServer`] - - logger.log( - `Registry set to`, - this.registry, - `(setting sourced from .yarnrc.yml)`, - ) - } - }) - .catch(error => { - logger.warn(`Error reading .yarnrc.yml`, `\n`, error) - }) + if (await this.bud.fs.exists(this.bud.path(`.yarnrc.yml`))) { + await this.bud.fs.yml + .read(this.bud.path(`.yarnrc.yml`)) + .then(yarnrc => { + if (!yarnrc) return + + if (yarnrc[`npmRegistryServer`]) { + this.registry = yarnrc[`npmRegistryServer`] + + logger.log( + `registry set to`, + this.registry, + `(setting sourced from .yarnrc.yml)`, + ) + } + }) + .catch(error => { + logger.warn(`error reading .yarnrc.yml`, error) + }) + } } logger.log(`Using registry:`, this.registry) @@ -240,8 +222,8 @@ export default class BudUpgradeCommand extends BudCommand { await this.$(this.bin, [`install`, `--shamefully-hoist`]) } - if (this.browserslist) - await this.upgradeBrowserslistDb().catch(error => { + if (this.browserslist && !this.bud.env.isFalse(`BUD_BROWSERSLIST_UPDATE`)) + await updateBrowserslist(this.bud).catch(error => { logger.warn(`Error upgrading browserslist db`, `\n`, error) }) } @@ -260,21 +242,24 @@ export default class BudUpgradeCommand extends BudCommand { const results = Object.entries(dependencies) .filter(([signifier, version]: [string, string]) => { if (!version || !signifier) return false - if (version.includes(`workspace:`)) return false + if (version.includes(`workspace:`)) { + logger.log(`ignoring workspace:* dependency`, signifier) + return false + } if ( signifier.includes(`bud-`) || signifier.includes(`/bud`) || signifier.includes(`@roots/sage`) - ) + ) { + logger.log(`found candidate`, `${signifier}@${version}`) return true + } return false }) .map(([signifier]) => signifier) - logger.log(`candidates:`, `\n`, results) - return results } @@ -317,7 +302,6 @@ export default class BudUpgradeCommand extends BudCommand { const communityDependencies = this.findCandidates(type).filter( signifier => !signifier.startsWith(`@roots/`), ) - logger.log(`found community dependencies`, communityDependencies) await Promise.all( communityDependencies.map(async signifier => { const {versions} = await this.doRegistryRequest(signifier) @@ -363,12 +347,15 @@ export default class BudUpgradeCommand extends BudCommand { logger.warn(`error getting upgradeable`, type, `\n`, error) }) - logger.log( - `discovered upgradeable`, - type, - `:\n`, - this.upgradeable[type], - ) + if (this.upgradeable[type] && this.upgradeable[type].length) { + logger.log( + `discovered upgradeable`, + type, + `:\n`, + this.upgradeable[type], + ) + } + return this.upgradeable[type] } @@ -427,26 +414,4 @@ export default class BudUpgradeCommand extends BudCommand { logger.error(error) }) } - - /** - * Try to upgrade browserslist - */ - @bind - public async upgradeBrowserslistDb() { - if (this.registry !== `https://registry.npmjs.org`) { - logger.warn(`Cannot upgrade browserslist db with custom registry`) - return - } - - logger.log(`Attempting to upgrade browserslist db...`) - - switch (this.pm) { - case `pnpm`: - await this.$(`pnpx`, [`update-browserslist-db`]) - break - default: - await this.$(`npx`, [`update-browserslist-db`]) - break - } - } } diff --git a/sources/@roots/bud/src/cli/flags/storage.ts b/sources/@roots/bud/src/cli/flags/storage.ts index 92f32aad89..f81c6e736f 100644 --- a/sources/@roots/bud/src/cli/flags/storage.ts +++ b/sources/@roots/bud/src/cli/flags/storage.ts @@ -2,5 +2,4 @@ import {Option} from '@roots/bud-support/clipanion' export default Option.String(`--storage`, undefined, { description: `Storage directory (relative to project)`, - env: `APP_PATH_STORAGE`, }) diff --git a/sources/@roots/bud/src/cli/flags/updateCheck.ts b/sources/@roots/bud/src/cli/flags/updateCheck.ts new file mode 100644 index 0000000000..b808810974 --- /dev/null +++ b/sources/@roots/bud/src/cli/flags/updateCheck.ts @@ -0,0 +1,5 @@ +import {Option} from '@roots/bud-support/clipanion' + +export default Option.Boolean(`--update-browserslist`, true, { + description: `Check for browserslist db updates at regular intervals.`, +}) diff --git a/sources/@roots/bud/src/cli/helpers/argumentOverride.ts b/sources/@roots/bud/src/cli/helpers/argumentOverride.ts new file mode 100644 index 0000000000..afd8cecfc9 --- /dev/null +++ b/sources/@roots/bud/src/cli/helpers/argumentOverride.ts @@ -0,0 +1,16 @@ +import type {Bud} from '@roots/bud' + +import {isset} from '@roots/bud/cli/helpers/isset' + +export default async function argumentOverride( + bud: Bud, + arg: string, + env: string, + callback: (value: any) => (bud: Bud) => Promise, +) { + if (isset(bud.context[arg])) { + return await callback(bud.context[arg])(bud) + } else if (bud.env.has(env)) { + return await callback(bud.env.get(env))(bud) + } +} diff --git a/sources/@roots/bud/src/cli/helpers/browserslistUpdate.tsx b/sources/@roots/bud/src/cli/helpers/browserslistUpdate.tsx new file mode 100644 index 0000000000..7f7d8ac89c --- /dev/null +++ b/sources/@roots/bud/src/cli/helpers/browserslistUpdate.tsx @@ -0,0 +1,110 @@ +import type {Bud} from '@roots/bud' + +import execa from '@roots/bud-support/execa' +import logger from '@roots/bud-support/logger' + +async function browserslistUpdateCheck(bud: Bud) { + if ((!await hasBrowserslistConfig(bud))) { + return logger.log( + `No browserslist configuration found. Skipping browserslist upgrade check.`, + ) + } + + if (isCI(bud)) { + return logger.log( + `CI environment detected. Skipping browserslist upgrade check.`, + ) + } + + if (isDisabled(bud)) { + return logger.log(`Browserslist update check disabled. Skipping.`) + } + + const nowTime = Date.now() + const pastWeekTime = nowTime - 1000 * 60 * 60 * 24 * 7 + + if (await hasBrowserslistCheckFile(bud)) { + let changeTime: number + let response = await bud.fs.read( + bud.path(`@storage`, `browserslist-db-check.yml`), + ) + if (response?.changeTime) changeTime = response.changeTime + + if (changeTime && changeTime > pastWeekTime) { + logger.log( + `Browserslist database updated within the past week. Skipping.`, + ) + return + } + } + + if (!isSilent(bud)) { + process.stdout.write(`\nChecking for browserslist updates...\n`) + process.stdout.write( + `(you can disable this behavior with the --no-update-browserslist flag.)\n\n`, + ) + } + + /** + * Write the current time to the storage file + */ + await bud.fs.write(bud.path(`@storage`, `browserslist-db-check.yml`), { + changeTime: nowTime, + }) + + await updateBrowserslist(bud) +} + +const hasBrowserslistConfig = async (bud: Bud): Promise => { + const hasBrowserslistListConfig = await bud.fs.exists(`.browserslistrc`) + const hasBrowserslistPackageConfig = bud.context?.manifest?.browserslist + return hasBrowserslistListConfig || hasBrowserslistPackageConfig +} + +const hasBrowserslistCheckFile = async (bud: Bud): Promise => { + return !!(await bud.fs.exists( + bud.path(`@storage`, `browserslist-db-check.yml`), + )) +} + +const isCI = (bud: Bud): boolean => bud.context?.ci +const isDisabled = (bud: Bud): boolean => { + if (bud.context?.updateBrowserslistCheck === false) return true + if (bud.env.has(`BUD_UPDATE_BROWSERSLIST`) && bud.env.get(`BUD_UPDATE_BROWSERSLIST`) === false) return true + return false +} +const isSilent = (bud: Bud): boolean => bud.context?.silent + +const updateBrowserslist = async (bud: Bud) => { + /** + * Run the update command + */ + if (bud.context.pm === `npm` || bud.context.pm === `yarn-classic`) { + return await execa(`npx`, [`update-browserslist-db`], { + cwd: bud.context.basedir, + encoding: `utf8`, + env: {NODE_ENV: `development`}, + extendEnv: true, + }) + } + + if (bud.context.pm === `pnpm`) { + return await execa(`pnpx`, [`update-browserslist-db`], { + cwd: bud.context.basedir, + encoding: `utf8`, + env: {NODE_ENV: `development`}, + extendEnv: true, + }) + } + + if (bud.context.pm === `yarn`) { + return await execa(`yarn`, [`dlx`, `update-browserslist-db`], { + cwd: bud.context.basedir, + encoding: `utf8`, + env: {NODE_ENV: `development`}, + extendEnv: true, + }) + } +} + +export {browserslistUpdateCheck as default, updateBrowserslist} diff --git a/sources/@roots/bud/src/context/index.ts b/sources/@roots/bud/src/context/index.ts index ff64c5ed14..60501679fb 100644 --- a/sources/@roots/bud/src/context/index.ts +++ b/sources/@roots/bud/src/context/index.ts @@ -10,6 +10,7 @@ import args from '@roots/bud-support/utilities/args' import * as projectEnv from '@roots/bud-support/utilities/env' import * as projectFiles from '@roots/bud-support/utilities/files' import * as projectPaths from '@roots/bud-support/utilities/paths' +import whichPm from '@roots/bud-support/which-pm' import * as budManifest from './bud.js' import getExtensions from './extensions.js' @@ -41,6 +42,11 @@ export default async (options: Options = {}): Promise => { options?.extensions, ) + if (!options.pm) { + const pm = await whichPm(basedir) + options.pm = pm !== false ? pm : `npm` + } + const context: Context = { ...(args ?? {}), ...options, @@ -54,6 +60,7 @@ export default async (options: Options = {}): Promise => { manifest: {...(manifest ?? {}), ...(options?.manifest ?? {})}, mode: options?.mode ?? `production`, paths: {...paths, ...(options?.paths ?? {})}, + pm: args?.pm ?? options?.pm ?? `npm`, render: options?.render ?? render, services: [...(services ?? []), ...(options?.services ?? [])], stderr: options?.stderr ?? stderr, @@ -69,6 +76,7 @@ export default async (options: Options = {}): Promise => { .log(`🏗️`, `building`, context.label) .log(`📂`, `basedir`, context.basedir) .log(`😎`, `version`, context.bud.version) + .log(`📦`, `package manager`, context.pm) .scope(context.label) return context diff --git a/sources/@roots/bud/test/cli-flag-hash/filter-hash.test.ts b/sources/@roots/bud/test/cli-flag-hash/filter-hash.test.ts index 0c2f3b6c5b..ba1b74d78e 100644 --- a/sources/@roots/bud/test/cli-flag-hash/filter-hash.test.ts +++ b/sources/@roots/bud/test/cli-flag-hash/filter-hash.test.ts @@ -1,45 +1,42 @@ -import {join} from 'node:path' -import {test, expect} from 'vitest' -import fs from 'fs-jetpack' +import {path} from '@repo/constants' import {execa} from 'execa' -import {paths} from '@repo/constants' +import fs from 'fs-jetpack' +import {expect, test} from 'vitest' -test('--hash', async () => { +test(`--hash`, async () => { await fs.removeAsync( - join(paths.root, 'sources/@roots/bud/test/cli-flag-hash/project/dist'), + path(`sources/@roots/bud/test/cli-flag-hash/project/dist`), ) - await execa('yarn', [ - 'workspace', - '@tests/bud-hash-flag', - 'run', - 'bud', - 'build', - '--hash', + await execa(`yarn`, [ + `workspace`, + `@tests/bud-hash-flag`, + `run`, + `bud`, + `build`, + `--hash`, ]) expect( await fs.existsAsync( - join( - paths.root, - 'sources/@roots/bud/test/cli-flag-hash/project/dist/js/main.js', + path( + `sources/@roots/bud/test/cli-flag-hash/project/dist/js/main.js`, ), ), ).toBe(false) - await execa('yarn', [ - 'workspace', - '@tests/bud-hash-flag', - 'run', - 'bud', - 'build', + await execa(`yarn`, [ + `workspace`, + `@tests/bud-hash-flag`, + `run`, + `bud`, + `build`, ]) expect( await fs.existsAsync( - join( - paths.root, - 'sources/@roots/bud/test/cli-flag-hash/project/dist/js/main.js', + path( + `sources/@roots/bud/test/cli-flag-hash/project/dist/js/main.js`, ), ), ).toBe(`file`) diff --git a/sources/@roots/bud/test/cli-flag-html/html-flag.test.ts b/sources/@roots/bud/test/cli-flag-html/html-flag.test.ts new file mode 100644 index 0000000000..0c38e1e6f3 --- /dev/null +++ b/sources/@roots/bud/test/cli-flag-html/html-flag.test.ts @@ -0,0 +1,48 @@ +import {path} from '@repo/constants' +import {execa} from 'execa' +import fs from 'fs-jetpack' +import {expect, test} from 'vitest' + +test(`--html`, async () => { + await fs.removeAsync( + path(`sources/@roots/bud/test/cli-flag-html/project/dist`), + ) + + await execa(`yarn`, [ + `workspace`, + `@tests/html-flag`, + `run`, + `bud`, + `build`, + `--html`, + ]) + + expect( + await fs.existsAsync( + path( + `sources/@roots/bud/test/cli-flag-html/project/dist/index.html`, + ), + ), + ).toBe(`file`) + + await fs.removeAsync( + path(`sources/@roots/bud/test/cli-flag-html/project/dist`), + ) + + await execa(`yarn`, [ + `workspace`, + `@tests/html-flag`, + `run`, + `bud`, + `build`, + `--no-html`, + ]) + + expect( + await fs.existsAsync( + path( + `sources/@roots/bud/test/cli-flag-html/project/dist/index.html`, + ), + ), + ).toBe(false) +}) diff --git a/sources/@roots/bud/test/cli-flag-html/project/package.json b/sources/@roots/bud/test/cli-flag-html/project/package.json new file mode 100644 index 0000000000..1c99d9ab1b --- /dev/null +++ b/sources/@roots/bud/test/cli-flag-html/project/package.json @@ -0,0 +1,8 @@ +{ + "name": "@tests/html-flag", + "private": true, + "type": "module", + "devDependencies": { + "@roots/bud": "workspace:*" + } +} diff --git a/sources/@roots/bud/test/cli-flag-html/project/src/index.js b/sources/@roots/bud/test/cli-flag-html/project/src/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sources/@roots/bud/test/cli-flag-runtime/filter-runtime.test.ts b/sources/@roots/bud/test/cli-flag-runtime/filter-runtime.test.ts index eb880cf24b..e151b4edba 100644 --- a/sources/@roots/bud/test/cli-flag-runtime/filter-runtime.test.ts +++ b/sources/@roots/bud/test/cli-flag-runtime/filter-runtime.test.ts @@ -24,6 +24,10 @@ test(`--runtime`, async () => { ), ).toBe(`file`) + await fs.removeAsync( + path(`sources/@roots/bud/test/cli-flag-runtime/project/dist`), + ) + await execa(`yarn`, [ `workspace`, `@tests/bud-runtime-flag`, diff --git a/sources/@roots/bud/test/env-hash/env-hash.test.ts b/sources/@roots/bud/test/env-hash/env-hash.test.ts new file mode 100644 index 0000000000..f548efe394 --- /dev/null +++ b/sources/@roots/bud/test/env-hash/env-hash.test.ts @@ -0,0 +1,24 @@ +import {path} from '@repo/constants' +import {execa} from 'execa' +import fs from 'fs-jetpack' +import {expect, test} from 'vitest' + +test(`env.hash`, async () => { + await fs.removeAsync( + path(`sources/@roots/bud/test/env-hash/project/dist`), + ) + + await execa(`yarn`, [ + `workspace`, + `@tests/env-hash`, + `run`, + `bud`, + `build`, + ]) + + expect( + await fs.existsAsync( + path(`sources/@roots/bud/test/env-hash/project/dist/js/main.js`), + ), + ).toBe(false) +}) diff --git a/sources/@roots/bud/test/env-hash/project/.env b/sources/@roots/bud/test/env-hash/project/.env new file mode 100644 index 0000000000..df67bcb7ba --- /dev/null +++ b/sources/@roots/bud/test/env-hash/project/.env @@ -0,0 +1 @@ +BUD_HASH=true diff --git a/sources/@roots/bud/test/env-hash/project/package.json b/sources/@roots/bud/test/env-hash/project/package.json new file mode 100644 index 0000000000..ee1e3079d4 --- /dev/null +++ b/sources/@roots/bud/test/env-hash/project/package.json @@ -0,0 +1,8 @@ +{ + "name": "@tests/env-hash", + "private": true, + "type": "module", + "devDependencies": { + "@roots/bud": "workspace:*" + } +} diff --git a/sources/@roots/bud/test/env-hash/project/src/index.js b/sources/@roots/bud/test/env-hash/project/src/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sources/@roots/bud/test/env-runtime/env-runtime.test.ts b/sources/@roots/bud/test/env-runtime/env-runtime.test.ts new file mode 100644 index 0000000000..a4f5977eda --- /dev/null +++ b/sources/@roots/bud/test/env-runtime/env-runtime.test.ts @@ -0,0 +1,26 @@ +import {path} from '@repo/constants' +import {execa} from 'execa' +import fs from 'fs-jetpack' +import {expect, test} from 'vitest' + +test(`env.runtime`, async () => { + await fs.removeAsync( + path(`sources/@roots/bud/test/env-runtime/project/dist`), + ) + + await execa(`yarn`, [ + `workspace`, + `@tests/bud-runtime-flag`, + `run`, + `bud`, + `build`, + ]) + + expect( + await fs.existsAsync( + path( + `sources/@roots/bud/test/env-runtime/project/dist/js/runtime.js`, + ), + ), + ).toBe(false) +}) diff --git a/sources/@roots/bud/test/env-runtime/project/.env b/sources/@roots/bud/test/env-runtime/project/.env new file mode 100644 index 0000000000..879167cc89 --- /dev/null +++ b/sources/@roots/bud/test/env-runtime/project/.env @@ -0,0 +1 @@ +BUD_RUNTIME=false diff --git a/sources/@roots/bud/test/env-runtime/project/package.json b/sources/@roots/bud/test/env-runtime/project/package.json new file mode 100644 index 0000000000..6fb094d4f6 --- /dev/null +++ b/sources/@roots/bud/test/env-runtime/project/package.json @@ -0,0 +1,8 @@ +{ + "name": "@tests/env-runtime", + "private": true, + "type": "module", + "devDependencies": { + "@roots/bud": "workspace:*" + } +} diff --git a/sources/@roots/bud/test/env-runtime/project/src/index.js b/sources/@roots/bud/test/env-runtime/project/src/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sources/@roots/bud/test/env-splitChunks/env-split-chunks.test.ts b/sources/@roots/bud/test/env-splitChunks/env-split-chunks.test.ts new file mode 100644 index 0000000000..6830e788b0 --- /dev/null +++ b/sources/@roots/bud/test/env-splitChunks/env-split-chunks.test.ts @@ -0,0 +1,24 @@ +import {path} from '@repo/constants' +import {execa} from 'execa' +import fs from 'fs-jetpack' +import {expect, test} from 'vitest' + +test(`env.splitChunks`, async () => { + await fs.removeAsync( + path(`sources/@roots/bud/test/env-split-chunks/project/dist`), + ) + + await execa(`yarn`, [ + `workspace`, + `@tests/env-split-chunks`, + `run`, + `bud`, + `build`, + ]) + + expect( + await fs.existsAsync( + path(`sources/@roots/bud/test/env-split-chunks/project/dist/js/main.js`), + ), + ).toBe(false) +}) diff --git a/sources/@roots/bud/test/env-splitChunks/project/.env b/sources/@roots/bud/test/env-splitChunks/project/.env new file mode 100644 index 0000000000..316e45f8a8 --- /dev/null +++ b/sources/@roots/bud/test/env-splitChunks/project/.env @@ -0,0 +1 @@ +BUD_SPLIT_CHUNKS=true diff --git a/sources/@roots/bud/test/env-splitChunks/project/package.json b/sources/@roots/bud/test/env-splitChunks/project/package.json new file mode 100644 index 0000000000..155bed4510 --- /dev/null +++ b/sources/@roots/bud/test/env-splitChunks/project/package.json @@ -0,0 +1,9 @@ +{ + "name": "@tests/env-split-chunks", + "private": true, + "type": "module", + "devDependencies": { + "@roots/bud": "workspace:*", + "lodash": "4.17.21" + } +} diff --git a/sources/@roots/bud/test/env-splitChunks/project/src/index.js b/sources/@roots/bud/test/env-splitChunks/project/src/index.js new file mode 100644 index 0000000000..f1c70cc501 --- /dev/null +++ b/sources/@roots/bud/test/env-splitChunks/project/src/index.js @@ -0,0 +1,3 @@ +import _ from 'lodash'; + +document.body.innerHTML = Object.keys(_).join(` `) diff --git a/sources/@roots/filesystem/src/s3/index.ts b/sources/@roots/filesystem/src/s3/index.ts index 33e09bcffd..e66cf3a84f 100644 --- a/sources/@roots/filesystem/src/s3/index.ts +++ b/sources/@roots/filesystem/src/s3/index.ts @@ -121,7 +121,7 @@ export class S3 { * * @remarks * By default the {@link ListObjectsCommandOutput} will be mapped so that the returned value is an array of file keys. - * This can be disabled by setting `raw` to `true`. + * This can be disabled by setting `raw` to true. * * @param props - {@link Omit command input props} * @returns Array of file keys @@ -150,7 +150,7 @@ export class S3 { * * @remarks * By default the raw response will be transformed to `utf8` before being returned. - * This can be disabled by setting `raw` to `true`. + * This can be disabled by setting `raw` to true. * * @param key - The file key * @param raw - Whether to return raw response diff --git a/tests/e2e/util/install.ts b/tests/e2e/util/install.ts index e86e796763..bfe3e2dba2 100644 --- a/tests/e2e/util/install.ts +++ b/tests/e2e/util/install.ts @@ -31,7 +31,15 @@ export const runDev = async ( return execa( `npx`, - [`bud`, `dev`, `--no-cache`, `--html`, `--port`, `${port}`], + [ + `bud`, + `dev`, + `--no-cache`, + `--html`, + `--port`, + `${port}`, + `--no-update-browserslist`, + ], {cwd: fs.destinationPath(dirname)}, ).catch(error => { throw error diff --git a/yarn.lock b/yarn.lock index 0a0e9247bb..6c5307121a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11132,6 +11132,39 @@ __metadata: languageName: unknown linkType: soft +"@tests/env-hash@workspace:sources/@roots/bud/test/env-hash/project": + version: 0.0.0-use.local + resolution: "@tests/env-hash@workspace:sources/@roots/bud/test/env-hash/project" + dependencies: + "@roots/bud": "workspace:*" + languageName: unknown + linkType: soft + +"@tests/env-runtime@workspace:sources/@roots/bud/test/env-runtime/project": + version: 0.0.0-use.local + resolution: "@tests/env-runtime@workspace:sources/@roots/bud/test/env-runtime/project" + dependencies: + "@roots/bud": "workspace:*" + languageName: unknown + linkType: soft + +"@tests/env-split-chunks@workspace:sources/@roots/bud/test/env-splitChunks/project": + version: 0.0.0-use.local + resolution: "@tests/env-split-chunks@workspace:sources/@roots/bud/test/env-splitChunks/project" + dependencies: + "@roots/bud": "workspace:*" + lodash: 4.17.21 + languageName: unknown + linkType: soft + +"@tests/html-flag@workspace:sources/@roots/bud/test/cli-flag-html/project": + version: 0.0.0-use.local + resolution: "@tests/html-flag@workspace:sources/@roots/bud/test/cli-flag-html/project" + dependencies: + "@roots/bud": "workspace:*" + languageName: unknown + linkType: soft + "@tests/issue-1798@workspace:tests/reproductions/issue-1798": version: 0.0.0-use.local resolution: "@tests/issue-1798@workspace:tests/reproductions/issue-1798" @@ -17613,9 +17646,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001464, caniuse-lite@npm:^1.0.30001503, caniuse-lite@npm:^1.0.30001517, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001541": - version: 1.0.30001554 - resolution: "caniuse-lite@npm:1.0.30001554" - checksum: ccb557daa716b474a15f3a0a3a0e33f59393024a9fd1ccef6d8ee6f35c195fb5cca7f99f1ac88e3db5926b4f1bcd4ad6d7380a27e1d45d68468a837dd7e60106 + version: 1.0.30001558 + resolution: "caniuse-lite@npm:1.0.30001558" + checksum: 1bd6ef855a0de6ff052234912910d699e58edabcf2f34848b7df1f97ee40b059bbdf1901ac919d19360a0603e32e2ac30ae89670ceca8f118e750be3280ef5b1 languageName: node linkType: hard