Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Generally, the project structure is baked-in to the defaults, however, most of t
* `./examples` - Contains any examples or demos use to test the project
* `./lib` - Generated folder for ES2020 modules and types
* `./src` - Contains all the source code (TypeScript files)
* `./test` - The Jest unit-tests
* `./src/__tests__` - The Jest unit-tests

## Configuration

Expand Down Expand Up @@ -115,13 +115,14 @@ Configuration can be provided using the `extensionConfig` field in **package.jso
* **`environments`** _string[]_ - Environments supports for output, only values supprted `node`, `browser` (default: `['node', 'browser']`)
* **`globals`** _object_ - [Output globals](https://rollupjs.org/guide/en/#outputglobals) as defined by Rollup. This is used for creating the browser bundle. All defaults are provide for the core package of PixiJS (e.g., `@pixi/core`, `@pixi/sprite`, etc).
* **`jestConfig`** _string_ - Optional path to the Jest config file (default: `null`)
* **`lint`** _string[]_ - List of additional folders or files to lint. (default: `['src', 'test', 'examples']`)
* **`lint`** _string[]_ - List of additional folders or files to lint. (default: `['src', 'examples']`)
* **`moduleSource`** _string_ - Input for the `module` output, fallback to `source`. Supports globs. (default: `null`)
* **`namespace`** _string_ - User-defined global namespace for the bundle.
* **`serve`** _string_ - Relative path to the serve folder (default: `examples`).
* **`silent`** _boolean_ - Whether to silence the output (default: `false`)
* **`source`** _string_ - The entry-point for building the extension (default: `src/index.ts`)
* **`tsconfig`** _string_ - Relative path to the tsconfig file for doing type check (default: `tsconfig.json`)
* **`tsconfigTypes`** _string_ - Relative path to the tsconfig file for outputting types, if not defined, will use `tsconfig` option (default: `null`)

### Example

Expand Down
3 changes: 2 additions & 1 deletion lib/configs/jest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default {
// Support for loading vertex and fragment shaders for PixiJS
'\\.vert$': 'jest-raw-loader',
'\\.frag$': 'jest-raw-loader',
'\\.wgsl$': 'jest-raw-loader',
},
testMatch: ['<rootDir>/test/*.test.ts']
testMatch: ['<rootDir>/**/__tests__/*.test.ts']
};
10 changes: 8 additions & 2 deletions lib/configs/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
"sourceMap": true,
"module": "ESNext",
"target": "ES2020",
"moduleResolution": "node",
"moduleResolution": "bundler",
"esModuleInterop": true,
"strict": true,
"noImplicitAny": true
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noImplicitAny": true,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
}
}
3 changes: 2 additions & 1 deletion lib/extensionConfig.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ export const extensionConfig = {
environments: ['browser', 'node'],
globals: {},
jestConfig: null,
lint: ['src', 'test', 'examples'],
lint: ['src', 'examples'],
moduleSource: null,
namespace: defaultNamespace,
serve: 'examples',
silent: false,
source: 'src/index.ts',
tsconfig: 'tsconfig.json',
tsconfigTypes: null,
...pkg.extensionConfig,
};
108 changes: 66 additions & 42 deletions lib/index.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env node

import chalk from 'chalk';
import { glob } from 'glob';
import { promises } from 'node:fs';
import path from 'node:path';
import url from 'url';
Expand Down Expand Up @@ -29,38 +30,40 @@ const bundle = (...args) =>
]);
};

/** Wrapper for using typescript's CLI */
const tsc = async (...args) =>
/** Ensure that the project has a tsconfig */
const ensureTsconfig = async (tsconfigFile) =>
{
const tsconfig = path.join(process.cwd(), extensionConfig.tsconfig);
const tsconfig = tsconfigFile ?? path.join(process.cwd(), extensionConfig.tsconfig);

if (await pathExists(tsconfig))
if (!(await pathExists(tsconfig)))
{
return spawn('tsc', ['-p', tsconfig, ...args]);
// eslint-disable-next-line no-console
console.log(chalk.red(`${prefix} Error: TypeScript configuration file "${path.basename(tsconfig)}"`
+ ` not found but is required for linting and building.`));

process.exit(1);
}

return spawn('tsc', [
extensionConfig.source,
'--target', 'ES2020',
'--module', 'ESNext',
'--sourceMap',
'--moduleResolution', 'node',
'--esModuleInterop',
'--noImplicitAny',
'--strict',
...args,
]);
return tsconfig;
};

/**
* Wrapper for using typescript's CLI
* @param {string} tsconfigFile Optional absolute path to the tsconfig file
*
*/
const tsc = async (tsconfigFile, ...args) =>
spawn('tsc', ['-p', await ensureTsconfig(tsconfigFile), ...args]);

/** Wrapper for Jest */
const test = async (additionalArgs) =>
{
const testPath = path.join(process.cwd(), 'test');
const testFiles = await glob(path.join(process.cwd(), '**/__tests__/*.test.ts'));

if (!(await pathExists(testPath)))
if (testFiles.length === 0)
{
// eslint-disable-next-line no-console
console.log(chalk.yellow(`${prefix} Warning: No "test" folder found, skipping tests.`));
console.log(chalk.yellow(`${prefix} Warning: No *.test.ts files found, skipping tests.`));

return;
}
Expand Down Expand Up @@ -88,40 +91,63 @@ const test = async (additionalArgs) =>
await spawn('jest', [
'--config', configPath ?? path.join(__dirname, 'configs/jest.mjs'),
'--rootDir', process.cwd(),
'--passWithNoTests',
...additionalArgs,
]);
};

