0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

feat(toolbar): Toolbar API improvements (#10665)

* feat(toolbar): Add a `astro:toolbar` module

* fix: use entrypoint

* feat: add new shape for defining toolbar apps

* fix: types

* feat(toolbar): Add helpers features (#10667)

* feat(toolbar): Add helpers features

* fix: consistent payloads and naming

* chore: changeset

* nit: rename eventTarget to app

* feat: add server-side helpers

* test: update test to use new APIs

* fix: types

* nit: erikaaaaa

* feat: add new event

* Update .changeset/khaki-pianos-burn.md

* test: use data to create text

* Apply suggestions from code review

Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>

* nit: use diff

* nit: documentation effort

* test: fix

---------

Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>

* nit: small changes to helpers

* nit: update changeset

* fix: move to astro/toolbar for building purposes

* feat(toolbar): Add a toolbar example (#10793)

* feat: add a toolbar starter

* test: skip examples that are not Astro projects

* nit: small changes

* feat: setup for build step

* fix: add to devdep

* docs: add commands to README

* fix: reorder classes to make more sense

* fix: add improvements from recipe

* Apply suggestions from code review

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

---------

Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
Erika 2024-04-24 17:56:12 +02:00 committed by GitHub
parent 6fc4c0e420
commit 7b4f284020
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 453 additions and 47 deletions

View file

@ -0,0 +1,53 @@
---
"astro": minor
---
Adds new utilities to ease the creation of toolbar apps including `defineToolbarApp` to make it easier to define your toolbar app and `app` and `server` helpers for easier communication between the toolbar and the server. These new utilities abstract away some of the boilerplate code that is common in toolbar apps, and lower the barrier of entry for app authors.
For example, instead of creating an event listener for the `app-toggled` event and manually typing the value in the callback, you can now use the `onAppToggled` method. Additionally, communicating with the server does not require knowing any of the Vite APIs anymore, as a new `server` object is passed to the `init` function that contains easy to use methods for communicating with the server.
```diff
import { defineToolbarApp } from "astro/toolbar";
export default defineToolbarApp({
init(canvas, app, server) {
- app.addEventListener("app-toggled", (e) => {
- console.log(`App is now ${state ? "enabled" : "disabled"}`);.
- });
+ app.onToggled(({ state }) => {
+ console.log(`App is now ${state ? "enabled" : "disabled"}`);
+ });
- if (import.meta.hot) {
- import.meta.hot.send("my-app:my-client-event", { message: "world" });
- }
+ server.send("my-app:my-client-event", { message: "world" })
- if (import.meta.hot) {
- import.meta.hot.on("my-server-event", (data: {message: string}) => {
- console.log(data.message);
- });
- }
+ server.on<{ message: string }>("my-server-event", (data) => {
+ console.log(data.message); // data is typed using the type parameter
+ });
},
})
```
Server helpers are also available on the server side, for use in your integrations, through the new `toolbar` object:
```ts
"astro:server:setup": ({ toolbar }) => {
toolbar.on<{ message: string }>("my-app:my-client-event", (data) => {
console.log(data.message);
toolbar.send("my-server-event", { message: "hello" });
});
}
```
This is a backwards compatible change and your your existing dev toolbar apps will continue to function. However, we encourage you to build your apps with the new helpers, following the [updated Dev Toolbar API documentation](https://docs.astro.build/en/reference/dev-toolbar-app-reference/).

View file

@ -0,0 +1 @@
FROM node:18-bullseye

21
examples/toolbar-app/.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# dependencies
node_modules/
# production build
dist
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# jetbrains setting folder
.idea/

View file

@ -0,0 +1,40 @@
# Astro Starter Kit: Toolbar App
```sh
npm create astro@latest -- --template toolbar-app
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/toolbar-app)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/toolbar-app)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/toolbar-app/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
/
├── app.ts
├── integration.ts
└── package.json
```
The logic of your app is in the appropriately named `app.ts` file. This is where the vast majority of your toolbar app logic will live.
The `integration.ts` file is a simple Astro integration file that will be used to add your app into the toolbar.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :------------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Watch for changes and build your app automatically |
| `npm run build` | Build your app to `./dist/` |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

View file

@ -0,0 +1,20 @@
{
"name": "@example/toolbar-app",
"type": "module",
"version": "0.0.1",
"peerDependencies": {
"astro": "^4.6.1"
},
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"prepublish": "npm run build"
},
"exports": {
".": "./dist/integration.js",
"./app": "./dist/app.js"
},
"devDependencies": {
"astro": "^4.6.1"
}
}

View file

@ -0,0 +1,16 @@
import { defineToolbarApp } from 'astro/toolbar';
// Guide: https://docs.astro.build/en/recipes/making-toolbar-apps/
// API Reference: https://docs.astro.build/en/reference/dev-toolbar-app-reference/
export default defineToolbarApp({
init(canvas) {
const astroWindow = document.createElement('astro-dev-toolbar-window');
const text = document.createElement('p');
text.textContent = 'Hello, Astro!';
astroWindow.append(text);
canvas.append(astroWindow);
},
});

View file

@ -0,0 +1,17 @@
import { fileURLToPath } from 'node:url';
import type { AstroIntegration } from 'astro';
// API Reference: https://docs.astro.build/en/reference/integrations-reference/
export default {
name: 'my-astro-integration',
hooks: {
'astro:config:setup': ({ addDevToolbarApp }) => {
addDevToolbarApp({
id: "my-toolbar-app",
name: "My Toolbar App",
icon: "🚀",
entrypoint: fileURLToPath(new URL('./app.js', import.meta.url))
});
},
},
} satisfies AstroIntegration;

View file

@ -0,0 +1,7 @@
{
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
}
}

View file

@ -304,6 +304,8 @@ test.describe('Dev Toolbar', () => {
await expect(myAppWindow).toHaveCount(1);
await expect(myAppWindow).toBeVisible();
await expect(myAppWindow).toContainText('Hello from the server!');
// Toggle app off
await appButton.click();
await expect(myAppWindow).not.toBeVisible();

View file

@ -10,8 +10,18 @@ export function myIntegration() {
const importPath = dirname(fileURLToPath(import.meta.url));
const pluginPath = join(importPath, 'custom-plugin.js');
addDevToolbarApp(pluginPath);
addDevToolbarApp({
id: 'my-plugin',
name: 'My Plugin',
icon: 'astro:logo',
entrypoint: pluginPath
});
},
'astro:server:setup': ({ toolbar }) => {
toolbar.onAppInitialized("my-plugin", () => {
toolbar.send("super-server-event", { message: "Hello from the server!" })
});
}
},
};
}

View file

@ -1,8 +1,7 @@
export default {
id: 'my-plugin',
name: 'My Plugin',
icon: 'astro:logo',
init(canvas, eventTarget) {
import { defineToolbarApp } from "astro/toolbar";
export default defineToolbarApp({
init(canvas, app, server) {
const astroWindow = document.createElement('astro-dev-toolbar-window');
const myButton = document.createElement('astro-dev-toolbar-button');
myButton.size = 'medium';
@ -13,16 +12,17 @@ export default {
console.log('Clicked!');
});
eventTarget.dispatchEvent(
new CustomEvent("toggle-notification", {
detail: {
level: "warning",
},
})
);
app.toggleNotification({
state: true,
level: 'warning'
})
server.on("super-server-event", (data) => {
astroWindow.appendChild(document.createTextNode(data.message));
});
astroWindow.appendChild(myButton);
canvas.appendChild(astroWindow);
},
};
});

View file

@ -53,6 +53,7 @@
"./client/*": "./dist/runtime/client/*",
"./components": "./components/index.ts",
"./components/*": "./components/*",
"./toolbar": "./dist/toolbar/index.js",
"./assets": "./dist/assets/index.js",
"./assets/utils": "./dist/assets/utils/index.js",
"./assets/endpoint/*": "./dist/assets/endpoint/*.js",

View file

@ -38,10 +38,15 @@ import type {
TransitionBeforePreparationEvent,
TransitionBeforeSwapEvent,
} from '../transitions/events.js';
import type { DeepPartial, OmitIndexSignature, Simplify } from '../type-utils.js';
import type { DeepPartial, OmitIndexSignature, Simplify, WithRequired } from '../type-utils.js';
import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
import type {
ToolbarAppEventTarget,
ToolbarServerHelpers,
} from '../runtime/client/dev-toolbar/helpers.js';
import type { getToolbarServerCommunicationHelpers } from '../integrations/index.js';
export { type AstroIntegrationLogger };
export type { AstroIntegrationLogger, ToolbarServerHelpers };
export type {
MarkdownHeading,
@ -2100,7 +2105,7 @@ export interface AstroSettings {
* Map of directive name (e.g. `load`) to the directive script code
*/
clientDirectives: Map<string, string>;
devToolbarApps: string[];
devToolbarApps: (DevToolbarAppEntry | string)[];
middlewares: { pre: string[]; post: string[] };
tsConfig: TSConfig | undefined;
tsConfigPath: string | undefined;
@ -2735,7 +2740,8 @@ export interface AstroIntegration {
* TODO: Fully remove in Astro 5.0
*/
addDevOverlayPlugin: (entrypoint: string) => void;
addDevToolbarApp: (entrypoint: string) => void;
// TODO: Deprecate the `string` overload once a few apps have been migrated to the new API.
addDevToolbarApp: (entrypoint: DevToolbarAppEntry | string) => void;
addMiddleware: (mid: AstroIntegrationMiddleware) => void;
logger: AstroIntegrationLogger;
// TODO: Add support for `injectElement()` for full HTML element injection, not just scripts.
@ -2751,6 +2757,7 @@ export interface AstroIntegration {
'astro:server:setup'?: (options: {
server: vite.ViteDevServer;
logger: AstroIntegrationLogger;
toolbar: ReturnType<typeof getToolbarServerCommunicationHelpers>;
}) => void | Promise<void>;
'astro:server:start'?: (options: {
address: AddressInfo;
@ -3006,13 +3013,53 @@ export interface ClientDirectiveConfig {
entrypoint: string;
}
export interface DevToolbarApp {
type DevToolbarAppMeta = {
id: string;
name: string;
icon?: Icon;
init?(canvas: ShadowRoot, eventTarget: EventTarget): void | Promise<void>;
};
// The param passed to `addDevToolbarApp` in the integration
export type DevToolbarAppEntry = DevToolbarAppMeta & {
entrypoint: string;
};
// Public API for the dev toolbar
export type DevToolbarApp = {
/**
* @deprecated The `id`, `name`, and `icon` properties should now be defined when using `addDevToolbarApp`.
*
* Ex: `addDevToolbarApp({ id: 'my-app', name: 'My App', icon: '🚀', entrypoint: '/path/to/app' })`
*
* In the future, putting these properties directly on the app object will be removed.
*/
id?: string;
/**
* @deprecated The `id`, `name`, and `icon` properties should now be defined when using `addDevToolbarApp`.
*
* Ex: `addDevToolbarApp({ id: 'my-app', name: 'My App', icon: '🚀', entrypoint: '/path/to/app' })`
*
* In the future, putting these properties directly on the app object will be removed.
*/
name?: string;
/**
* @deprecated The `id`, `name`, and `icon` properties should now be defined when using `addDevToolbarApp`.
*
* Ex: `addDevToolbarApp({ id: 'my-app', name: 'My App', icon: '🚀', entrypoint: '/path/to/app' })`
*
* In the future, putting these properties directly on the app object will be removed.
*/
icon?: Icon;
init?(
canvas: ShadowRoot,
app: ToolbarAppEventTarget,
server: ToolbarServerHelpers
): void | Promise<void>;
beforeTogglingOff?(canvas: ShadowRoot): boolean | Promise<boolean>;
}
};
// An app that has been loaded and as such contain all of its properties
export type ResolvedDevToolbarApp = DevToolbarAppMeta & Omit<DevToolbarApp, 'id' | 'name' | 'icon'>;
// TODO: Remove in Astro 5.0
export type DevOverlayPlugin = DevToolbarApp;

View file

@ -18,7 +18,7 @@ import astroPostprocessVitePlugin from '../vite-plugin-astro-postprocess/index.j
import { vitePluginAstroServer } from '../vite-plugin-astro-server/index.js';
import astroVitePlugin from '../vite-plugin-astro/index.js';
import configAliasVitePlugin from '../vite-plugin-config-alias/index.js';
import astroDevToolbar from '../vite-plugin-dev-toolbar/vite-plugin-dev-toolbar.js';
import astroDevToolbar from '../toolbar/vite-plugin-dev-toolbar.js';
import envVitePlugin from '../vite-plugin-env/index.js';
import vitePluginFileURL from '../vite-plugin-fileurl/index.js';
import astroHeadPlugin from '../vite-plugin-head/index.js';

View file

@ -61,6 +61,45 @@ function getLogger(integration: AstroIntegration, logger: Logger) {
return integrationLogger;
}
const serverEventPrefix = 'astro-dev-toolbar';
export function getToolbarServerCommunicationHelpers(server: ViteDevServer) {
return {
/**
* Send a message to the dev toolbar that an app can listen for. The payload can be any serializable data.
* @param event - The event name
* @param payload - The payload to send
*/
send: <T>(event: string, payload: T) => {
server.hot.send(event, payload);
},
/**
* Receive a message from a dev toolbar app.
* @param event
* @param callback
*/
on: <T>(event: string, callback: (data: T) => void) => {
server.hot.on(event, callback);
},
/**
* Fired when an app is initialized.
* @param appId - The id of the app that was initialized
* @param callback - The callback to run when the app is initialized
*/
onAppInitialized: (appId: string, callback: (data: Record<string, never>) => void) => {
server.hot.on(`${serverEventPrefix}:${appId}:initialized`, callback);
},
/**
* Fired when an app is toggled on or off.
* @param appId - The id of the app that was toggled
* @param callback - The callback to run when the app is toggled
*/
onAppToggled: (appId: string, callback: (data: { state: boolean }) => void) => {
server.hot.on(`${serverEventPrefix}:${appId}:toggled`, callback);
},
};
}
export async function runHookConfigSetup({
settings,
command,
@ -305,6 +344,7 @@ export async function runHookServerSetup({
hookResult: integration.hooks['astro:server:setup']({
server,
logger: getLogger(integration, logger),
toolbar: getToolbarServerCommunicationHelpers(server),
}),
logger,
});

View file

@ -1,8 +1,9 @@
// @ts-expect-error
import { loadDevToolbarApps } from 'astro:dev-toolbar';
import type { DevToolbarApp as DevToolbarAppDefinition } from '../../../@types/astro.js';
import type { ResolvedDevToolbarApp as DevToolbarAppDefinition } from '../../../@types/astro.js';
import { ToolbarAppEventTarget } from './helpers.js';
import { settings } from './settings.js';
import type { AstroDevToolbar, DevToolbarApp } from './toolbar.js';
// @ts-expect-error - This module is private and untyped
import { loadDevToolbarApps } from 'astro:toolbar:internal';
let overlay: AstroDevToolbar;
@ -74,7 +75,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} as const;
const prepareApp = (appDefinition: DevToolbarAppDefinition, builtIn: boolean): DevToolbarApp => {
const eventTarget = new EventTarget();
const eventTarget = new ToolbarAppEventTarget();
const app: DevToolbarApp = {
...appDefinition,
builtIn: builtIn,

View file

@ -0,0 +1,103 @@
type NotificationPayload = {
state: true;
level?: 'error' | 'warn' | 'info';
} | {
state: false
};
type AppStatePayload = {
state: boolean;
};
type AppToggledEvent = (opts: { state: boolean }) => void;
type ToolbarPlacementUpdatedEvent = (opts: { placement: 'bottom-left' | 'bottom-center' | 'bottom-right' }) => void;
export class ToolbarAppEventTarget extends EventTarget {
constructor() {
super();
}
/**
* Toggle the notification state of the toolbar
* @param options - The notification options
* @param options.state - The state of the notification
* @param options.level - The level of the notification, optional when state is false
*/
toggleNotification(options: NotificationPayload) {
this.dispatchEvent(
new CustomEvent('toggle-notification', {
detail: {
state: options.state,
level: options.state === true ? options.level : undefined,
} satisfies NotificationPayload,
})
);
}
/**
* Toggle the app state on or off
* @param options - The app state options
* @param options.state - The new state of the app
*/
toggleState(options: AppStatePayload) {
this.dispatchEvent(
new CustomEvent('app-toggled', {
detail: {
state: options.state,
} satisfies AppStatePayload,
})
);
}
/**
* Fired when the app is toggled on or off
* @param callback - The callback to run when the event is fired, takes an object with the new state
*/
onToggled(callback: AppToggledEvent) {
this.addEventListener('app-toggled', (evt) => {
if (!(evt instanceof CustomEvent)) return;
callback(evt.detail);
});
}
/**
* Fired when the toolbar placement is updated by the user
* @param callback - The callback to run when the event is fired, takes an object with the new placement
*/
onToolbarPlacementUpdated(callback: ToolbarPlacementUpdatedEvent) {
this.addEventListener('placement-updated', (evt) => {
if (!(evt instanceof CustomEvent)) return;
callback(evt.detail);
});
}
}
export const serverHelpers = {
/**
* Send a message to the server, the payload can be any serializable data.
*
* The server can listen for this message in the `astro:server:config` hook of an Astro integration, using the `toolbar.on` method.
*
* @param event - The event name
* @param payload - The payload to send
*/
send: <T>(event: string, payload: T) => {
if (import.meta.hot) {
import.meta.hot.send(event, payload);
}
},
/**
* Receive a message from the server.
* @param event - The event name
* @param callback - The callback to run when the event is received.
* The payload's content will be passed to the callback as an argument
*/
on: <T>(event: string, callback: (data: T) => void) => {
if (import.meta.hot) {
import.meta.hot.on(event, callback);
}
},
};
export type ToolbarServerHelpers = typeof serverHelpers;

View file

@ -1,5 +1,6 @@
/* eslint-disable no-console */
import type { DevToolbarApp as DevToolbarAppDefinition } from '../../../@types/astro.js';
import type { ResolvedDevToolbarApp as DevToolbarAppDefinition } from '../../../@types/astro.js';
import { serverHelpers, type ToolbarAppEventTarget } from './helpers.js';
import { settings } from './settings.js';
import { type Icon, getIconElement, isDefinedIcon } from './ui-library/icons.js';
import { type Placement } from './ui-library/window.js';
@ -12,7 +13,7 @@ export type DevToolbarApp = DevToolbarAppDefinition & {
state: boolean;
level?: 'error' | 'warning' | 'info';
};
eventTarget: EventTarget;
eventTarget: ToolbarAppEventTarget;
};
const WS_EVENT_NAME = 'astro-dev-toolbar';
// TODO: Remove in Astro 5.0
@ -385,7 +386,7 @@ export class AstroDevToolbar extends HTMLElement {
try {
settings.logger.verboseLog(`Initializing app ${app.id}`);
await app.init?.(shadowRoot, app.eventTarget);
await app.init?.(shadowRoot, app.eventTarget, serverHelpers);
app.status = 'ready';
if (import.meta.hot) {

View file

@ -0,0 +1,5 @@
import type { DevToolbarApp } from '../@types/astro.js';
export function defineToolbarApp(app: DevToolbarApp) {
return app;
}

View file

@ -3,8 +3,8 @@ import type { AstroPluginOptions } from '../@types/astro.js';
import { telemetry } from '../events/index.js';
import { eventAppToggled } from '../events/toolbar.js';
const VIRTUAL_MODULE_ID = 'astro:dev-toolbar';
const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
const PRIVATE_VIRTUAL_MODULE_ID = 'astro:toolbar:internal';
const resolvedPrivateVirtualModuleId = '\0' + PRIVATE_VIRTUAL_MODULE_ID;
export default function astroDevToolbar({ settings, logger }: AstroPluginOptions): vite.Plugin {
let telemetryTimeout: ReturnType<typeof setTimeout>;
@ -20,8 +20,8 @@ export default function astroDevToolbar({ settings, logger }: AstroPluginOptions
};
},
resolveId(id) {
if (id === VIRTUAL_MODULE_ID) {
return resolvedVirtualModuleId;
if (id === PRIVATE_VIRTUAL_MODULE_ID) {
return resolvedPrivateVirtualModuleId;
}
},
configureServer(server) {
@ -57,29 +57,42 @@ export default function astroDevToolbar({ settings, logger }: AstroPluginOptions
});
},
async load(id) {
if (id === resolvedVirtualModuleId) {
// TODO: In Astro 5.0, we should change the addDevToolbarApp function to separate the logic from the app's metadata.
// That way, we can pass the app's data to the dev toolbar without having to load the app's entrypoint, which will allow
// for a better UI in the browser where we could still show the app's name and icon even if the app's entrypoint fails to load.
// ex: `addDevToolbarApp({ id: 'astro:dev-toolbar:app', name: 'App', icon: '🚀', entrypoint: "./src/something.ts" })`
if (id === resolvedPrivateVirtualModuleId) {
return `
export const loadDevToolbarApps = async () => {
return (await Promise.all([${settings.devToolbarApps
.map(
(plugin) =>
`safeLoadPlugin(async () => (await import(${JSON.stringify(
plugin
)})).default, ${JSON.stringify(plugin)})`
`safeLoadPlugin(${JSON.stringify(plugin)}, async () => (await import(${JSON.stringify(
typeof plugin === 'string' ? plugin : plugin.entrypoint
)})).default, ${JSON.stringify(typeof plugin === 'string' ? plugin : plugin.entrypoint)})`
)
.join(',')}])).filter(app => app);
.join(',')}]));
};
async function safeLoadPlugin(importEntrypoint, entrypoint) {
async function safeLoadPlugin(appDefinition, importEntrypoint, entrypoint) {
try {
const app = await importEntrypoint();
let app;
if (typeof appDefinition === 'string') {
app = await importEntrypoint();
if (typeof app !== 'object' || !app.id || !app.name) {
throw new Error("Apps must default export an object with an id, and a name.");
if (typeof app !== 'object' || !app.id || !app.name) {
throw new Error("Apps must default export an object with an id, and a name.");
}
} else {
app = appDefinition;
if (typeof app !== 'object' || !app.id || !app.name || !app.entrypoint) {
throw new Error("Apps must be an object with an id, a name and an entrypoint.");
}
const loadedApp = await importEntrypoint();
if (typeof loadedApp !== 'object') {
throw new Error("App entrypoint must default export an object.");
}
app = { ...app, ...loadedApp };
}
return app;

View file

@ -381,6 +381,12 @@ importers:
specifier: ^0.33.3
version: 0.33.3
examples/toolbar-app:
devDependencies:
astro:
specifier: ^4.6.1
version: link:../../packages/astro
examples/view-transitions:
devDependencies:
'@astrojs/node':

View file

@ -6,9 +6,11 @@ import * as path from 'node:path';
import pLimit from 'p-limit';
import { tsconfigResolverSync } from 'tsconfig-resolver';
const skippedExamples = ['toolbar-app', 'component']
function checkExamples() {
let examples = readdirSync('./examples', { withFileTypes: true });
examples = examples.filter((dirent) => dirent.isDirectory());
examples = examples.filter((dirent) => dirent.isDirectory()).filter((dirent) => !skippedExamples.includes(dirent.name));
console.log(`Running astro check on ${examples.length} examples...`);