Repository: sveltejs/kit (js)

Issue:
`npm run package` isn't playing nice without typescript
### Describe the bug

Running `npm run package` on a code stack meant to spit out _javascript modules_ (not typescript) gives us the error:
```
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'svelte2tsx' imported from /Users/x/Projects/crow/node_modules/@sveltejs/kit/dist/chunks/index6.js
```

Installning `svelte2tsx` makes it work, but it bundles `.d.ts`-files.

### Reproduction

1. Download `npm init svelte@next test`
  (Skeleton Project > **No Typescript** > **Use ESLint** > **Use Prettier**)
2. Install `cd test; npm install`
3. Run `npm run package`

Yields the error: `Cannot find package 'svelte2tsx'`

### Logs

_No response_

### System Info

```shell
System:
  OS: macOS 11.1
  CPU: (8) x64 Apple M1
  Memory: 648.46 MB / 16.00 GB
  Shell: 5.8 - /bin/zsh
Binaries:
  Node: 14.16.0 - ~/.nvm/versions/node/v14.16.0/bin/node
  npm: 7.20.3 - ~/.nvm/versions/node/v14.16.0/bin/npm
Browsers:
  Chrome: 96.0.4664.55
  Firefox: 94.0.2
  Safari: 14.0.2
npmPackages:
  @sveltejs/adapter-vercel: ^1.0.0-next.23 => 1.0.0-next.23
  @sveltejs/kit: ^1.0.0-next.120 => 1.0.0-next.120
  svelte: ^3.42.6 => 3.44.0
```


### Severity

annoyance

### Additional Information

_No response_

Pull request:
clearer packaging error messages
Closes #2951

### Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [x] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it solves.
- [x] Ideally, include a test that fails without this PR but passes with it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpx changeset` and following the prompts. All changesets should be `patch` until SvelteKit 1.0


Patch:
diff --git a/.changeset/clever-donuts-smile.md b/.changeset/clever-donuts-smile.md
new file mode 100644
index 000000000..3a1fbc9c8
--- /dev/null
+++ b/.changeset/clever-donuts-smile.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+`svelte-kit package` gives clearer error message when svelte2tsx and typescript are not installed
diff --git a/.changeset/eleven-dots-reply.md b/.changeset/eleven-dots-reply.md
new file mode 100644
index 000000000..aa71e1b79
--- /dev/null
+++ b/.changeset/eleven-dots-reply.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+`svelte-kit package` errors when lib directory does not exist
diff --git a/packages/kit/src/packaging/index.js b/packages/kit/src/packaging/index.js
index b6584506b..3a288f79c 100644
--- a/packages/kit/src/packaging/index.js
+++ b/packages/kit/src/packaging/index.js
@@ -12,18 +12,23 @@ const essential_files = ['README', 'LICENSE', 'CHANGELOG', '.gitignore', '.npmig
  * @param {string} cwd
  */
 export async function make_package(config, cwd = process.cwd()) {
-	const package_dir = config.kit.package.dir;
-	const abs_package_dir = path.isAbsolute(package_dir) ? package_dir : path.join(cwd, package_dir);
-	rimraf(abs_package_dir);
-	mkdirp(abs_package_dir); // TODO https://github.com/sveltejs/kit/issues/2333
+	if (!fs.existsSync(config.kit.files.lib)) {
+		throw new Error(`${config.kit.files.lib} does not exist`);
+	}
+
+	const package_dir = path.isAbsolute(config.kit.package.dir)
+		? config.kit.package.dir
+		: path.join(cwd, config.kit.package.dir);
+	rimraf(package_dir);
+	mkdirp(package_dir); // TODO https://github.com/sveltejs/kit/issues/2333
 
 	if (config.kit.package.emitTypes) {
 		// Generate type definitions first so hand-written types can overwrite generated ones
 		await emit_dts(config);
 		// Resolve aliases, TS leaves them as-is
-		const files = walk(abs_package_dir);
+		const files = walk(package_dir);
 		for (const file of files) {
-			const filename = path.join(abs_package_dir, file);
+			const filename = path.join(package_dir, file);
 			const source = fs.readFileSync(filename, 'utf8');
 			fs.writeFileSync(filename, resolve_$lib_alias(file, source, config));
 		}
@@ -50,7 +55,7 @@ export async function make_package(config, cwd = process.cwd()) {
 
 		if (!config.kit.package.files(normalized)) {
 			const dts_file = (svelte_ext ? file : file.slice(0, -ext.length)) + '.d.ts';
-			const dts_path = path.join(abs_package_dir, dts_file);
+			const dts_path = path.join(package_dir, dts_file);
 			if (fs.existsSync(dts_path)) {
 				fs.unlinkSync(dts_path);
 
@@ -85,7 +90,7 @@ export async function make_package(config, cwd = process.cwd()) {
 			out_file = file;
 			out_contents = source.toString('utf-8');
 			out_contents = resolve_$lib_alias(out_file, out_contents, config);
-			if (fs.existsSync(path.join(abs_package_dir, out_file))) {
+			if (fs.existsSync(path.join(package_dir, out_file))) {
 				console.warn(
 					'Found already existing file from d.ts generation for ' +
 						out_file +
@@ -101,7 +106,7 @@ export async function make_package(config, cwd = process.cwd()) {
 			out_contents = source;
 		}
 
-		write(path.join(abs_package_dir, out_file), out_contents);
+		write(path.join(package_dir, out_file), out_contents);
 
 		if (config.kit.package.exports(normalized)) {
 			const original = `$lib/${normalized}`;
@@ -148,7 +153,7 @@ export async function make_package(config, cwd = process.cwd()) {
 		}
 	}
 
-	write(path.join(abs_package_dir, 'package.json'), JSON.stringify(pkg, null, '  '));
+	write(path.join(package_dir, 'package.json'), JSON.stringify(pkg, null, 2));
 
 	const whitelist = fs.readdirSync(cwd).filter((file) => {
 		const lowercased = file.toLowerCase();
@@ -158,7 +163,7 @@ export async function make_package(config, cwd = process.cwd()) {
 		const full_path = path.join(cwd, pathname);
 		if (fs.lstatSync(full_path).isDirectory()) continue; // just to be sure
 
-		const package_path = path.join(abs_package_dir, pathname);
+		const package_path = path.join(package_dir, pathname);
 		if (!fs.existsSync(package_path)) fs.copyFileSync(full_path, package_path);
 	}
 
@@ -326,8 +331,7 @@ async function try_load_svelte2tsx() {
 			return await import('svelte2tsx');
 		} catch (e) {
 			throw new Error(
-				'You need to install svelte2tsx and typescript if you want to generate type definitions\n' +
-					e
+				'You need svelte2tsx and typescript if you want to generate type definitions. Install it through your package manager, or disable generation which is highly discouraged. See https://kit.svelte.dev/docs#packaging'
 			);
 		}
 	}


Test patch:
diff --git a/packages/kit/src/packaging/test/errors/duplicate-export/package.json b/packages/kit/src/packaging/test/errors/duplicate-export/package.json
index 696dcdb26..4befdcc6b 100644
--- a/packages/kit/src/packaging/test/errors/duplicate-export/package.json
+++ b/packages/kit/src/packaging/test/errors/duplicate-export/package.json
@@ -1,5 +1,6 @@
 {
-	"name": "errors",
+	"name": "error-duplicate-export",
+	"private": true,
 	"version": "1.0.0",
-	"description": "validate error output"
+	"description": "validate duplicate export error output"
 }
diff --git a/packages/kit/src/packaging/test/errors/no-lib-folder/package.json b/packages/kit/src/packaging/test/errors/no-lib-folder/package.json
new file mode 100644
index 000000000..060a9474e
--- /dev/null
+++ b/packages/kit/src/packaging/test/errors/no-lib-folder/package.json
@@ -0,0 +1,6 @@
+{
+	"name": "error-no-lib-folder",
+	"private": true,
+	"version": "1.0.0",
+	"description": "validate no lib folder error output"
+}
diff --git a/packages/kit/src/packaging/test/errors/no-lib-folder/svelte.config.js b/packages/kit/src/packaging/test/errors/no-lib-folder/svelte.config.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/kit/src/packaging/test/fixtures/assets/expected/package.json b/packages/kit/src/packaging/test/fixtures/assets/expected/package.json
index 4ce122a1a..8cd8408fe 100644
--- a/packages/kit/src/packaging/test/fixtures/assets/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/assets/expected/package.json
@@ -1,5 +1,6 @@
 {
   "name": "assets",
+	"private": true,
   "version": "1.0.0",
   "description": "no tampering assets",
   "type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/assets/package.json b/packages/kit/src/packaging/test/fixtures/assets/package.json
index ee3ef4904..f25793367 100644
--- a/packages/kit/src/packaging/test/fixtures/assets/package.json
+++ b/packages/kit/src/packaging/test/fixtures/assets/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "assets",
+	"private": true,
 	"version": "1.0.0",
 	"description": "no tampering assets"
 }
diff --git a/packages/kit/src/packaging/test/fixtures/emitTypes-false/expected/package.json b/packages/kit/src/packaging/test/fixtures/emitTypes-false/expected/package.json
index b92c803cd..3c97b0b19 100644
--- a/packages/kit/src/packaging/test/fixtures/emitTypes-false/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/emitTypes-false/expected/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "emit-types",
+	"private": true,
 	"version": "1.0.0",
 	"description": "emitTypes settings disabled",
 	"type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/emitTypes-false/package.json b/packages/kit/src/packaging/test/fixtures/emitTypes-false/package.json
index bdd9bbbaa..ec97559d2 100644
--- a/packages/kit/src/packaging/test/fixtures/emitTypes-false/package.json
+++ b/packages/kit/src/packaging/test/fixtures/emitTypes-false/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "emit-types",
+	"private": true,
 	"version": "1.0.0",
 	"description": "emitTypes settings disabled",
 	"type": "module"
diff --git a/packages/kit/src/packaging/test/fixtures/exports-merge/expected/package.json b/packages/kit/src/packaging/test/fixtures/exports-merge/expected/package.json
index 36398680c..87ee8e1ea 100644
--- a/packages/kit/src/packaging/test/fixtures/exports-merge/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/exports-merge/expected/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "exports-replace",
+	"private": true,
 	"version": "1.0.0",
 	"description": "merges exports field",
 	"exports": {
diff --git a/packages/kit/src/packaging/test/fixtures/exports-merge/package.json b/packages/kit/src/packaging/test/fixtures/exports-merge/package.json
index 0607e2902..0033602dd 100644
--- a/packages/kit/src/packaging/test/fixtures/exports-merge/package.json
+++ b/packages/kit/src/packaging/test/fixtures/exports-merge/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "exports-replace",
+	"private": true,
 	"version": "1.0.0",
 	"description": "merges exports field",
 	"exports": {
diff --git a/packages/kit/src/packaging/test/fixtures/exports-replace/expected/package.json b/packages/kit/src/packaging/test/fixtures/exports-replace/expected/package.json
index 64f5503df..e84633d71 100644
--- a/packages/kit/src/packaging/test/fixtures/exports-replace/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/exports-replace/expected/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "exports-replace",
+	"private": true,
 	"version": "1.0.0",
 	"description": "replaces exports field",
 	"type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/exports-replace/package.json b/packages/kit/src/packaging/test/fixtures/exports-replace/package.json
index 9a1f196ad..96c198738 100644
--- a/packages/kit/src/packaging/test/fixtures/exports-replace/package.json
+++ b/packages/kit/src/packaging/test/fixtures/exports-replace/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "exports-replace",
+	"private": true,
 	"version": "1.0.0",
 	"description": "replaces exports field",
 	"type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/files-exclude/expected/package.json b/packages/kit/src/packaging/test/fixtures/files-exclude/expected/package.json
index 43785b17d..26f20bb77 100644
--- a/packages/kit/src/packaging/test/fixtures/files-exclude/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/files-exclude/expected/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "files-exclude",
+	"private": true,
 	"version": "1.0.0",
 	"description": "files.exclude settings configured",
 	"type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/files-exclude/package.json b/packages/kit/src/packaging/test/fixtures/files-exclude/package.json
index aa6ad65f0..c81333c30 100644
--- a/packages/kit/src/packaging/test/fixtures/files-exclude/package.json
+++ b/packages/kit/src/packaging/test/fixtures/files-exclude/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "files-exclude",
+	"private": true,
 	"version": "1.0.0",
 	"description": "files.exclude settings configured",
 	"type": "module"
diff --git a/packages/kit/src/packaging/test/fixtures/javascript/expected/package.json b/packages/kit/src/packaging/test/fixtures/javascript/expected/package.json
index 61989d1d8..3d7d65e37 100644
--- a/packages/kit/src/packaging/test/fixtures/javascript/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/javascript/expected/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "javascript",
+	"private": true,
 	"version": "1.0.0",
 	"description": "standard javascript package",
 	"type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/javascript/package.json b/packages/kit/src/packaging/test/fixtures/javascript/package.json
index c568fbfa5..77440f772 100644
--- a/packages/kit/src/packaging/test/fixtures/javascript/package.json
+++ b/packages/kit/src/packaging/test/fixtures/javascript/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "javascript",
+	"private": true,
 	"version": "1.0.0",
 	"description": "standard javascript package"
 }
diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/package.json b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/package.json
index 78ebd4d10..3e59313a2 100644
--- a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "resolve-alias",
+	"private": true,
 	"version": "1.0.0",
 	"description": "package using $lib alias",
 	"type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/package.json b/packages/kit/src/packaging/test/fixtures/resolve-alias/package.json
index eec695b67..19ecfdbec 100644
--- a/packages/kit/src/packaging/test/fixtures/resolve-alias/package.json
+++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "resolve-alias",
+	"private": true,
 	"version": "1.0.0",
 	"description": "package using $lib alias",
 	"type": "module"
diff --git a/packages/kit/src/packaging/test/fixtures/typescript/expected/package.json b/packages/kit/src/packaging/test/fixtures/typescript/expected/package.json
index 16dc1669f..59ea2b06d 100644
--- a/packages/kit/src/packaging/test/fixtures/typescript/expected/package.json
+++ b/packages/kit/src/packaging/test/fixtures/typescript/expected/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "typescript",
+	"private": true,
 	"version": "1.0.0",
 	"description": "standard typescript package",
 	"type": "module",
diff --git a/packages/kit/src/packaging/test/fixtures/typescript/package.json b/packages/kit/src/packaging/test/fixtures/typescript/package.json
index a2feaf4d4..7e166c721 100644
--- a/packages/kit/src/packaging/test/fixtures/typescript/package.json
+++ b/packages/kit/src/packaging/test/fixtures/typescript/package.json
@@ -1,5 +1,6 @@
 {
 	"name": "typescript",
+	"private": true,
 	"version": "1.0.0",
 	"description": "standard typescript package",
 	"type": "module"
diff --git a/packages/kit/src/packaging/test/index.js b/packages/kit/src/packaging/test/index.js
index e51b9ac05..cdad2d3ee 100644
--- a/packages/kit/src/packaging/test/index.js
+++ b/packages/kit/src/packaging/test/index.js
@@ -1,4 +1,4 @@
-import { statSync, readFileSync } from 'fs';
+import fs from 'fs';
 import { join } from 'path';
 import { fileURLToPath } from 'url';
 
@@ -37,11 +37,11 @@ async function test_make_package(path) {
 		const extensions = ['.json', '.svelte', '.ts', 'js'];
 		for (const file of actual_files) {
 			const pathname = join(pwd, file);
-			if (statSync(pathname).isDirectory()) continue;
+			if (fs.statSync(pathname).isDirectory()) continue;
 			assert.ok(expected_files.includes(file), `Did not expect ${file} in ${path}`);
 
-			const expected = readFileSync(join(ewd, file));
-			const actual = readFileSync(join(pwd, file));
+			const expected = fs.readFileSync(join(ewd, file));
+			const actual = fs.readFileSync(join(pwd, file));
 			const err_msg = `Expected equal file contents for ${file} in ${path}`;
 
 			if (extensions.some((ext) => pathname.endsWith(ext))) {
@@ -75,25 +75,43 @@ function format(file, content) {
 	});
 }
 
-test('standard package errors', async () => {
-	// TODO: refactor and allow this to handle multiple errors
-	const cwd = join(__dirname, 'errors', 'duplicate-export');
-	const pwd = join(cwd, 'package');
+for (const dir of fs.readdirSync(join(__dirname, 'errors'))) {
+	test(`package error [${dir}]`, async () => {
+		const cwd = join(__dirname, 'errors', dir);
+		const pwd = join(cwd, 'package');
 
-	const config = await load_config({ cwd });
-	try {
-		// TODO: use assert.throws, does not seem to work with async/await
-		await make_package(config, cwd);
-	} catch (/** @type {any} */ e) {
-		assert.equal(
-			e.message,
-			'Duplicate "./utils" export. Please remove or rename either $lib/utils/index.js or $lib/utils.ts',
-			'Duplicate export are not thrown'
-		);
-	} finally {
-		rimraf(pwd);
-	}
-});
+		const config = await load_config({ cwd });
+		try {
+			await make_package(config, cwd);
+			assert.unreachable('Must not pass make_package');
+		} catch (/** @type {any} */ error) {
+			assert.instance(error, Error);
+			switch (dir) {
+				case 'duplicate-export':
+					assert.match(
+						error.message,
+						'Duplicate "./utils" export. Please remove or rename either $lib/utils/index.js or $lib/utils.ts'
+					);
+					break;
+				case 'no-lib-folder':
+					assert.match(error.message, `${join(cwd, 'src', 'lib')} does not exist`);
+					break;
+				// TODO: non-existent tsconfig passes without error
+				// 	it detects tsconfig in packages/kit instead and creates package folder
+				// 	in packages/kit/package, not sure how to handle and test this yet
+				// case 'no-tsconfig':
+				// 	assert.match(error.message, 'Failed to locate tsconfig or jsconfig');
+				// 	break;
+
+				default:
+					assert.unreachable('All error test must be handled');
+					break;
+			}
+		} finally {
+			rimraf(pwd);
+		}
+	});
+}
 
 test('create standard package with javascript', async () => {
 	// should also preserve filename casing