No 👏 more 👏 server 👏 restarts 👏 on 👏 config 👏 changes (#4578)

* feat: restart config on add, remove, update

* fix: reload for root project configs only

* fix: throw when userConfigPath can't resolve

* chore: changeset

* wip: remove normalizePath before writeFile

* refactor: invalidateWithCache -> isConfigReload

* wip: mustExist?

* debug: config loaded successfully

* debug: more logs

* debug: MORE logging

* fix: normalize resolved config path

* debug: yet MORE logging

* chore: bump proload

* fix: use file path, not URL.pathname

* Revert "wip: mustExist?"

This reverts commit 8ca8662132532dcdc9fd120868e615ddc60f498e.

* chore: remove console log

* feat: cleanup restart message, better invalid config handling

* chore: update lockfile

* chore: fix types

* fix: throw helpful error when config does not exist

* docs: remove "restart dev server" from integrations

* docs: make sure to restart -> try restarting

Co-authored-by: Nate Moore <nate@astro.build>
This commit is contained in:
Ben Holmes 2022-09-09 11:58:16 -04:00 committed by GitHub
parent b6dd8b595c
commit c706d845eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 153 additions and 122 deletions

View file

@ -0,0 +1,5 @@
---
'astro': minor
---
Restart dev server when config file is added, updated, or removed

View file

@ -106,7 +106,7 @@
"@babel/plugin-transform-react-jsx": "^7.17.12",
"@babel/traverse": "^7.18.2",
"@babel/types": "^7.18.4",
"@proload/core": "^0.3.2",
"@proload/core": "^0.3.3",
"@proload/plugin-tsm": "^0.2.1",
"@types/babel__core": "^7.1.19",
"@types/html-escaper": "^3.0.0",

View file

@ -1,14 +1,15 @@
/* eslint-disable no-console */
import type { Arguments as Flags } from 'yargs-parser'
import * as colors from 'kleur/colors';
import yargs from 'yargs-parser';
import { z } from 'zod';
import { normalizePath } from 'vite';
import add from '../core/add/index.js';
import build from '../core/build/index.js';
import { openConfig } from '../core/config.js';
import { openConfig, resolveConfigPath, resolveFlags, resolveRoot } from '../core/config.js';
import devServer from '../core/dev/index.js';
import { collectErrorMetadata } from '../core/errors.js';
import { debug, info, LogOptions, warn } from '../core/logger/core.js';
import { debug, error, info, LogOptions, warn } from '../core/logger/core.js';
import { enableVerboseLogging, nodeLogDestination } from '../core/logger/node.js';
import { formatConfigErrorMessage, formatErrorMessage, printHelp } from '../core/messages.js';
import preview from '../core/preview/index.js';
@ -18,6 +19,8 @@ import { eventConfigError, eventError, telemetry } from '../events/index.js';
import { check } from './check/index.js';
import { openInBrowser } from './open.js';
import * as telemetryHandler from './telemetry.js';
import { appendForwardSlash } from '../core/path.js';
import { pathToFileURL } from 'url'
type Arguments = yargs.Arguments;
type CLICommand =
@ -81,6 +84,16 @@ function resolveCommand(flags: Arguments): CLICommand {
return 'help';
}
async function handleConfigError(e: any, { cwd, flags, logging }: { cwd?: string; flags?: Flags, logging: LogOptions }) {
const path = await resolveConfigPath({ cwd, flags });
if (e instanceof Error) {
if (path) {
error(logging, 'astro', `Unable to load ${colors.bold(path)}\n`);
}
console.error(formatErrorMessage(collectErrorMetadata(e, path ? pathToFileURL(path) : undefined)) + '\n')
}
}
/**
* Run the given command with the given flags.
* NOTE: This function provides no error handling, so be sure
@ -132,12 +145,16 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
}
}
let { astroConfig, userConfig, userConfigPath } = await openConfig({
cwd: root,
flags,
cmd,
logging,
});
let { astroConfig, userConfig } = await openConfig({
cwd: root,
flags,
cmd,
logging,
}).catch(async (e) => {
await handleConfigError(e, { cwd: root, flags, logging })
return {} as any;
});
if (!astroConfig) return;
telemetry.record(event.eventCliSession(cmd, userConfig, flags));
// Common CLI Commands:
@ -145,33 +162,56 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
// by the end of this switch statement.
switch (cmd) {
case 'dev': {
async function startDevServer() {
const { watcher, stop } = await devServer(astroConfig, { logging, telemetry });
async function startDevServer({ isRestart = false }: { isRestart?: boolean } = {}) {
const { watcher, stop } = await devServer(astroConfig, { logging, telemetry, isRestart });
let restartInFlight = false;
const configFlag = resolveFlags(flags).config;
const configFlagPath = configFlag
? await resolveConfigPath({ cwd: root, flags })
: undefined;
const resolvedRoot = appendForwardSlash(resolveRoot(root));
watcher.on('change', logRestartServerOnConfigChange);
watcher.on('unlink', logRestartServerOnConfigChange);
function logRestartServerOnConfigChange(changedFile: string) {
if (userConfigPath === changedFile) {
warn(logging, 'astro', 'Astro config updated. Restart server to see changes!');
}
}
const handleServerRestart = (logMsg: string) =>
async function (changedFile: string) {
if (
!restartInFlight &&
(configFlag
? // If --config is specified, only watch changes for this file
configFlagPath && normalizePath(configFlagPath) === normalizePath(changedFile)
: // Otherwise, watch for any astro.config.* file changes in project root
new RegExp(
`${normalizePath(resolvedRoot)}.*astro\.config\.((mjs)|(cjs)|(js)|(ts))$`
).test(normalizePath(changedFile)))
) {
restartInFlight = true;
console.clear()
try {
const newConfig = await openConfig({
cwd: root,
flags,
cmd,
logging,
isConfigReload: true,
});
info(logging, 'astro', logMsg + '\n');
astroConfig = newConfig.astroConfig;
await stop();
await startDevServer({ isRestart: true });
} catch (e) {
await handleConfigError(e, { cwd: root, flags, logging })
await stop();
info(logging, 'astro', 'Continuing with previous valid configuration\n');
await startDevServer({ isRestart: true });
watcher.on('add', async function restartServerOnNewConfigFile(addedFile: string) {
// if there was not a config before, attempt to resolve
if (!userConfigPath && addedFile.includes('astro.config')) {
const addedConfig = await openConfig({ cwd: root, flags, cmd, logging });
if (addedConfig.userConfigPath) {
info(logging, 'astro', 'Astro config detected. Restarting server...');
astroConfig = addedConfig.astroConfig;
userConfig = addedConfig.userConfig;
userConfigPath = addedConfig.userConfigPath;
await stop();
await startDevServer();
}
}
}
});
};
watcher.on('change', handleServerRestart('Configuration updated. Restarting...'));
watcher.on('unlink', handleServerRestart('Configuration removed. Restarting...'));
watcher.on('add', handleServerRestart('Configuration added. Restarting...'));
}
await startDevServer();
await startDevServer({ isRestart: false });
return await new Promise(() => {}); // lives forever
}

View file

@ -10,7 +10,7 @@ import preferredPM from 'preferred-pm';
import prompts from 'prompts';
import { fileURLToPath, pathToFileURL } from 'url';
import type yargs from 'yargs-parser';
import { resolveConfigURL } from '../config.js';
import { resolveConfigPath } from '../config.js';
import { debug, info, LogOptions } from '../logger/core.js';
import * as msg from '../messages.js';
import { printHelp } from '../messages.js';
@ -97,7 +97,8 @@ export default async function add(names: string[], { cwd, flags, logging, teleme
}
let configURL: URL | undefined;
const root = pathToFileURL(cwd ? path.resolve(cwd) : process.cwd());
configURL = await resolveConfigURL({ cwd, flags });
const rawConfigPath = await resolveConfigPath({ cwd, flags });
configURL = rawConfigPath ? pathToFileURL(rawConfigPath) : undefined;
applyPolyfill();
if (configURL) {

View file

@ -3,6 +3,7 @@ import type * as Postcss from 'postcss';
import type { ILanguageRegistration, IThemeRegistration, Theme } from 'shiki';
import type { Arguments as Flags } from 'yargs-parser';
import type { AstroConfig, AstroUserConfig, CLIFlags, ViteUserConfig } from '../@types/astro';
import fs from 'fs';
import load, { ProloadError, resolve } from '@proload/core';
import loadTypeScript from '@proload/plugin-tsm';
@ -361,7 +362,7 @@ export async function validateConfig(
}
/** Convert the generic "yargs" flag object into our own, custom TypeScript object. */
function resolveFlags(flags: Partial<Flags>): CLIFlags {
export function resolveFlags(flags: Partial<Flags>): CLIFlags {
return {
root: typeof flags.root === 'string' ? flags.root : undefined,
site: typeof flags.site === 'string' ? flags.site : undefined,
@ -373,6 +374,10 @@ function resolveFlags(flags: Partial<Flags>): CLIFlags {
};
}
export function resolveRoot(cwd?: string): string {
return cwd ? path.resolve(cwd) : process.cwd();
}
/** Merge CLI flags & user config object (CLI flags take priority) */
function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags, cmd: string) {
astroConfig.server = astroConfig.server || {};
@ -398,6 +403,8 @@ interface LoadConfigOptions {
cmd: string;
validate?: boolean;
logging: LogOptions;
/** Invalidate when reloading a previously loaded config */
isConfigReload?: boolean;
}
/**
@ -405,10 +412,10 @@ interface LoadConfigOptions {
* Note: currently the same as loadConfig but only returns the `filePath`
* instead of the resolved config
*/
export async function resolveConfigURL(
export async function resolveConfigPath(
configOptions: Pick<LoadConfigOptions, 'cwd' | 'flags'>
): Promise<URL | undefined> {
const root = configOptions.cwd ? path.resolve(configOptions.cwd) : process.cwd();
): Promise<string | undefined> {
const root = resolveRoot(configOptions.cwd);
const flags = resolveFlags(configOptions.flags || {});
let userConfigPath: string | undefined;
@ -419,19 +426,23 @@ export async function resolveConfigURL(
// Resolve config file path using Proload
// If `userConfigPath` is `undefined`, Proload will search for `astro.config.[cm]?[jt]s`
const configPath = await resolve('astro', {
mustExist: false,
cwd: root,
filePath: userConfigPath,
});
if (configPath) {
return pathToFileURL(configPath);
try {
const configPath = await resolve('astro', {
mustExist: !!userConfigPath,
cwd: root,
filePath: userConfigPath,
});
return configPath;
} catch (e) {
if (e instanceof ProloadError && flags.config) {
throw new Error(`Unable to resolve --config "${flags.config}"! Does the file exist?`);
}
throw e
}
}
interface OpenConfigResult {
userConfig: AstroUserConfig;
userConfigPath: string | undefined;
astroConfig: AstroConfig;
flags: CLIFlags;
root: string;
@ -439,22 +450,13 @@ interface OpenConfigResult {
/** Load a configuration file, returning both the userConfig and astroConfig */
export async function openConfig(configOptions: LoadConfigOptions): Promise<OpenConfigResult> {
const root = configOptions.cwd ? path.resolve(configOptions.cwd) : process.cwd();
const root = resolveRoot(configOptions.cwd);
const flags = resolveFlags(configOptions.flags || {});
let userConfig: AstroUserConfig = {};
let userConfigPath: string | undefined;
if (flags?.config) {
userConfigPath = /^\.*\//.test(flags.config) ? flags.config : `./${flags.config}`;
userConfigPath = fileURLToPath(
new URL(userConfigPath, appendForwardSlash(pathToFileURL(root).toString()))
);
}
const config = await tryLoadConfig(configOptions, flags, userConfigPath, root);
const config = await tryLoadConfig(configOptions, flags, root);
if (config) {
userConfig = config.value;
userConfigPath = config.filePath;
}
const astroConfig = await resolveConfig(
userConfig,
@ -467,7 +469,6 @@ export async function openConfig(configOptions: LoadConfigOptions): Promise<Open
return {
astroConfig,
userConfig,
userConfigPath,
flags,
root,
};
@ -481,16 +482,37 @@ interface TryLoadConfigResult {
async function tryLoadConfig(
configOptions: LoadConfigOptions,
flags: CLIFlags,
userConfigPath: string | undefined,
root: string
): Promise<TryLoadConfigResult | undefined> {
let finallyCleanup = async () => {};
try {
// Automatically load config file using Proload
// If `userConfigPath` is `undefined`, Proload will search for `astro.config.[cm]?[jt]s`
let configPath = await resolveConfigPath({
cwd: configOptions.cwd,
flags: configOptions.flags,
});
if (!configPath) return undefined;
if (configOptions.isConfigReload) {
// Hack: Write config to temporary file at project root
// This invalidates and reloads file contents when using ESM imports or "resolve"
const tempConfigPath = path.join(
root,
`.temp.${Date.now()}.config${path.extname(configPath)}`
);
await fs.promises.writeFile(tempConfigPath, await fs.promises.readFile(configPath));
finallyCleanup = async () => {
try {
await fs.promises.unlink(tempConfigPath);
} catch {
/** file already removed */
}
};
configPath = tempConfigPath;
}
const config = await load('astro', {
mustExist: !!userConfigPath,
mustExist: !!configPath,
cwd: root,
filePath: userConfigPath,
filePath: configPath,
});
return config as TryLoadConfigResult;
@ -499,28 +521,32 @@ async function tryLoadConfig(
throw new Error(`Unable to resolve --config "${flags.config}"! Does the file exist?`);
}
const configURL = await resolveConfigURL(configOptions);
if (!configURL) {
const configPath = await resolveConfigPath(configOptions);
if (!configPath) {
throw e;
}
// Fallback to use Vite DevServer
const viteServer = await vite.createServer({
server: { middlewareMode: true, hmr: false },
optimizeDeps: { entries: [] },
clearScreen: false,
appType: 'custom',
});
try {
const mod = await viteServer.ssrLoadModule(fileURLToPath(configURL));
const mod = await viteServer.ssrLoadModule(configPath);
if (mod?.default) {
return {
value: mod.default,
filePath: fileURLToPath(configURL),
filePath: configPath,
};
}
} finally {
await viteServer.close();
}
} finally {
await finallyCleanup();
}
}
@ -529,19 +555,11 @@ async function tryLoadConfig(
* @deprecated
*/
export async function loadConfig(configOptions: LoadConfigOptions): Promise<AstroConfig> {
const root = configOptions.cwd ? path.resolve(configOptions.cwd) : process.cwd();
const root = resolveRoot(configOptions.cwd);
const flags = resolveFlags(configOptions.flags || {});
let userConfig: AstroUserConfig = {};
let userConfigPath: string | undefined;
if (flags?.config) {
userConfigPath = /^\.*\//.test(flags.config) ? flags.config : `./${flags.config}`;
userConfigPath = fileURLToPath(
new URL(userConfigPath, appendForwardSlash(pathToFileURL(root).toString()))
);
}
const config = await tryLoadConfig(configOptions, flags, userConfigPath, root);
const config = await tryLoadConfig(configOptions, flags, root);
if (config) {
userConfig = config.value;
}

View file

@ -18,6 +18,7 @@ import { apply as applyPolyfill } from '../polyfill.js';
export interface DevOptions {
logging: LogOptions;
telemetry: AstroTelemetry;
isRestart?: boolean;
}
export interface DevServer {
@ -33,6 +34,7 @@ export default async function dev(config: AstroConfig, options: DevOptions): Pro
await options.telemetry.record([]);
config = await runHookConfigSetup({ config, command: 'dev', logging: options.logging });
const { host, port } = config.server;
const { isRestart = false } = options;
// The client entrypoint for renderers. Since these are imported dynamically
// we need to tell Vite to preoptimize them.
@ -66,6 +68,7 @@ export default async function dev(config: AstroConfig, options: DevOptions): Pro
devServerAddressInfo,
site,
https: !!viteConfig.server?.https,
isRestart
})
);

View file

@ -58,12 +58,14 @@ export function devStart({
config,
https,
site,
isRestart = false
}: {
startupTime: number;
devServerAddressInfo: AddressInfo;
config: AstroConfig;
https: boolean;
site: URL | undefined;
isRestart?: boolean
}): string {
// PACKAGE_VERSION is injected at build-time
const version = process.env.PACKAGE_VERSION ?? '0.0.0';
@ -106,7 +108,7 @@ export function devStart({
const messages = [
`${emoji('🚀 ', '')}${bgGreen(black(` astro `))} ${green(`v${version}`)} ${dim(
`started in ${Math.round(startupTime)}ms`
`${isRestart ? 're' : ''}started in ${Math.round(startupTime)}ms`
)}`,
'',
local,

View file

@ -125,6 +125,7 @@ export async function handleHotUpdate(
// TODO: Svelte files should be marked as `isSelfAccepting` but they don't appear to be
const isSelfAccepting = mods.every((m) => m.isSelfAccepting || m.url.endsWith('.svelte'));
if (isSelfAccepting) {
if (/astro\.config\.[cm][jt]s$/.test(file)) return mods;
info(logging, 'astro', msg.hmr({ file }));
} else {
info(logging, 'astro', msg.reload({ file }));

View file

@ -25,8 +25,6 @@ yarn astro add alpinejs
pnpm astro add alpinejs
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -56,8 +54,6 @@ export default defineConfig({
});
```
Finally, restart the dev server.
## Usage
Once the integration is installed, you can use [Alpine.js](https://alpinejs.dev/) directives and syntax inside any Astro component. The Alpine.js script is automatically added and enabled on every page of your website.

View file

@ -36,8 +36,6 @@ yarn astro add image
pnpm astro add image
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -58,7 +56,6 @@ export default {
integrations: [image()],
}
```
Then, restart the dev server.
### Update `env.d.ts`
@ -469,7 +466,7 @@ const imageUrl = 'https://www.google.com/images/branding/googlelogo/2x/googlelog
```
## Troubleshooting
- If your installation doesn't seem to be working, make sure to restart the dev server.
- If your installation doesn't seem to be working, try restarting the dev server.
- If you edit and save a file and don't see your site update accordingly, try refreshing the page.
- If refreshing the page doesn't update your preview, or if a new installation doesn't seem to be working, then restart the dev server.

View file

@ -23,8 +23,6 @@ yarn astro add lit
pnpm astro add lit
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Install dependencies manually

View file

@ -33,8 +33,6 @@ yarn astro add mdx
pnpm astro add mdx
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -59,8 +57,6 @@ export default defineConfig({
});
```
Finally, restart the dev server.
## Usage
You can [add MDX pages to your project](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages) by adding `.mdx` files within your `src/pages/` directory.

View file

@ -35,8 +35,6 @@ yarn astro add partytown
pnpm astro add partytown
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -59,7 +57,6 @@ export default defineConfig({
})
```
Then, restart the dev server.
## Usage

View file

@ -35,8 +35,6 @@ yarn astro add preact
pnpm astro add preact
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -67,8 +65,6 @@ export default defineConfig({
});
```
Finally, restart the dev server.
## Usage
To use your first Preact component in Astro, head to our [UI framework documentation][astro-ui-frameworks]. You'll explore:

View file

@ -29,8 +29,6 @@ yarn astro add prefetch
pnpm astro add prefetch
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -52,7 +50,6 @@ export default {
}
```
Then, restart the dev server.
## Usage
@ -94,7 +91,7 @@ export default {
```
## Troubleshooting
- If your installation doesn't seem to be working, make sure to restart the dev server.
- If your installation doesn't seem to be working, try restarting the dev server.
- If a link doesn't seem to be prefetching, make sure that the link is pointing to a page on the same domain and matches the integration's `selector` option.
For help, check out the `#support-threads` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!

View file

@ -23,8 +23,6 @@ yarn astro add react
pnpm astro add react
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Install dependencies manually

View file

@ -35,8 +35,6 @@ yarn astro add sitemap
pnpm astro add sitemap
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -59,7 +57,6 @@ export default defineConfig({
})
```
Then, restart the dev server.
## Usage

View file

@ -23,8 +23,6 @@ yarn astro add solid
pnpm astro add solid
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Install dependencies manually

View file

@ -23,8 +23,6 @@ yarn astro add svelte
pnpm astro add svelte
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Install dependencies manually

View file

@ -38,8 +38,6 @@ yarn astro add tailwind
pnpm astro add tailwind
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Manual Install
@ -61,7 +59,6 @@ export default {
}
```
Then, restart the dev server.
## Usage
@ -154,7 +151,7 @@ module.exports = {
- [Browse Astro Tailwind projects on GitHub](https://github.com/search?q=%22%40astrojs%2Ftailwind%22+filename%3Apackage.json&type=Code) for more examples!
## Troubleshooting
- If your installation doesn't seem to be working, make sure to restart the dev server.
- If your installation doesn't seem to be working, try restarting the dev server.
- If you edit and save a file and don't see your site update accordingly, try refreshing the page.
- If refreshing the page doesn't update your preview, or if a new installation doesn't seem to be working, then restart the dev server.

View file

@ -33,8 +33,6 @@ yarn astro add turbolinks
pnpm astro add turbolinks
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Install dependencies manually

View file

@ -23,8 +23,6 @@ yarn astro add vue
pnpm astro add vue
```
Finally, in the terminal window running Astro, press `CTRL+C` and then restart the dev server.
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
### Install dependencies manually

View file

@ -350,7 +350,7 @@ importers:
'@babel/traverse': ^7.18.2
'@babel/types': ^7.18.4
'@playwright/test': ^1.22.2
'@proload/core': ^0.3.2
'@proload/core': ^0.3.3
'@proload/plugin-tsm': ^0.2.1
'@types/babel__core': ^7.1.19
'@types/babel__generator': ^7.6.4