diff --git a/docs/config/build-options.md b/docs/config/build-options.md index 3419070bd..b7f2f6c8c 100644 --- a/docs/config/build-options.md +++ b/docs/config/build-options.md @@ -185,6 +185,34 @@ export default defineConfig({ }) ``` +## build.license + +- **Type:** `boolean | string` +- **Default:** `false` + +When set to `true`, the build will also generate a `.vite/license.md` file that includes all bundled dependencies' licenses. It can be hosted to display and acknowledge the dependencies used by the app. When the value is a string, it will be used as the license file name. + +If a string is passed that ends with `.json`, a raw JSON file will be generated instead. For example: + +```json +[ + { + "name": "dep-1", + "version": "0.0.0", + "identifier": "CC0-1.0", + "text": "CC0 1.0 Universal ..." + }, + { + "name": "dep-2", + "version": "0.0.0", + "identifier": "MIT", + "text": "MIT License ..." + } +] +``` + +It can be used for further processing to output as a different format. + ## build.manifest - **Type:** `boolean | string` diff --git a/packages/vite/src/node/__tests__/plugins/__snapshots__/license.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/__snapshots__/license.spec.ts.snap new file mode 100644 index 000000000..149e15653 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/__snapshots__/license.spec.ts.snap @@ -0,0 +1,47 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`json 1`] = ` +"[ + { + "name": "@vitejs/test-dep-licence-cc0", + "version": "0.0.0", + "identifier": "CC0-1.0", + "text": "CC0 1.0 Universal\\n\\n..." + }, + { + "name": "@vitejs/test-dep-license-mit", + "version": "0.0.0", + "identifier": "MIT", + "text": "MIT License\\n\\nCopyright (c) ..." + }, + { + "name": "@vitejs/test-dep-nested-license-isc", + "version": "0.0.0", + "identifier": "ISC", + "text": "Copyright (c) ..." + } +]" +`; + +exports[`markdown 1`] = ` +"# Licenses + +The app bundles dependencies which contains the following licenses: + +## @vitejs/test-dep-licence-cc0 - 0.0.0 (CC0-1.0) + +CC0 1.0 Universal + +... + +## @vitejs/test-dep-license-mit - 0.0.0 (MIT) + +MIT License + +Copyright (c) ... + +## @vitejs/test-dep-nested-license-isc - 0.0.0 (ISC) + +Copyright (c) ... +" +`; diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/index.js b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/index.js new file mode 100644 index 000000000..60c71f346 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/index.js @@ -0,0 +1 @@ +export default 'ok' diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/licence b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/licence new file mode 100644 index 000000000..7837407e7 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/licence @@ -0,0 +1,3 @@ +CC0 1.0 Universal + +... diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/package.json new file mode 100644 index 000000000..9e4c8b22a --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0/package.json @@ -0,0 +1,7 @@ +{ + "name": "@vitejs/test-dep-licence-cc0", + "private": true, + "version": "0.0.0", + "type": "module", + "license": "CC0-1.0" +} diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/index.js b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/index.js new file mode 100644 index 000000000..9da0ff4a9 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/index.js @@ -0,0 +1,3 @@ +import nestedDep from '@vitejs/test-dep-nested-licence-isc' + +export default 'ok' + nestedDep diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/license b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/license new file mode 100644 index 000000000..1732da241 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/license @@ -0,0 +1,3 @@ +MIT License + +Copyright (c) ... diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/package.json new file mode 100644 index 000000000..73594817c --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit/package.json @@ -0,0 +1,10 @@ +{ + "name": "@vitejs/test-dep-license-mit", + "private": true, + "version": "0.0.0", + "type": "module", + "license": "MIT", + "dependencies": { + "@vitejs/test-dep-nested-licence-isc": "file:../dep-nested-license-isc" + } +} diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/LICENSE b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/LICENSE new file mode 100644 index 000000000..40ce705e5 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/LICENSE @@ -0,0 +1 @@ +Copyright (c) ... diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/index.js b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/index.js new file mode 100644 index 000000000..60c71f346 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/index.js @@ -0,0 +1 @@ +export default 'ok' diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/package.json new file mode 100644 index 000000000..70b3745d3 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc/package.json @@ -0,0 +1,7 @@ +{ + "name": "@vitejs/test-dep-nested-license-isc", + "private": true, + "version": "0.0.0", + "type": "module", + "license": "ISC" +} diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/index.html b/packages/vite/src/node/__tests__/plugins/fixtures/license/index.html new file mode 100644 index 000000000..b0825ecb3 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/index.html @@ -0,0 +1,5 @@ + diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/package.json new file mode 100644 index 000000000..4e06638e9 --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/package.json @@ -0,0 +1,10 @@ +{ + "name": "@vitejs/test-license", + "private": true, + "version": "0.0.0", + "type": "module", + "dependencies": { + "@vitejs/test-dep-license-mit": "file:./dep-license-mit", + "@vitejs/test-dep-licence-cc0": "file:./dep-licence-cc0" + } +} diff --git a/packages/vite/src/node/__tests__/plugins/license.spec.ts b/packages/vite/src/node/__tests__/plugins/license.spec.ts new file mode 100644 index 000000000..0b410c29f --- /dev/null +++ b/packages/vite/src/node/__tests__/plugins/license.spec.ts @@ -0,0 +1,36 @@ +import { fileURLToPath } from 'node:url' +import type { OutputAsset, RollupOutput } from 'rollup' +import { expect, test } from 'vitest' +import { build } from '../../build' + +test('markdown', async () => { + const result = (await build({ + root: fileURLToPath(new URL('./fixtures/license', import.meta.url)), + logLevel: 'silent', + build: { + write: false, + license: true, + }, + })) as RollupOutput + const licenseAsset = result.output.find( + (asset) => asset.fileName === '.vite/license.md', + ) as OutputAsset | undefined + expect(licenseAsset).toBeDefined() + expect(licenseAsset?.source).toMatchSnapshot() +}) + +test('json', async () => { + const result = (await build({ + root: fileURLToPath(new URL('./fixtures/license', import.meta.url)), + logLevel: 'silent', + build: { + write: false, + license: '.vite/license.json', + }, + })) as RollupOutput + const licenseAsset = result.output.find( + (asset) => asset.fileName === '.vite/license.json', + ) as OutputAsset | undefined + expect(licenseAsset).toBeDefined() + expect(licenseAsset?.source).toMatchSnapshot() +}) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 4564beead..cd4730067 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -201,8 +201,8 @@ export interface BuildEnvironmentOptions { */ copyPublicDir?: boolean /** - * Whether to emit a .vite/license.md that includes all bundled dependencies' - * licenses. Specify a path that ends with `.json` to generate a raw JSON.entry. + * Whether to emit a `.vite/license.md` file that includes all bundled dependencies' + * licenses. Specify a path that ends with `.json` to generate a raw JSON entry. * @default false */ license?: boolean | string diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8236b1c7..b7175d02a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -429,6 +429,25 @@ importers: packages/vite/src/node/__tests__/packages/noname: {} + packages/vite/src/node/__tests__/plugins/fixtures/license: + dependencies: + '@vitejs/test-dep-licence-cc0': + specifier: file:./dep-licence-cc0 + version: file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0 + '@vitejs/test-dep-license-mit': + specifier: file:./dep-license-mit + version: file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit + + packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0: {} + + packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit: + dependencies: + '@vitejs/test-dep-nested-licence-isc': + specifier: file:../dep-nested-license-isc + version: '@vitejs/test-dep-nested-license-isc@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc' + + packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc: {} + packages/vite/src/node/server/__tests__/fixtures/lerna/nested: {} packages/vite/src/node/server/__tests__/fixtures/none/nested: {} @@ -3242,6 +3261,15 @@ packages: '@vitejs/test-dep-incompatible@file:playground/optimize-deps/dep-incompatible': resolution: {directory: playground/optimize-deps/dep-incompatible, type: directory} + '@vitejs/test-dep-licence-cc0@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0': + resolution: {directory: packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0, type: directory} + + '@vitejs/test-dep-license-mit@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit': + resolution: {directory: packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit, type: directory} + + '@vitejs/test-dep-nested-license-isc@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc': + resolution: {directory: packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc, type: directory} + '@vitejs/test-dep-no-discovery@file:playground/optimize-deps-no-discovery/dep-no-discovery': resolution: {directory: playground/optimize-deps-no-discovery/dep-no-discovery, type: directory} @@ -8706,6 +8734,14 @@ snapshots: '@vitejs/test-dep-incompatible@file:playground/optimize-deps/dep-incompatible': {} + '@vitejs/test-dep-licence-cc0@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0': {} + + '@vitejs/test-dep-license-mit@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit': + dependencies: + '@vitejs/test-dep-nested-licence-isc': '@vitejs/test-dep-nested-license-isc@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc' + + '@vitejs/test-dep-nested-license-isc@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc': {} + '@vitejs/test-dep-no-discovery@file:playground/optimize-deps-no-discovery/dep-no-discovery': {} '@vitejs/test-dep-node-env@file:playground/optimize-deps/dep-node-env': {}