diff --git a/packages/assetpack/src/core/Asset.ts b/packages/assetpack/src/core/Asset.ts index 52aa791..e60fee5 100644 --- a/packages/assetpack/src/core/Asset.ts +++ b/packages/assetpack/src/core/Asset.ts @@ -253,5 +253,40 @@ export class Asset this.children[i].releaseChildrenBuffers(); } } + + /** + * Get the public meta data for this asset + * This will exclude any internal data + */ + getPublicMetaData(internalPipeData: Record) + { + const internalKeys = new Set(Object.keys(internalPipeData)); + const metaData = Object.keys(this.allMetaData).reduce((result: Record, key) => + { + if (!internalKeys.has(key)) + { + result[key] = this.allMetaData[key]; + } + + return result; + }, {} as Record); + + return metaData; + } + + getInternalMetaData(internalPipeData: Record) + { + const res: Record = {}; + + Object.keys(internalPipeData).forEach((key) => + { + if (this.allMetaData[key]) + { + res[key] = this.allMetaData[key]; + } + }); + + return res; + } } diff --git a/packages/assetpack/src/core/pipes/AssetPipe.ts b/packages/assetpack/src/core/pipes/AssetPipe.ts index 6a2feb6..1662ba3 100644 --- a/packages/assetpack/src/core/pipes/AssetPipe.ts +++ b/packages/assetpack/src/core/pipes/AssetPipe.ts @@ -17,7 +17,7 @@ export type DeepRequired = T extends Primitive }; export interface PluginOptions {} -export interface AssetPipe, TAGS extends string = string> +export interface AssetPipe, TAGS extends string = string, INTERNAL_TAGS extends string = string> { /** Whether the process runs on a folder */ folder?: boolean; @@ -31,6 +31,11 @@ export interface AssetPipe, TAGS extends string = st /** Tags that can be used to control the plugin */ tags?: Record; + /** + * Any tags here will not be placed in the manifest data. + */ + internalTags?: Record; + /** * Called once at the start. * @param asser - the root asset diff --git a/packages/assetpack/src/core/pipes/PipeSystem.ts b/packages/assetpack/src/core/pipes/PipeSystem.ts index 39b528c..6b14e85 100644 --- a/packages/assetpack/src/core/pipes/PipeSystem.ts +++ b/packages/assetpack/src/core/pipes/PipeSystem.ts @@ -28,6 +28,11 @@ export class PipeSystem assetSettings: AssetSettings[] = []; + internalMetaData: Record = { + copy: 'copy', + ignore: 'ignore', + }; + constructor(options: PipeSystemOptions) { const pipes = []; @@ -49,6 +54,7 @@ export class PipeSystem options.pipes.flat().forEach((pipe) => { this.pipeHash[pipe.name] = pipe; + this.internalMetaData = { ...this.internalMetaData, ...Object.values(pipe.internalTags ?? pipe.tags ?? {}).reduce((acc, tag) => ({ ...acc, [tag]: true }), {}) }; }); this.pipes = pipes; diff --git a/packages/assetpack/src/image/compress.ts b/packages/assetpack/src/image/compress.ts index c94d361..aa1acc3 100644 --- a/packages/assetpack/src/image/compress.ts +++ b/packages/assetpack/src/image/compress.ts @@ -97,7 +97,7 @@ export function compress(options: CompressOptions = {}): AssetPipe { - let compressed: CompressImageDataResult[] = []; + let compressed: (Partial & {image: Promise})[] = []; if (!options.astc && !options.bc7 && !options.basis) { - return compressed; + return compressed as CompressImageDataResult[]; } const tmpDir = await fs.mkdtemp(join(tmpdir(), 'assetpack-tex-')); @@ -87,7 +87,7 @@ export async function compressGpuTextures( await fs.rm(tmpDir, { recursive: true, force: true }); } - return compressed; + return compressed as CompressImageDataResult[]; } async function adjustImageSize(sharpImage: sharp.Sharp, imagePath: string): Promise diff --git a/packages/assetpack/src/manifest/pixiManifest.ts b/packages/assetpack/src/manifest/pixiManifest.ts index 127525f..d439f51 100644 --- a/packages/assetpack/src/manifest/pixiManifest.ts +++ b/packages/assetpack/src/manifest/pixiManifest.ts @@ -30,10 +30,49 @@ export interface PixiManifestEntry export interface PixiManifestOptions extends PluginOptions { + /** + * The output location for the manifest file. + */ output?: string; + /** + * if true, the alias will be created with the basename of the file. + */ createShortcuts?: boolean; + /** + * if true, the extensions will be removed from the alias names. + */ trimExtensions?: boolean; + /** + * if true, the metaData will be outputted in the data field of the manifest. + */ includeMetaData?: boolean; + /** + * if true, the all tags will be outputted in the data.tags field of the manifest. + * If false, only internal tags will be outputted to the data.tags field. All other tags will be outputted to the data field directly. + * @example + * ```json + * { + * "bundles": [ + * { + * "name": "default", + * "assets": [ + * { + * "alias": ["test"], + * "src": ["test.png"], + * "data": { + * "tags": { + * "nc": true, + * "customTag": true // this tag will be outputted to the data field directly instead of the data.tags field + * } + * } + * } + * ] + * } + * ] + * } + * @default true + */ + legacyMetaDataOutput?: boolean; } export function pixiManifest(_options: PixiManifestOptions = {}): AssetPipe @@ -45,6 +84,7 @@ export function pixiManifest(_options: PixiManifestOptions = {}): AssetPipe['tags'] + tags: AssetPipe['tags'], + internalTags: Record ) { if (asset.skip) return; @@ -137,20 +179,28 @@ function collectAssets( if (finalManifestAssets.length === 0) return; + const metadata = { + tags: { ...asset.getInternalMetaData(internalTags) }, + ...asset.getPublicMetaData(internalTags) + } as Record; + + if (options.legacyMetaDataOutput) + { + metadata.tags = asset.allMetaData; + } + bundleAssets.push({ alias: getShortNames(stripTags(path.relative(entryPath, asset.path)), options), src: finalManifestAssets .map((finalAsset) => path.relative(outputPath, finalAsset.path)) .sort((a, b) => b.localeCompare(a)), - data: options.includeMetaData ? { - tags: asset.allMetaData - } : undefined + data: options.includeMetaData ? metadata : undefined }); } asset.children.forEach((child) => { - collectAssets(child, options, outputPath, entryPath, bundles, localBundle, tags); + collectAssets(child, options, outputPath, entryPath, bundles, localBundle, tags, internalTags); }); // for all assets.. check for atlas and remove them from the bundle.. diff --git a/packages/assetpack/src/webfont/sdf.ts b/packages/assetpack/src/webfont/sdf.ts index 9b16132..5749f09 100644 --- a/packages/assetpack/src/webfont/sdf.ts +++ b/packages/assetpack/src/webfont/sdf.ts @@ -1,6 +1,6 @@ import fs from 'fs-extra'; import generateBMFont from 'msdf-bmfont-xml'; -import { checkExt, createNewAssetAt, stripTags } from '../core/index.js'; +import { checkExt, createNewAssetAt, path, stripTags } from '../core/index.js'; import type { BitmapFontOptions } from 'msdf-bmfont-xml'; import type { Asset, AssetPipe, PluginOptions } from '../core/index.js'; @@ -33,6 +33,8 @@ function signedFont( { const newFileName = stripTags(asset.filename.replace(/\.(ttf)$/i, '')); + // set the family name to the filename if it doesn't exist + asset.metaData.family ??= path.trimExt(asset.filename); const { font, textures } = await GenerateFont(asset.path, { ...options.font, filename: newFileName, diff --git a/packages/assetpack/src/webfont/webfont.ts b/packages/assetpack/src/webfont/webfont.ts index 3f56165..4ed2471 100644 --- a/packages/assetpack/src/webfont/webfont.ts +++ b/packages/assetpack/src/webfont/webfont.ts @@ -43,6 +43,9 @@ export function webfont(): AssetPipe newAsset.buffer = buffer; + // set the family name to the filename if it doesn't exist + asset.metaData.family ??= path.trimExt(asset.filename); + return [newAsset]; } }; diff --git a/packages/assetpack/test/manifest/Manifest.test.ts b/packages/assetpack/test/manifest/Manifest.test.ts index 31f344e..b76691d 100644 --- a/packages/assetpack/test/manifest/Manifest.test.ts +++ b/packages/assetpack/test/manifest/Manifest.test.ts @@ -225,6 +225,7 @@ describe('Manifest', () => alias: ['spine/dragon.atlas'], src: ['spine/dragon@0.5x.atlas', 'spine/dragon.atlas'], data: { + spine: true, tags: { spine: true, }, diff --git a/packages/assetpack/test/spine/spineAtlasAll.test.ts b/packages/assetpack/test/spine/spineAtlasAll.test.ts index eefc4d5..2d29ff9 100644 --- a/packages/assetpack/test/spine/spineAtlasAll.test.ts +++ b/packages/assetpack/test/spine/spineAtlasAll.test.ts @@ -168,6 +168,7 @@ describe('Spine Atlas All', () => // remove the outputDir file = file.replace(`${outputDir}/`, ''); const isFileHalfSize = file.includes('@0.5x'); + // eslint-disable-next-line no-nested-ternary const isFileFileType = file.includes(isWebp ? '.webp' : isAstc ? '.astc' : '.png'); const shouldExist = isHalfSize === isFileHalfSize && isFileType === isFileFileType; diff --git a/packages/assetpack/test/spine/spineAtlasManifest.test.ts b/packages/assetpack/test/spine/spineAtlasManifest.test.ts index 2a24b3d..f546e62 100644 --- a/packages/assetpack/test/spine/spineAtlasManifest.test.ts +++ b/packages/assetpack/test/spine/spineAtlasManifest.test.ts @@ -78,6 +78,7 @@ describe('Atlas Manifest', () => 'dragon.atlas' ], data: { + spine: true, tags: { spine: true } @@ -182,6 +183,7 @@ describe('Atlas Manifest', () => 'dragon.atlas' ], data: { + spine: true, tags: { spine: true } @@ -206,6 +208,7 @@ describe('Atlas Manifest', () => 'nested/dragon.atlas' ], data: { + spine: true, tags: { spine: true } diff --git a/packages/assetpack/test/texture-packer/texturePackerAll.test.ts b/packages/assetpack/test/texture-packer/texturePackerAll.test.ts index 3d39700..494921c 100644 --- a/packages/assetpack/test/texture-packer/texturePackerAll.test.ts +++ b/packages/assetpack/test/texture-packer/texturePackerAll.test.ts @@ -85,6 +85,7 @@ describe('Texture Packer All', () => // remove the outputDir file = file.replace(`${outputDir}/`, ''); const isFileHalfSize = file.includes('@0.5x'); + // eslint-disable-next-line no-nested-ternary const isFileFileType = file.includes(isWebp ? '.webp' : isAstc ? '.astc.ktx' : '.png'); const shouldExist = isHalfSize === isFileHalfSize && isFileType === isFileFileType; diff --git a/packages/assetpack/test/texture-packer/texturePackerCompress.test.ts b/packages/assetpack/test/texture-packer/texturePackerCompress.test.ts index d9e867f..9ca4964 100644 --- a/packages/assetpack/test/texture-packer/texturePackerCompress.test.ts +++ b/packages/assetpack/test/texture-packer/texturePackerCompress.test.ts @@ -52,5 +52,5 @@ describe('Texture Packer Compression', () => expect(sheetWebp.meta.image).toEqual(`sprites.webp`); expect(sheetAstc.meta.image).toEqual(`sprites.astc.ktx`); expect(sheetBasis.meta.image).toEqual(`sprites.basis.ktx2`); - }); + }, { timeout: 20000 }); }); diff --git a/packages/assetpack/test/texture-packer/texturePackerManifest.test.ts b/packages/assetpack/test/texture-packer/texturePackerManifest.test.ts index 7245c96..12932fb 100644 --- a/packages/assetpack/test/texture-packer/texturePackerManifest.test.ts +++ b/packages/assetpack/test/texture-packer/texturePackerManifest.test.ts @@ -110,5 +110,5 @@ describe('Texture Packer Compression', () => } }, ]); - }); + }, { timeout: 20000 }); }); diff --git a/packages/assetpack/test/webfont/Webfont.test.ts b/packages/assetpack/test/webfont/Webfont.test.ts index b924fc9..ea7e695 100644 --- a/packages/assetpack/test/webfont/Webfont.test.ts +++ b/packages/assetpack/test/webfont/Webfont.test.ts @@ -293,7 +293,7 @@ describe('Webfont', () => msdfFont(), mipmap(), compress(), - pixiManifest(), + pixiManifest({ legacyMetaDataOutput: false }), ] }); @@ -309,36 +309,40 @@ describe('Webfont', () => alias: ['defaultFolder/ttf.ttf'], src: ['defaultFolder/ttf.woff2'], data: { + family: 'ttf', tags: { wf: true, - } + }, } }, { alias: ['msdfFolder/ttf.ttf'], src: ['msdfFolder/ttf.fnt'], data: { + family: 'ttf', tags: { msdf: true, - } + }, } }, { alias: ['sdfFolder/ttf.ttf'], src: ['sdfFolder/ttf.fnt'], data: { + family: 'ttf', tags: { sdf: true, - } + }, } }, { alias: ['svgFolder/svg.svg'], src: ['svgFolder/svg.woff2'], data: { + family: 'svg', tags: { wf: true, - } + }, } }, ], diff --git a/packages/assetpack/vitest.config.js b/packages/assetpack/vitest.config.js index 558d2fc..95696c1 100644 --- a/packages/assetpack/vitest.config.js +++ b/packages/assetpack/vitest.config.js @@ -2,6 +2,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { + testTimeout: 10000, poolOptions: { threads: { // Due to the cpu-features and vitest threads incompatibility, see: diff --git a/packages/docs/docs/guide/pipes/overview.mdx b/packages/docs/docs/guide/pipes/overview.mdx index be273fc..5c5d6dd 100644 --- a/packages/docs/docs/guide/pipes/overview.mdx +++ b/packages/docs/docs/guide/pipes/overview.mdx @@ -57,5 +57,12 @@ Each plugin has its own set of tags, so be sure to check the documentation for t ### Other Tag Examples - You can also add multiple tags to a single asset, like this `asset{tag1}{tag2}`. -- Tags can have data appended to them, like this `asset{tag1:myData}`. -- Tags can have multiple data values, like this `asset{tag1:100,200}`. +- Tags can have data appended to them, like this `asset{tag1=myData}`. +- Tags can have multiple data values, like this `asset{tag1=100&200}`. + +### Data Tags + +Data tags are a special type of tag that a plugin can specify to allow for the value of that tag to be passed to the manifest. +This can be useful for PixiJS as in the manifest you can specify certain properties for each asset. + +For example, the webfont plugin has a `family` tag that can be used to specify the font family name of the font file. diff --git a/packages/docs/docs/guide/pipes/webfont.mdx b/packages/docs/docs/guide/pipes/webfont.mdx index 0bd9bad..3907127 100644 --- a/packages/docs/docs/guide/pipes/webfont.mdx +++ b/packages/docs/docs/guide/pipes/webfont.mdx @@ -30,9 +30,10 @@ export default { ### Tags -| Tag | Folder/File | Description | -| ---- | ----------- | -------------------------------------------------------------- | -| `wf` | `both` | If present the file(s) will be converted to a webfont (woff2). | +| Tag | Folder/File | Description | +| -------- | ----------- | -------------------------------------------------------------- | +| `wf` | `both` | If present the file(s) will be converted to a webfont (woff2). | +| `family` | `file` | The font family name. | --- @@ -80,7 +81,8 @@ export default { ### Tags -| Tag | Folder/File | Description | -| ------ | ----------- | -------------------------------------------------------- | -| `sdf` | `both` | If present the file(s) will be converted to a SDF font. | -| `msdf` | `both` | If present the file(s) will be converted to a MSDF font. | +| Tag | Folder/File | Description | +| -------- | ----------- | -------------------------------------------------------- | +| `sdf` | `both` | If present the file(s) will be converted to a SDF font. | +| `msdf` | `both` | If present the file(s) will be converted to a MSDF font. | +| `family` | `file` | The font family name. |