diff --git a/packages/vite/schemas/manifest.schema.json b/packages/vite/schemas/manifest.schema.json new file mode 100644 index 00000000000000..6ba533a6cc42a7 --- /dev/null +++ b/packages/vite/schemas/manifest.schema.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://vitejs.dev/schemas/manifest.json", + "title": "Vite Manifest", + "type": "object", + "patternProperties": { + "^.+$": { + "$ref": "#/$defs/chunk" + } + }, + "$defs": { + "chunk": { + "type": "object", + "properties": { + "src": { + "type": "string", + "description": "Source file of the chunk." + }, + "file": { + "type": "string", + "description": "A JS filename, relative to the outDir." + }, + "css": { + "type": "array", + "description": "CSS files imported by the chunk.", + "items": { + "type": "string", + "description": "A CSS filename, relative to the outDir." + } + }, + "assets": { + "type": "array", + "description": "Assets imported by the chunk.", + "items": { + "type": "string", + "description": "An asset filename, relative to the outDir." + } + }, + "isEntry": { + "type": "boolean", + "description": "Whether the chunk is an entry." + }, + "isDynamicEntry": { + "type": "boolean", + "description": "Whether the chunk is a dynamic entry." + }, + "imports": { + "type": "array", + "description": "Imports of the chunk.", + "items": { + "type": "string", + "description": "A key for an existing JS entry in the manifest." + } + }, + "dynamicImports": { + "type": "array", + "description": "Dynamic imports of the chunk.", + "items": { + "type": "string", + "description": "A key for an existing JS entry in the manifest." + } + } + }, + "additionalProperties": true, + "required": ["file"] + } + } +} diff --git a/packages/vite/schemas/ssr-manifest.schema.json b/packages/vite/schemas/ssr-manifest.schema.json new file mode 100644 index 00000000000000..b5cd4eda597a4c --- /dev/null +++ b/packages/vite/schemas/ssr-manifest.schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://vitejs.dev/schemas/ssr-manifest.json", + "title": "Vite SSR Manifest", + "type": "object", + "patternProperties": { + "^.+$": { + "type": "array", + "items": { + "type": "string" + } + } + } +} diff --git a/playground/backend-integration/__tests__/manifests/additionalProperties.manifest.json b/playground/backend-integration/__tests__/manifests/additionalProperties.manifest.json new file mode 100644 index 00000000000000..32284b81dd8a01 --- /dev/null +++ b/playground/backend-integration/__tests__/manifests/additionalProperties.manifest.json @@ -0,0 +1,6 @@ +{ + "main.js": { + "file": "test", + "customProperty": "custom value" + } +} diff --git a/playground/backend-integration/__tests__/manifests/invalid.manifest.json b/playground/backend-integration/__tests__/manifests/invalid.manifest.json new file mode 100644 index 00000000000000..84872a5f4e8577 --- /dev/null +++ b/playground/backend-integration/__tests__/manifests/invalid.manifest.json @@ -0,0 +1,18 @@ +{ + "main.js": { + "src": "main.js", + "isEntry": true, + "dynamicImports": ["views/foo.js"], + "css": ["assets/main.b82dbe22.css"], + "assets": ["assets/asset.0ab0f9cd.png"] + }, + "views/foo.js": { + "file": "assets/foo.869aea0d.js", + "src": "views/foo.js", + "isDynamicEntry": true, + "imports": ["_shared.83069a53.js"] + }, + "_shared.83069a53.js": { + "file": "assets/shared.83069a53.js" + } +} diff --git a/playground/backend-integration/__tests__/manifests/manifest-schema.spec.ts b/playground/backend-integration/__tests__/manifests/manifest-schema.spec.ts new file mode 100644 index 00000000000000..ed9705d8c06ce9 --- /dev/null +++ b/playground/backend-integration/__tests__/manifests/manifest-schema.spec.ts @@ -0,0 +1,25 @@ +import Ajv2020 from 'ajv/dist/2020' + +const schema = require('../../../../packages/vite/schemas/manifest.schema.json') +const ajv = new Ajv2020() +const validate = ajv.compile(schema) + +describe('manifest json schema', () => { + test('valid manifest validates against manifest schema', () => { + const manifest = require('./valid.manifest.json') + const result = validate(manifest) + expect(result).toBeTruthy() + }) + + test('invalid manifest does not validate against manifest schema', () => { + const manifest = require('./invalid.manifest.json') + const result = validate(manifest) + expect(result).toBeFalsy() + }) + + test('manifest chunks support additional properties', () => { + const manifest = require('./additionalProperties.manifest.json') + const result = validate(manifest) + expect(result).toBeTruthy() + }) +}) diff --git a/playground/backend-integration/__tests__/manifests/valid.manifest.json b/playground/backend-integration/__tests__/manifests/valid.manifest.json new file mode 100644 index 00000000000000..3d9ba04e076f3c --- /dev/null +++ b/playground/backend-integration/__tests__/manifests/valid.manifest.json @@ -0,0 +1,19 @@ +{ + "main.js": { + "file": "assets/main.4889e940.js", + "src": "main.js", + "isEntry": true, + "dynamicImports": ["views/foo.js"], + "css": ["assets/main.b82dbe22.css"], + "assets": ["assets/asset.0ab0f9cd.png"] + }, + "views/foo.js": { + "file": "assets/foo.869aea0d.js", + "src": "views/foo.js", + "isDynamicEntry": true, + "imports": ["_shared.83069a53.js"] + }, + "_shared.83069a53.js": { + "file": "assets/shared.83069a53.js" + } +} diff --git a/playground/backend-integration/package.json b/playground/backend-integration/package.json index ead0c3a70d8e10..1a9bbcbf9db3a2 100644 --- a/playground/backend-integration/package.json +++ b/playground/backend-integration/package.json @@ -11,6 +11,7 @@ "devDependencies": { "sass": "^1.53.0", "tailwindcss": "^3.1.4", + "ajv": "^8.11.0", "fast-glob": "^3.2.11" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 404ceea6b8f837..a2ebdaacd64678 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -360,10 +360,12 @@ importers: playground/backend-integration: specifiers: + ajv: ^8.11.0 fast-glob: ^3.2.11 sass: ^1.53.0 tailwindcss: ^3.1.4 devDependencies: + ajv: 8.11.0 fast-glob: 3.2.11 sass: 1.53.0 tailwindcss: 3.1.4 @@ -2920,6 +2922,15 @@ packages: uri-js: 4.4.1 dev: true + /ajv/8.11.0: + resolution: {integrity: sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: true + /algoliasearch/4.13.1: resolution: {integrity: sha512-dtHUSE0caWTCE7liE1xaL+19AFf6kWEcyn76uhcitWpntqvicFHXKFoZe5JJcv9whQOTRM6+B8qJz6sFj+rDJA==} dependencies: @@ -5690,6 +5701,10 @@ packages: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true + /json-schema-traverse/1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + /json-stable-stringify-without-jsonify/1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true @@ -7287,6 +7302,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /require-from-string/2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + /requires-port/1.0.0: resolution: {integrity: sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=} dev: true