Skip to content

Commit

Permalink
feat(devtools): resolve config files from target directory upward to …
Browse files Browse the repository at this point in the history
…the root path
  • Loading branch information
Asuka109 committed Mar 14, 2024
1 parent d9b0778 commit ed5c344
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 11 deletions.
1 change: 1 addition & 0 deletions packages/devtools/plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"serve-static": "^1.14.1",
"p-defer": "^3.0.0",
"ws": "^8.13.0",
"cookie-es": "^1.0.0",
"ufo": "^1.3.0"
},
"devDependencies": {
Expand Down
22 changes: 17 additions & 5 deletions packages/devtools/plugin/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import http from 'http';
import path from 'path';
import assert from 'assert';
import _ from '@modern-js/utils/lodash';
import { ProxyDetail } from '@modern-js/types';
import { getPort, logger } from '@modern-js/utils';
import createServeMiddleware from 'serve-static';
import type { AppTools, CliPlugin } from '@modern-js/app-tools';
import { ClientDefinition, ROUTE_BASENAME } from '@modern-js/devtools-kit/node';
import { DevtoolsPluginOptions, resolveContext } from './config';
import {
DevtoolsPluginOptions,
resolveContext,
updateContext,
} from './options';
import { setupClientConnection } from './rpc';
import { SocketServer } from './utils/socket';
import { loadConfigFiles } from './utils/config';

export type { DevtoolsPluginOptions };

Expand Down Expand Up @@ -57,17 +63,23 @@ export const devtoolsPlugin = (
});
return { routes };
},
config() {
const config = api.useConfigContext().devtools ?? {};
Object.assign(ctx, resolveContext(ctx, config));
async config() {
const appConfig = api.useConfigContext();
const appCtx = api.useAppContext();
const { devtools: options = {} } = appConfig;
updateContext(ctx, options);
updateContext(ctx, ...(await loadConfigFiles(appCtx.appDirectory)));
logger.info(`${ctx.def.name.formalName} DevTools is enabled`);

const swProxyEntry = require.resolve(
'@modern-js/devtools-client/sw-proxy',
);

// Inject options to client.
const serializedOptions = JSON.stringify(ctx);
const clientOptions = _.pick(ctx, ['def', 'endpoint', 'dataSource']);
// Keep resource query always existing.
Object.assign(clientOptions, { __keep: true });
const serializedOptions = JSON.stringify(clientOptions);
const tags: AppTools['normalizedConfig']['html']['tags'] = [
{
tag: 'script',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { ClientDefinition, ROUTE_BASENAME } from '@modern-js/devtools-kit/node';
import type { RequiredDeep } from 'type-fest';
import { DevtoolsConfig } from './types';

export interface DevtoolsPluginOptions {
export interface DevtoolsPluginOptions extends DevtoolsConfig {
enable?: boolean;
endpoint?: string;
dataSource?: string;
}

export interface DevtoolsContext extends RequiredDeep<DevtoolsPluginOptions> {
export interface DevtoolsContext extends Required<DevtoolsPluginOptions> {
def: ClientDefinition;
}

Expand All @@ -19,16 +19,22 @@ export const resolveContext = (
dataSource: `${ROUTE_BASENAME}/rpc`,
endpoint: ROUTE_BASENAME,
def: new ClientDefinition(),
storagePresets: [],
};

// Keep resource query always existing.
Object.assign(ret, { __keep: true });

for (const opts of sources) {
ret.enable = opts.enable ?? ret.enable;
ret.dataSource = opts.dataSource ?? ret.dataSource;
ret.endpoint = opts.endpoint ?? ret.endpoint;
ret.def = opts.def ?? ret.def;
opts.storagePresets && ret.storagePresets.push(...opts.storagePresets);
}
return ret;
};

export const updateContext = (
context: DevtoolsContext,
...sources: Partial<DevtoolsContext>[]
) => {
Object.assign(context, resolveContext(context, ...sources));
};
File renamed without changes.
5 changes: 5 additions & 0 deletions packages/devtools/plugin/src/types/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { StoragePresetOptions } from './preset';

export interface DevtoolsConfig {
storagePresets?: StoragePresetOptions[];
}
3 changes: 3 additions & 0 deletions packages/devtools/plugin/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type * from './common';
export type * from './preset';
export type * from './config';
30 changes: 30 additions & 0 deletions packages/devtools/plugin/src/types/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { CookieSerializeOptions } from 'cookie-es';

export interface LocalStoragePresetItem {
type: 'local-storage';
key: string;
value: string | object | number;
}

export interface SessionStoragePresetItem {
type: 'session-storage';
key: string;
value: string | object | number;
}

export interface CookiePresetItem
extends Omit<CookieSerializeOptions, 'encode'> {
type: 'cookie';
key: string;
value: string | object | number;
}

export type StoragePreset =
| LocalStoragePresetItem
| SessionStoragePresetItem
| CookiePresetItem;

export interface StoragePresetOptions {
name: string;
items: StoragePreset[];
}
53 changes: 53 additions & 0 deletions packages/devtools/plugin/src/utils/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import path from 'path';
import fs from '@modern-js/utils/fs-extra';
import { DevtoolsConfig } from '../types';

const CONFIG_FILENAME = 'modern.devtools.json';

async function findUp(filename: string, dir = process.cwd()) {
const filePath = path.join(dir, filename);
if (await fs.pathExists(filePath)) {
return filePath;
}
const parent = path.dirname(dir);
if (parent === dir) {
return null;
}
return findUp(filename, parent);
}

export function resolveConfigFile(dir = process.cwd()) {
return findUp(CONFIG_FILENAME, dir);
}

/** Resolve all config files from target directory upward to the root path. */
export async function resolveConfigFiles(
dir = process.cwd(),
): Promise<string[]> {
const files = [];
let currentDir = dir;
while (true) {
const configFile = await resolveConfigFile(currentDir);
if (!configFile) {
break;
}
files.push(configFile);
currentDir = path.dirname(currentDir);
}
return files;
}

export async function loadConfigFile(dir = process.cwd()) {
const filename = await resolveConfigFile(dir);
if (!filename) {
return null;
}
const raw = await fs.readJson(filename);
return raw as DevtoolsConfig;
}

export async function loadConfigFiles(dir = process.cwd()) {
const filenames = await resolveConfigFiles(dir);
const configs = await Promise.all(filenames.map(loadConfigFile));
return configs.filter(Boolean) as DevtoolsConfig[];
}
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ed5c344

Please sign in to comment.