Skip to content

Commit

Permalink
Improve error message when a Svelte config is not found (#3219)
Browse files Browse the repository at this point in the history
* Improve an error message for MODULE_NOT_FOUND

* Add a changeset

* Update a changeset

Co-authored-by: Bjorn Lu <bjornlu.dev@gmail.com>

* Move some error messages

* Move some error messages again

* Update

* remove support for svelte.config.cjs

* tweak changeset

* simplify config error handling

* simplify further

* lint

* update test

Co-authored-by: Bjorn Lu <bjornlu.dev@gmail.com>
Co-authored-by: Rich Harris <hello@rich-harris.dev>
  • Loading branch information
3 people authored Jan 7, 2022
1 parent a59c89f commit 1a7c0da
Show file tree
Hide file tree
Showing 14 changed files with 62 additions and 102 deletions.
5 changes: 5 additions & 0 deletions .changeset/neat-points-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

Improve error message when svelte.config.js is not found
1 change: 1 addition & 0 deletions packages/kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"sirv": "^1.0.19",
"svelte": "^3.44.2",
"svelte-check": "^2.2.10",
"svelte-preprocess": "^4.9.8",
"svelte2tsx": "~0.4.10",
"tiny-glob": "^0.2.9",
"uvu": "^0.5.2"
Expand Down
82 changes: 23 additions & 59 deletions packages/kit/src/cli.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,22 @@
import { existsSync } from 'fs';
import sade from 'sade';
import colors from 'kleur';
import { relative } from 'path';
import * as ports from 'port-authority';
import { load_config } from './core/config/index.js';
import { networkInterfaces, release } from 'os';
import { coalesce_to_error, has_error_code } from './utils/error.js';
import { coalesce_to_error } from './utils/error.js';

async function get_config() {
// TODO this is temporary, for the benefit of early adopters
if (existsSync('svelte.config.cjs')) {
// prettier-ignore
console.error(colors.bold().red(
'svelte.config.cjs should be renamed to svelte.config.js and converted to an ES module. See https://kit.svelte.dev/docs#configuration for an example'
));
}
/** @param {unknown} e */
function handle_error(e) {
const error = coalesce_to_error(e);

if (existsSync('vite.config.js')) {
// prettier-ignore
console.error(colors.bold().red(
'Please remove vite.config.js and put Vite config in svelte.config.js: https://kit.svelte.dev/docs#configuration-vite'
));
}
if (error.name === 'SyntaxError') throw error;

try {
return await load_config();
} catch (err) {
const error = coalesce_to_error(err);
let message = error.message;

if (
has_error_code(error, 'MODULE_NOT_FOUND') &&
/Cannot find module svelte\.config\./.test(error.message)
) {
message = 'Missing svelte.config.js';
} else if (error.name === 'SyntaxError') {
message = 'Malformed svelte.config.js';
}

console.error(colors.bold().red(message));
if (error.stack) {
console.error(colors.grey(error.stack));
}
process.exit(1);
console.log(colors.bold().red(`> ${error.message}`));
if (error.stack) {
console.log(colors.gray(error.stack.split('\n').slice(1).join('\n')));
}
}

/** @param {unknown} error */
function handle_error(error) {
const err = coalesce_to_error(error);
console.log(colors.bold().red(`> ${err.message}`));
if (err.stack) {
console.log(colors.gray(err.stack));
}
process.exit(1);
}

Expand Down Expand Up @@ -85,12 +49,12 @@ prog
.option('-H, --https', 'Use self-signed HTTPS certificate')
.option('-o, --open', 'Open a browser tab')
.action(async ({ port, host, https, open }) => {
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
const config = await get_config();
try {
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
const config = await load_config();

const { dev } = await import('./core/dev/index.js');
const { dev } = await import('./core/dev/index.js');

try {
const cwd = process.cwd();

const { address_info, server_config } = await dev({
Expand Down Expand Up @@ -120,10 +84,10 @@ prog
.describe('Create a production build of your app')
.option('--verbose', 'Log more stuff', false)
.action(async ({ verbose }) => {
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
const config = await get_config();

try {
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
const config = await load_config();

const { build } = await import('./core/build/index.js');
const build_data = await build(config);

Expand Down Expand Up @@ -158,14 +122,14 @@ prog
.option('-H, --https', 'Use self-signed HTTPS certificate', false)
.option('-o, --open', 'Open a browser tab', false)
.action(async ({ port, host, https, open }) => {
await check_port(port);
try {
await check_port(port);

process.env.NODE_ENV = process.env.NODE_ENV || 'production';
const config = await get_config();
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
const config = await load_config();

const { preview } = await import('./core/preview/index.js');
const { preview } = await import('./core/preview/index.js');

try {
await preview({ port, host, config, https });

welcome({ port, host, https, open });
Expand All @@ -179,11 +143,11 @@ prog
.describe('Create a package')
.option('-d, --dir', 'Destination directory', 'package')
.action(async () => {
const config = await get_config();
try {
const config = await load_config();

const { make_package } = await import('./packaging/index.js');
const { make_package } = await import('./packaging/index.js');

try {
await make_package(config);
} catch (error) {
handle_error(error);
Expand Down
24 changes: 10 additions & 14 deletions packages/kit/src/core/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ export function load_template(cwd, config) {
}

export async function load_config({ cwd = process.cwd() } = {}) {
const config_file_esm = path.join(cwd, 'svelte.config.js');
const config_file = fs.existsSync(config_file_esm)
? config_file_esm
: path.join(cwd, 'svelte.config.cjs');
const config_file = path.join(cwd, 'svelte.config.js');

if (!fs.existsSync(config_file)) {
throw new Error(
'You need to create a svelte.config.js file. See https://kit.svelte.dev/docs#configuration'
);
}

const config = await import(url.pathToFileURL(config_file).href);

const validated = validate_config(config.default);
Expand All @@ -51,17 +55,9 @@ export async function load_config({ cwd = process.cwd() } = {}) {
* @returns {import('types/config').ValidatedConfig}
*/
export function validate_config(config) {
const type = typeof config;

if (type === 'undefined') {
throw new Error(
'Your config is missing default exports. Make sure to include "export default config;"'
);
}

if (type !== 'object') {
if (typeof config !== 'object') {
throw new Error(
`Unexpected config type "${type}", make sure your default export is an object.`
'svelte.config.js must have a configuration object as its default export. See https://kit.svelte.dev/docs#configuration'
);
}

Expand Down
Empty file.
24 changes: 7 additions & 17 deletions packages/kit/src/core/config/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ import { load_config } from '../index.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = join(__filename, '..');

/**
* @param {string} path
*/
async function testLoadDefaultConfig(path) {
const cwd = join(__dirname, 'fixtures', path);
test('load default config (esm)', async () => {
const cwd = join(__dirname, 'fixtures/default');

const config = await load_config({ cwd });
remove_keys(config, ([, v]) => typeof v === 'function');
Expand Down Expand Up @@ -64,28 +61,21 @@ async function testLoadDefaultConfig(path) {
trailingSlash: 'never'
}
});
}

test('load default config (cjs)', async () => {
await testLoadDefaultConfig('default-cjs');
});

test('load default config (esm)', async () => {
await testLoadDefaultConfig('default-esm');
});

test('errors on loading config with incorrect default export', async () => {
let errorMessage = null;
let message = null;

try {
const cwd = join(__dirname, 'fixtures', 'export-string');
await load_config({ cwd });
} catch (/** @type {any} */ e) {
errorMessage = e.message;
message = e.message;
}

assert.equal(
errorMessage,
'Unexpected config type "string", make sure your default export is an object.'
message,
'svelte.config.js must have a configuration object as its default export. See https://kit.svelte.dev/docs#configuration'
);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "resolve-alias",
"version": "1.0.0",
"description": "package using $lib alias"
"description": "package using $lib alias",
"type": "module"
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import preprocess from 'svelte-preprocess';

export default {
preprocess: preprocess()
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "typescript",
"version": "1.0.0",
"description": "standard typescript package"
"description": "standard typescript package",
"type": "module"
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import preprocess from 'svelte-preprocess';

export default {
preprocess: preprocess()
};
2 changes: 2 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 1a7c0da

Please sign in to comment.