/** Export the types */
const bundleTypes = () => tsc(
'--outDir', path.join(process.cwd(), 'lib'),
'--declaration',
'--emitDeclarationOnly'
);

/**
* Fix/hack for importing global mixins for a project
* because tsc will output the wront triple reference
*/
const fixGlobalTypes = async () =>
/** Generate the types into the lib folder */
const bundleTypes = async () =>
{
const globalTypes = path.join(process.cwd(), 'global.d.ts');
let tsconfigTypesFile = extensionConfig.tsconfigTypes
? path.join(process.cwd(), extensionConfig.tsconfigTypes) : null;

if (await pathExists(globalTypes))
// If no tsconfig types file is defined, we will create one
// based on the current tsconfig.json file
if (!tsconfigTypesFile)
{
const indexFile = path.resolve(process.cwd(), 'lib/index.d.ts');
const buffer = await promises.readFile(indexFile, 'utf8');
const tsconfigFile = await ensureTsconfig();

tsconfigTypesFile = tsconfigFile.replace(/\.json$/, '.types.json');
const config = JSON.parse(await promises.readFile(tsconfigFile, 'utf8'));

await promises.writeFile(tsconfigTypesFile, JSON.stringify({
...config,
compilerOptions: {
...config.compilerOptions,
// Just emit the declaration files only
declaration: true,
emitDeclarationOnly: true,
outDir: './lib',
// make sure we exclude anything, such as scripts,
// outside of the src folder to avoid lib/src/index.d.ts
rootDir: './src',
},
// Make sure to exclude any Jest test files
exclude: ['**/__tests__']
}, null, 2), 'utf8');
}

await promises.writeFile(indexFile, buffer.replace(
'/// <reference types="global" />',
'/// <reference path="../global.d.ts" />'
));
try
{
await tsc(tsconfigTypesFile);
}
finally
{
// Clean up if the tsconfig file was generated
if (!extensionConfig.tsconfigTypes)
{
await promises.unlink(tsconfigTypesFile);
}
}
};

/** Run ESlint with built-in config */
const lint = async (additionalArgs = []) =>
{
// Ensure that the project has a tsconfig
await ensureTsconfig();

const eslintMJS = path.join(process.cwd(), 'eslint.config.mjs');
const eslintJS = path.join(process.cwd(), 'eslint.config.js');
const isDefined = 'eslintConfig' in packageInfo
Expand Down Expand Up @@ -264,8 +290,6 @@ const runCommand = async (command, additionalArgs) =>
case Command.Bundle: {
await bundle();
await bundleTypes();
await fixGlobalTypes();

break;
}
case Command.Clean: {
Expand Down Expand Up @@ -298,7 +322,7 @@ const runCommand = async (command, additionalArgs) =>
}
case Command.Serve: serve().then(() => runCommand(Command.Watch)); break;
case Command.Test: await test(additionalArgs); break;
case Command.Types: await tsc('-noEmit'); break;
case Command.Types: await tsc(null, '-noEmit'); break;
case Command.Upload: {
await spawn('gh-pages', [
'-d', extensionConfig.deployRoot,
Expand Down
22 changes: 17 additions & 5 deletions test/examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@
<title>Test</title>
</head>
<body>
<script src="https://pixijs.download/dev/pixi.min.js"></script>
<script src="../dist/pixi-my-system.js"></script>
<script>
const app = new PIXI.Application();
document.body.appendChild(app.view);
<script type="importmap">
{
"imports": {
"pixi.js": "https://cdn.jsdelivr.net/npm/pixi.js@8/dist/pixi.mjs",
"@pixi/my-system": "../dist/pixi-my-system.mjs"
}
}
</script>
<script type="module">
import { Application } from 'pixi.js';
import '@pixi/my-system';
const app = new Application();
await app.init();
document.body.appendChild(app.canvas);
setTimeout(() => {
app.destroy(true);
}, 4000);
</script>
</body>
</html>
6 changes: 4 additions & 2 deletions test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
}
},
"scripts": {
"start": "xs serve",
"build": "xs build",
"clean": "xs clean",
"docs": "xs docs",
Expand All @@ -24,9 +25,10 @@
"watch": "xs watch"
},
"peerDependencies": {
"@pixi/core": "^7.3.0"
"pixi.js": ">=8 <9"
},
"devDependencies": {
"@pixi/extension-scripts": "file:../"
"@pixi/extension-scripts": "file:../",
"pixi.js": "^8.0.0"
}
}
File renamed without changes.
8 changes: 4 additions & 4 deletions test/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { extensions, ExtensionType } from '@pixi/core';
import { extensions, ExtensionType } from 'pixi.js';

import type { ExtensionMetadata, ISystem } from '@pixi/core';
import type { ExtensionMetadata, System } from 'pixi.js';

/**
* Renderer system extension example.
* This doesn't do anything meaningful, but it shows how to create a system extension.
*/
class MySystem implements ISystem
class MySystem implements System
{
/** Metadata to install the extension */
static extension: ExtensionMetadata = {
name: 'mySystem',
type: ExtensionType.RendererSystem,
type: [ExtensionType.WebGLSystem, ExtensionType.WebGPUSystem],
};

/** Currention version can be inlined like this: */
Expand Down
4 changes: 1 addition & 3 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{
"compilerOptions": {
"skipLibCheck": true
}
"extends": "@pixi/extension-scripts/tsconfig"
}
Loading