Skip to content

Commit

Permalink
[fix] resolve $lib alias when packaging
Browse files Browse the repository at this point in the history
Fixes the 90% case of #1950
  • Loading branch information
Simon Holthausen committed Sep 17, 2021
1 parent 4f748a9 commit e3bada8
Show file tree
Hide file tree
Showing 23 changed files with 181 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/rich-seahorses-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

Resolve \$lib alias when packaging
54 changes: 48 additions & 6 deletions packages/kit/src/packaging/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@ const essential_files = ['README', 'LICENSE', 'CHANGELOG', '.gitignore', '.npmig
* @param {string} cwd
*/
export async function make_package(config, cwd = process.cwd()) {
rimraf(path.join(cwd, config.kit.package.dir));
const abs_package_dir = path.join(cwd, config.kit.package.dir);
rimraf(abs_package_dir);

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);
for (const file of files) {
const filename = path.join(abs_package_dir, file);
const source = fs.readFileSync(filename, 'utf8');
fs.writeFileSync(filename, resolve_$lib_alias(file, source, config));
}
}

const files_filter = create_filter(config.kit.package.files);
Expand Down Expand Up @@ -46,7 +54,7 @@ export async function make_package(config, cwd = process.cwd()) {

if (!files_filter(file.replace(/\\/g, '/'))) {
const dts_file = (svelte_ext ? file : file.slice(0, -ext.length)) + '.d.ts';
const dts_path = path.join(cwd, config.kit.package.dir, dts_file);
const dts_path = path.join(abs_package_dir, dts_file);
if (fs.existsSync(dts_path)) fs.unlinkSync(dts_path);
continue;
}
Expand All @@ -70,7 +78,7 @@ export async function make_package(config, cwd = process.cwd()) {
// TypeScript's declaration emit won't copy over the d.ts files, so we do it here
out_file = file;
out_contents = source;
if (fs.existsSync(path.join(cwd, config.kit.package.dir, out_file))) {
if (fs.existsSync(path.join(abs_package_dir, out_file))) {
console.warn(
'Found already existing file from d.ts generation for ' +
out_file +
Expand All @@ -84,8 +92,9 @@ export async function make_package(config, cwd = process.cwd()) {
out_file = file;
out_contents = source;
}
out_contents = resolve_$lib_alias(out_file, out_contents, config);

write(path.join(cwd, config.kit.package.dir, out_file), out_contents);
write(path.join(abs_package_dir, out_file), out_contents);

if (exports_filter(file)) {
const original = `$lib/${file.replace(/\\/g, '/')}`;
Expand All @@ -104,7 +113,7 @@ export async function make_package(config, cwd = process.cwd()) {
}

pkg.exports = { ...generated, ...pkg.exports };
write(path.join(cwd, config.kit.package.dir, 'package.json'), JSON.stringify(pkg, null, ' '));
write(path.join(abs_package_dir, 'package.json'), JSON.stringify(pkg, null, ' '));

const whitelist = fs.readdirSync(cwd).filter((file) => {
const lowercased = file.toLowerCase();
Expand All @@ -114,11 +123,44 @@ 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(cwd, config.kit.package.dir, pathname);
const package_path = path.join(abs_package_dir, pathname);
if (!fs.existsSync(package_path)) fs.copyFileSync(full_path, package_path);
}
}

/**
* Resolves the `$lib` alias.
*
* TODO: make this more generic to also handle
* other aliases the user could have defined via `kit.vite.resolve.alias`.
*
* @param {string} file Relative to the lib root
* @param {string} content
* @param {import('types/config').ValidatedConfig} config
* @returns {string}
*/
function resolve_$lib_alias(file, content, config) {
/**
* @param {string} match
* @param {string} _
* @param {string} import_path
*/
const replace_import_path = (match, _, import_path) => {
if (!import_path.startsWith('$lib/')) {
return match;
}

const full_path = path.join(config.kit.files.lib, file);
const full_import_path = path.join(config.kit.files.lib, import_path.slice('$lib/'.length));
let resolved = path.relative(path.dirname(full_path), full_import_path).replace(/\\/g, '/');
resolved = resolved.startsWith('.') ? resolved : './' + resolved;
return match.replace(import_path, resolved);
};
content = content.replace(/from\s+('|")([^"';,]+?)\1/g, replace_import_path);
content = content.replace(/import\s*\(\s*('|")([^"';,]+?)\1\s*\)/g, replace_import_path);
return content;
}

/**
* @param {string} filename
* @param {string} source
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<script lang="ts">
import { foo } from './sub/foo';
export let bar = foo;
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SvelteComponentTyped } from 'svelte';
declare const __propDef: {
props: {
bar?: import('./sub/foo').Foo;
};
events: {
[evt: string]: CustomEvent<any>;
};
slots: {};
};
export declare type TestProps = typeof __propDef.props;
export declare type TestEvents = typeof __propDef.events;
export declare type TestSlots = typeof __propDef.slots;
export default class Test extends SvelteComponentTyped<TestProps, TestEvents, TestSlots> {}
export {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Baz {
baz: string;
}
export declare const baz: Baz;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const baz = { baz: 'baz' };
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Test } from './Test.svelte';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Test } from './Test.svelte';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "resolve-alias",
"version": "1.0.0",
"description": "package using $lib alias",
"type": "module",
"exports": {
"./package.json": "./package.json",
"./Test.svelte": "./Test.svelte",
".": "./index.js",
"./baz": "./baz.js",
"./sub/bar": "./sub/bar.js",
"./sub/foo": "./sub/foo.js"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export declare const bar1: import('./foo').Foo;
export declare const bar2: import('../baz').Baz;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { baz } from '../baz';
import { foo } from './foo';
export const bar1 = foo;
export const bar2 = baz;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Foo {
foo: string;
}
export declare const foo: Foo;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo = { foo: 'foo' };
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "resolve-alias",
"version": "1.0.0",
"description": "package using $lib alias"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%svelte.head%
</head>
<body>
<div id="svelte">%svelte.body%</div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { foo } from '$lib/sub/foo';
export let bar = foo;
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Baz {
baz: string;
}

export const baz: Baz = { baz: 'baz' };
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Test } from '$lib/Test.svelte';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { baz } from '$lib/baz';
import { foo } from '$lib/sub/foo';

export const bar1 = foo;
export const bar2 = baz;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Foo {
foo: string;
}

export const foo: Foo = { foo: 'foo' };
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const preprocess = require('svelte-preprocess');

module.exports = {
preprocess: preprocess()
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"compilerOptions": {
"moduleResolution": "node",
"module": "es2020",
"lib": ["es2020", "DOM"],
"target": "es2019",
/**
svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
to enforce using \`import type\` instead of \`import\` for Types.
*/
"importsNotUsedAsValues": "error",
"isolatedModules": true,
"resolveJsonModule": true,
/**
To have warnings/errors of the Svelte compiler at the correct position,
enable source maps by default.
*/
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"allowJs": true,
"checkJs": true,
"paths": {
"$lib/*": ["src/lib/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
}
4 changes: 4 additions & 0 deletions packages/kit/src/packaging/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,8 @@ test('create package with files.exclude settings', async () => {
await test_make_package('files-exclude');
});

test('create package and resolves $lib alias', async () => {
await test_make_package('resolve-alias');
});

test.run();

0 comments on commit e3bada8

Please sign in to comment.