improve telemetry (#8600)
This commit is contained in:
parent
0119a271ae
commit
ed54d46449
6 changed files with 155 additions and 426 deletions
6
.changeset/large-shoes-hammer.md
Normal file
6
.changeset/large-shoes-hammer.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
'@astrojs/telemetry': patch
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve config info telemetry
|
|
@ -9,7 +9,12 @@ import ora from 'ora';
|
||||||
import preferredPM from 'preferred-pm';
|
import preferredPM from 'preferred-pm';
|
||||||
import prompts from 'prompts';
|
import prompts from 'prompts';
|
||||||
import type yargs from 'yargs-parser';
|
import type yargs from 'yargs-parser';
|
||||||
import { loadTSConfig, resolveConfigPath, resolveRoot } from '../../core/config/index.js';
|
import {
|
||||||
|
loadTSConfig,
|
||||||
|
resolveConfig,
|
||||||
|
resolveConfigPath,
|
||||||
|
resolveRoot,
|
||||||
|
} from '../../core/config/index.js';
|
||||||
import {
|
import {
|
||||||
defaultTSConfig,
|
defaultTSConfig,
|
||||||
presets,
|
presets,
|
||||||
|
@ -23,7 +28,7 @@ import { appendForwardSlash } from '../../core/path.js';
|
||||||
import { apply as applyPolyfill } from '../../core/polyfill.js';
|
import { apply as applyPolyfill } from '../../core/polyfill.js';
|
||||||
import { parseNpmName } from '../../core/util.js';
|
import { parseNpmName } from '../../core/util.js';
|
||||||
import { eventCliSession, telemetry } from '../../events/index.js';
|
import { eventCliSession, telemetry } from '../../events/index.js';
|
||||||
import { createLoggerFromFlags } from '../flags.js';
|
import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js';
|
||||||
import { generate, parse, t, visit } from './babel.js';
|
import { generate, parse, t, visit } from './babel.js';
|
||||||
import { ensureImport } from './imports.js';
|
import { ensureImport } from './imports.js';
|
||||||
import { wrapDefaultExport } from './wrapper.js';
|
import { wrapDefaultExport } from './wrapper.js';
|
||||||
|
@ -87,7 +92,9 @@ async function getRegistry(): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function add(names: string[], { flags }: AddOptions) {
|
export async function add(names: string[], { flags }: AddOptions) {
|
||||||
telemetry.record(eventCliSession('add'));
|
const inlineConfig = flagsToAstroInlineConfig(flags);
|
||||||
|
const { userConfig } = await resolveConfig(inlineConfig, 'add');
|
||||||
|
telemetry.record(eventCliSession('add', userConfig));
|
||||||
applyPolyfill();
|
applyPolyfill();
|
||||||
if (flags.help || names.length === 0) {
|
if (flags.help || names.length === 0) {
|
||||||
printHelp({
|
printHelp({
|
||||||
|
|
|
@ -140,7 +140,6 @@ export const AstroConfigSchema = z.object({
|
||||||
.optional()
|
.optional()
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.build.excludeMiddleware),
|
.default(ASTRO_CONFIG_DEFAULTS.build.excludeMiddleware),
|
||||||
})
|
})
|
||||||
.optional()
|
|
||||||
.default({}),
|
.default({}),
|
||||||
server: z.preprocess(
|
server: z.preprocess(
|
||||||
// preprocess
|
// preprocess
|
||||||
|
@ -158,7 +157,6 @@ export const AstroConfigSchema = z.object({
|
||||||
port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
|
port: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.server.port),
|
||||||
headers: z.custom<OutgoingHttpHeaders>().optional(),
|
headers: z.custom<OutgoingHttpHeaders>().optional(),
|
||||||
})
|
})
|
||||||
.optional()
|
|
||||||
.default({})
|
.default({})
|
||||||
),
|
),
|
||||||
redirects: z
|
redirects: z
|
||||||
|
@ -274,27 +272,11 @@ export const AstroConfigSchema = z.object({
|
||||||
.optional()
|
.optional()
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.experimental.optimizeHoistedScript),
|
.default(ASTRO_CONFIG_DEFAULTS.experimental.optimizeHoistedScript),
|
||||||
})
|
})
|
||||||
.passthrough()
|
.strict(
|
||||||
.refine(
|
`Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/configuration-reference/#experimental-flags for a list of all current experiments.`
|
||||||
(d) => {
|
|
||||||
const validKeys = Object.keys(ASTRO_CONFIG_DEFAULTS.experimental);
|
|
||||||
const invalidKeys = Object.keys(d).filter((key) => !validKeys.includes(key));
|
|
||||||
if (invalidKeys.length > 0) return false;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
(d) => {
|
|
||||||
const validKeys = Object.keys(ASTRO_CONFIG_DEFAULTS.experimental);
|
|
||||||
const invalidKeys = Object.keys(d).filter((key) => !validKeys.includes(key));
|
|
||||||
return {
|
|
||||||
message: `Invalid experimental key: \`${invalidKeys.join(
|
|
||||||
', '
|
|
||||||
)}\`. \nMake sure the spelling is correct, and that your Astro version supports this experiment.\nSee https://docs.astro.build/en/reference/configuration-reference/#experimental-flags for more information.`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
.optional()
|
|
||||||
.default({}),
|
.default({}),
|
||||||
legacy: z.object({}).optional().default({}),
|
legacy: z.object({}).default({}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AstroConfigType = z.infer<typeof AstroConfigSchema>;
|
export type AstroConfigType = z.infer<typeof AstroConfigSchema>;
|
||||||
|
|
|
@ -1,25 +1,8 @@
|
||||||
import type { AstroUserConfig } from '../@types/astro.js';
|
import type { AstroIntegration, AstroUserConfig } from '../@types/astro.js';
|
||||||
|
import { AstroConfigSchema } from '../core/config/schema.js';
|
||||||
|
|
||||||
const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED';
|
const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED';
|
||||||
|
|
||||||
interface ConfigInfo {
|
|
||||||
markdownPlugins: string[];
|
|
||||||
adapter: string | null;
|
|
||||||
integrations: string[];
|
|
||||||
trailingSlash: undefined | 'always' | 'never' | 'ignore';
|
|
||||||
build:
|
|
||||||
| undefined
|
|
||||||
| {
|
|
||||||
format: undefined | 'file' | 'directory';
|
|
||||||
};
|
|
||||||
markdown:
|
|
||||||
| undefined
|
|
||||||
| {
|
|
||||||
drafts: undefined | boolean;
|
|
||||||
syntaxHighlight: undefined | 'shiki' | 'prism' | false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EventPayload {
|
interface EventPayload {
|
||||||
cliCommand: string;
|
cliCommand: string;
|
||||||
config?: ConfigInfo;
|
config?: ConfigInfo;
|
||||||
|
@ -28,87 +11,126 @@ interface EventPayload {
|
||||||
optionalIntegrations?: number;
|
optionalIntegrations?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const multiLevelKeys = new Set([
|
type ConfigInfoValue = string | boolean | string[] | undefined;
|
||||||
'build',
|
type ConfigInfoRecord = Record<string, ConfigInfoValue>;
|
||||||
'markdown',
|
type ConfigInfoBase = {
|
||||||
'markdown.shikiConfig',
|
[alias in keyof AstroUserConfig]: ConfigInfoValue | ConfigInfoRecord;
|
||||||
'server',
|
};
|
||||||
'vite',
|
export interface ConfigInfo extends ConfigInfoBase {
|
||||||
'vite.resolve',
|
build: ConfigInfoRecord;
|
||||||
'vite.css',
|
image: ConfigInfoRecord;
|
||||||
'vite.json',
|
markdown: ConfigInfoRecord;
|
||||||
'vite.server',
|
experimental: ConfigInfoRecord;
|
||||||
'vite.server.fs',
|
legacy: ConfigInfoRecord;
|
||||||
'vite.build',
|
vite: ConfigInfoRecord | undefined;
|
||||||
'vite.preview',
|
}
|
||||||
'vite.optimizeDeps',
|
|
||||||
'vite.ssr',
|
|
||||||
'vite.worker',
|
|
||||||
]);
|
|
||||||
function configKeys(obj: Record<string, any> | undefined, parentKey: string): string[] {
|
|
||||||
if (!obj) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.entries(obj)
|
function measureIsDefined(val: unknown) {
|
||||||
.map(([key, value]) => {
|
// if val is undefined, measure undefined as a value
|
||||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
if (val === undefined) {
|
||||||
const localKey = parentKey ? parentKey + '.' + key : key;
|
return undefined;
|
||||||
if (multiLevelKeys.has(localKey)) {
|
|
||||||
let keys = configKeys(value, localKey).map((subkey) => key + '.' + subkey);
|
|
||||||
keys.unshift(key);
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// otherwise, convert the value to a boolean
|
||||||
|
return Boolean(val);
|
||||||
|
}
|
||||||
|
|
||||||
return key;
|
type StringLiteral<T> = T extends string ? (string extends T ? never : T) : never;
|
||||||
})
|
|
||||||
.flat(1);
|
/**
|
||||||
|
* Measure supports string literal values. Passing a generic `string` type
|
||||||
|
* results in an error, to make sure generic user input is never measured directly.
|
||||||
|
*/
|
||||||
|
function measureStringLiteral<T extends string>(
|
||||||
|
val: StringLiteral<T> | boolean | undefined
|
||||||
|
): string | boolean | undefined {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function measureIntegration(val: AstroIntegration | false | null | undefined): string | undefined {
|
||||||
|
if (!val || !val.name) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return val.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizeConfigInfo(obj: object | undefined, validKeys: string[]): ConfigInfoRecord {
|
||||||
|
if (!obj || validKeys.length === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return validKeys.reduce(
|
||||||
|
(result, key) => {
|
||||||
|
result[key] = measureIsDefined((obj as Record<string, unknown>)[key]);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
{} as Record<string, boolean | undefined>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function creates an anonymous ConfigInfo object from the user's config.
|
||||||
|
* All values are sanitized to preserve anonymity. Simple "exist" boolean checks
|
||||||
|
* are used by default, with a few additional sanitized values added manually.
|
||||||
|
* Helper functions should always be used to ensure correct sanitization.
|
||||||
|
*/
|
||||||
|
function createAnonymousConfigInfo(userConfig: AstroUserConfig) {
|
||||||
|
// Sanitize and measure the generic config object
|
||||||
|
// NOTE(fks): Using _def is the correct, documented way to get the `shape`
|
||||||
|
// from a Zod object that includes a wrapping default(), optional(), etc.
|
||||||
|
// Even though `_def` appears private, it is type-checked for us so that
|
||||||
|
// any changes between versions will be detected.
|
||||||
|
const configInfo: ConfigInfo = {
|
||||||
|
...sanitizeConfigInfo(userConfig, Object.keys(AstroConfigSchema.shape)),
|
||||||
|
build: sanitizeConfigInfo(
|
||||||
|
userConfig.build,
|
||||||
|
Object.keys(AstroConfigSchema.shape.build._def.innerType.shape)
|
||||||
|
),
|
||||||
|
image: sanitizeConfigInfo(
|
||||||
|
userConfig.image,
|
||||||
|
Object.keys(AstroConfigSchema.shape.image._def.innerType.shape)
|
||||||
|
),
|
||||||
|
markdown: sanitizeConfigInfo(
|
||||||
|
userConfig.markdown,
|
||||||
|
Object.keys(AstroConfigSchema.shape.markdown._def.innerType.shape)
|
||||||
|
),
|
||||||
|
experimental: sanitizeConfigInfo(
|
||||||
|
userConfig.experimental,
|
||||||
|
Object.keys(AstroConfigSchema.shape.experimental._def.innerType.shape)
|
||||||
|
),
|
||||||
|
legacy: sanitizeConfigInfo(
|
||||||
|
userConfig.legacy,
|
||||||
|
Object.keys(AstroConfigSchema.shape.legacy._def.innerType.shape)
|
||||||
|
),
|
||||||
|
vite: userConfig.vite
|
||||||
|
? sanitizeConfigInfo(userConfig.vite, Object.keys(userConfig.vite))
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
// Measure string literal/enum configuration values
|
||||||
|
configInfo.build.format = measureStringLiteral(userConfig.build?.format);
|
||||||
|
configInfo.markdown.syntaxHighlight = measureStringLiteral(userConfig.markdown?.syntaxHighlight);
|
||||||
|
configInfo.output = measureStringLiteral(userConfig.output);
|
||||||
|
configInfo.scopedStyleStrategy = measureStringLiteral(userConfig.scopedStyleStrategy);
|
||||||
|
configInfo.trailingSlash = measureStringLiteral(userConfig.trailingSlash);
|
||||||
|
// Measure integration & adapter usage
|
||||||
|
configInfo.adapter = measureIntegration(userConfig.adapter);
|
||||||
|
configInfo.integrations = userConfig.integrations
|
||||||
|
?.flat(100)
|
||||||
|
.map(measureIntegration)
|
||||||
|
.filter(Boolean) as string[];
|
||||||
|
// Return the sanitized ConfigInfo object
|
||||||
|
return configInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function eventCliSession(
|
export function eventCliSession(
|
||||||
cliCommand: string,
|
cliCommand: string,
|
||||||
userConfig?: AstroUserConfig,
|
userConfig: AstroUserConfig,
|
||||||
flags?: Record<string, any>
|
flags?: Record<string, any>
|
||||||
): { eventName: string; payload: EventPayload }[] {
|
): { eventName: string; payload: EventPayload }[] {
|
||||||
// Filter out falsy integrations
|
|
||||||
const configValues = userConfig
|
|
||||||
? {
|
|
||||||
markdownPlugins: [
|
|
||||||
...(userConfig?.markdown?.remarkPlugins?.map((p) =>
|
|
||||||
typeof p === 'string' ? p : typeof p
|
|
||||||
) ?? []),
|
|
||||||
...(userConfig?.markdown?.rehypePlugins?.map((p) =>
|
|
||||||
typeof p === 'string' ? p : typeof p
|
|
||||||
) ?? []),
|
|
||||||
] as string[],
|
|
||||||
adapter: userConfig?.adapter?.name ?? null,
|
|
||||||
integrations: (userConfig?.integrations ?? [])
|
|
||||||
.filter(Boolean)
|
|
||||||
.flat()
|
|
||||||
.map((i: any) => i?.name),
|
|
||||||
trailingSlash: userConfig?.trailingSlash,
|
|
||||||
build: userConfig?.build
|
|
||||||
? {
|
|
||||||
format: userConfig?.build?.format,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
markdown: userConfig?.markdown
|
|
||||||
? {
|
|
||||||
drafts: userConfig.markdown?.drafts,
|
|
||||||
syntaxHighlight: userConfig.markdown?.syntaxHighlight,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
// Filter out yargs default `_` flag which is the cli command
|
// Filter out yargs default `_` flag which is the cli command
|
||||||
const cliFlags = flags ? Object.keys(flags).filter((name) => name != '_') : undefined;
|
const cliFlags = flags ? Object.keys(flags).filter((name) => name != '_') : undefined;
|
||||||
|
|
||||||
const payload: EventPayload = {
|
const payload: EventPayload = {
|
||||||
cliCommand,
|
cliCommand,
|
||||||
configKeys: userConfig ? configKeys(userConfig, '') : undefined,
|
config: createAnonymousConfigInfo(userConfig),
|
||||||
config: configValues,
|
|
||||||
flags: cliFlags,
|
flags: cliFlags,
|
||||||
};
|
};
|
||||||
return [{ eventName: EVENT_SESSION, payload }];
|
return [{ eventName: EVENT_SESSION, payload }];
|
||||||
|
|
|
@ -5,44 +5,8 @@ import * as events from '../dist/events/index.js';
|
||||||
|
|
||||||
describe('Events', () => {
|
describe('Events', () => {
|
||||||
describe('eventCliSession()', () => {
|
describe('eventCliSession()', () => {
|
||||||
it('All top-level keys added', () => {
|
|
||||||
const config = {
|
|
||||||
root: 1,
|
|
||||||
srcDir: 2,
|
|
||||||
publicDir: 3,
|
|
||||||
outDir: 4,
|
|
||||||
site: 5,
|
|
||||||
base: 6,
|
|
||||||
trailingSlash: 7,
|
|
||||||
experimental: 8,
|
|
||||||
};
|
|
||||||
const expected = Object.keys(config);
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).to.deep.equal(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('configKeys includes format', () => {
|
it('string literal "build.format" is included', () => {
|
||||||
const config = {
|
|
||||||
srcDir: 1,
|
|
||||||
build: {
|
|
||||||
format: 'file',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).to.deep.equal(['srcDir', 'build', 'build.format']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('config.build.format', () => {
|
|
||||||
const config = {
|
const config = {
|
||||||
srcDir: 1,
|
srcDir: 1,
|
||||||
build: {
|
build: {
|
||||||
|
@ -58,59 +22,8 @@ describe('Events', () => {
|
||||||
expect(payload.config.build.format).to.equal('file');
|
expect(payload.config.build.format).to.equal('file');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('configKeys includes server props', () => {
|
|
||||||
const config = {
|
|
||||||
srcDir: 1,
|
|
||||||
server: {
|
|
||||||
host: 'example.com',
|
|
||||||
port: 8033,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).to.deep.equal(['srcDir', 'server', 'server.host', 'server.port']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('configKeys is deep', () => {
|
it('string literal "markdown.syntaxHighlight" is included', () => {
|
||||||
const config = {
|
|
||||||
publicDir: 1,
|
|
||||||
markdown: {
|
|
||||||
drafts: true,
|
|
||||||
shikiConfig: {
|
|
||||||
lang: 1,
|
|
||||||
theme: 2,
|
|
||||||
wrap: 3,
|
|
||||||
},
|
|
||||||
syntaxHighlight: 'shiki',
|
|
||||||
remarkPlugins: [],
|
|
||||||
rehypePlugins: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).to.deep.equal([
|
|
||||||
'publicDir',
|
|
||||||
'markdown',
|
|
||||||
'markdown.drafts',
|
|
||||||
'markdown.shikiConfig',
|
|
||||||
'markdown.shikiConfig.lang',
|
|
||||||
'markdown.shikiConfig.theme',
|
|
||||||
'markdown.shikiConfig.wrap',
|
|
||||||
'markdown.syntaxHighlight',
|
|
||||||
'markdown.remarkPlugins',
|
|
||||||
'markdown.rehypePlugins',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('syntaxHighlight', () => {
|
|
||||||
const config = {
|
const config = {
|
||||||
markdown: {
|
markdown: {
|
||||||
syntaxHighlight: 'shiki',
|
syntaxHighlight: 'shiki',
|
||||||
|
@ -145,233 +58,16 @@ describe('Events', () => {
|
||||||
},
|
},
|
||||||
config
|
config
|
||||||
);
|
);
|
||||||
expect(payload.configKeys).is.deep.equal([
|
expect(Object.keys(payload.config.vite)).is.deep.equal([
|
||||||
'root',
|
'css',
|
||||||
'vite',
|
'base',
|
||||||
'vite.css',
|
'mode',
|
||||||
'vite.css.modules',
|
'define',
|
||||||
'vite.base',
|
'publicDir',
|
||||||
'vite.mode',
|
|
||||||
'vite.define',
|
|
||||||
'vite.publicDir',
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('vite.resolve keys are captured', async () => {
|
it('falsy integrations are handled', () => {
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
a: 'b',
|
|
||||||
},
|
|
||||||
dedupe: ['one', 'two'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.resolve',
|
|
||||||
'vite.resolve.alias',
|
|
||||||
'vite.resolve.dedupe',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('vite.css keys are captured', async () => {
|
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
resolve: {
|
|
||||||
dedupe: ['one', 'two'],
|
|
||||||
},
|
|
||||||
css: {
|
|
||||||
modules: [],
|
|
||||||
postcss: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.resolve',
|
|
||||||
'vite.resolve.dedupe',
|
|
||||||
'vite.css',
|
|
||||||
'vite.css.modules',
|
|
||||||
'vite.css.postcss',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('vite.server keys are captured', async () => {
|
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
server: {
|
|
||||||
host: 'example.com',
|
|
||||||
open: true,
|
|
||||||
fs: {
|
|
||||||
strict: true,
|
|
||||||
allow: ['a', 'b'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.server',
|
|
||||||
'vite.server.host',
|
|
||||||
'vite.server.open',
|
|
||||||
'vite.server.fs',
|
|
||||||
'vite.server.fs.strict',
|
|
||||||
'vite.server.fs.allow',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('vite.build keys are captured', async () => {
|
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
build: {
|
|
||||||
target: 'one',
|
|
||||||
outDir: 'some/dir',
|
|
||||||
cssTarget: {
|
|
||||||
one: 'two',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.build',
|
|
||||||
'vite.build.target',
|
|
||||||
'vite.build.outDir',
|
|
||||||
'vite.build.cssTarget',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('vite.preview keys are captured', async () => {
|
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
preview: {
|
|
||||||
host: 'example.com',
|
|
||||||
port: 8080,
|
|
||||||
another: {
|
|
||||||
a: 'b',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.preview',
|
|
||||||
'vite.preview.host',
|
|
||||||
'vite.preview.port',
|
|
||||||
'vite.preview.another',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('vite.optimizeDeps keys are captured', async () => {
|
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
optimizeDeps: {
|
|
||||||
entries: ['one', 'two'],
|
|
||||||
exclude: ['secret', 'name'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.optimizeDeps',
|
|
||||||
'vite.optimizeDeps.entries',
|
|
||||||
'vite.optimizeDeps.exclude',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('vite.ssr keys are captured', async () => {
|
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
ssr: {
|
|
||||||
external: ['a'],
|
|
||||||
target: { one: 'two' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.ssr',
|
|
||||||
'vite.ssr.external',
|
|
||||||
'vite.ssr.target',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('vite.worker keys are captured', async () => {
|
|
||||||
const config = {
|
|
||||||
vite: {
|
|
||||||
worker: {
|
|
||||||
format: { a: 'b' },
|
|
||||||
plugins: ['a', 'b'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const [{ payload }] = events.eventCliSession(
|
|
||||||
{
|
|
||||||
cliCommand: 'dev',
|
|
||||||
},
|
|
||||||
config
|
|
||||||
);
|
|
||||||
expect(payload.configKeys).is.deep.equal([
|
|
||||||
'vite',
|
|
||||||
'vite.worker',
|
|
||||||
'vite.worker.format',
|
|
||||||
'vite.worker.plugins',
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('falsy integrations', () => {
|
|
||||||
const config = {
|
const config = {
|
||||||
srcDir: 1,
|
srcDir: 1,
|
||||||
integrations: [null, undefined, false],
|
integrations: [null, undefined, false],
|
||||||
|
@ -385,7 +81,7 @@ describe('Events', () => {
|
||||||
expect(payload.config.integrations.length).to.equal(0);
|
expect(payload.config.integrations.length).to.equal(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('finds names for integration arrays', () => {
|
it('only integration names are included', () => {
|
||||||
const config = {
|
const config = {
|
||||||
integrations: [{ name: 'foo' }, [{ name: 'bar' }, { name: 'baz' }]],
|
integrations: [{ name: 'foo' }, [{ name: 'bar' }, { name: 'baz' }]],
|
||||||
};
|
};
|
||||||
|
@ -393,6 +89,14 @@ describe('Events', () => {
|
||||||
expect(payload.config.integrations).to.deep.equal(['foo', 'bar', 'baz']);
|
expect(payload.config.integrations).to.deep.equal(['foo', 'bar', 'baz']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('only adapter name is included', () => {
|
||||||
|
const config = {
|
||||||
|
adapter: {name: 'ADAPTER_NAME'},
|
||||||
|
};
|
||||||
|
const [{ payload }] = events.eventCliSession({ cliCommand: 'dev' }, config);
|
||||||
|
expect(payload.config.adapter).to.equal('ADAPTER_NAME');
|
||||||
|
});
|
||||||
|
|
||||||
it('includes cli flags in payload', () => {
|
it('includes cli flags in payload', () => {
|
||||||
const config = {};
|
const config = {};
|
||||||
const flags = {
|
const flags = {
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
# Astro Telemetry
|
# Astro Telemetry
|
||||||
|
|
||||||
This package is used to collect anonymous telemetry data within the Astro CLI. It is enabled by default. Telemetry data does not contain any personal identifying information and can be disabled via:
|
This package is used to collect anonymous telemetry data within the Astro CLI.
|
||||||
|
|
||||||
|
It can be disabled in Astro using either method documented below:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
# Option 1: Run this to disable telemetry globally across your entire machine.
|
||||||
astro telemetry disable
|
astro telemetry disable
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [CLI documentation](https://docs.astro.build/en/reference/cli-reference/#astro-telemetry) for more options on configuration telemetry.
|
```shell
|
||||||
|
# Option 2: The ASTRO_TELEMETRY_DISABLED environment variable disables telemetry when set.
|
||||||
|
ASTRO_TELEMETRY_DISABLED=1 astro dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Visit https://astro.build/telemetry/ for more information about our approach to anonymous telemetry in Astro.
|
||||||
|
|
Loading…
Reference in a new issue