diff --git a/.changeset/rich-seahorses-walk.md b/.changeset/rich-seahorses-walk.md new file mode 100644 index 000000000000..ccb9a5405561 --- /dev/null +++ b/.changeset/rich-seahorses-walk.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +Resolve \$lib alias when packaging diff --git a/packages/kit/src/packaging/index.js b/packages/kit/src/packaging/index.js index 7a82a6cef0a2..d72b677342c9 100644 --- a/packages/kit/src/packaging/index.js +++ b/packages/kit/src/packaging/index.js @@ -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); @@ -47,7 +55,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; } @@ -72,7 +80,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 + @@ -86,8 +94,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, '/')}`; @@ -134,7 +143,7 @@ export async function make_package(config, cwd = process.cwd()) { } } - 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(); @@ -144,11 +153,46 @@ 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`. Also investage how to do this in a more robust way + * (right now regex string replacement is used). + * For more discussion see https://github.com/sveltejs/kit/pull/2453 + * + * @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 diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/Test.svelte b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/Test.svelte new file mode 100644 index 000000000000..1463588b2228 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/Test.svelte @@ -0,0 +1,4 @@ + diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/Test.svelte.d.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/Test.svelte.d.ts new file mode 100644 index 000000000000..613984c1649b --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/Test.svelte.d.ts @@ -0,0 +1,15 @@ +import { SvelteComponentTyped } from 'svelte'; +declare const __propDef: { + props: { + bar?: import('./sub/foo').Foo; + }; + events: { + [evt: string]: CustomEvent; + }; + 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 {} +export {}; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/baz.d.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/baz.d.ts new file mode 100644 index 000000000000..85f482c14ba7 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/baz.d.ts @@ -0,0 +1,4 @@ +export interface Baz { + baz: string; +} +export declare const baz: Baz; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/baz.js b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/baz.js new file mode 100644 index 000000000000..844535e7bc66 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/baz.js @@ -0,0 +1 @@ +export const baz = { baz: 'baz' }; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/index.d.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/index.d.ts new file mode 100644 index 000000000000..4c44188c3648 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/index.d.ts @@ -0,0 +1 @@ +export { default as Test } from './Test.svelte'; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/index.js b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/index.js new file mode 100644 index 000000000000..4c44188c3648 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/index.js @@ -0,0 +1 @@ +export { default as Test } from './Test.svelte'; 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 new file mode 100644 index 000000000000..78ebd4d10fb4 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/package.json @@ -0,0 +1,15 @@ +{ + "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" + }, + "svelte": "./index.js" +} diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/bar.d.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/bar.d.ts new file mode 100644 index 000000000000..9f1a49e9dfd6 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/bar.d.ts @@ -0,0 +1,2 @@ +export declare const bar1: import('./foo').Foo; +export declare const bar2: import('../baz').Baz; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/bar.js b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/bar.js new file mode 100644 index 000000000000..17941b746387 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/bar.js @@ -0,0 +1,4 @@ +import { baz } from '../baz'; +import { foo } from './foo'; +export const bar1 = foo; +export const bar2 = baz; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/foo.d.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/foo.d.ts new file mode 100644 index 000000000000..b5b3928ab61d --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/foo.d.ts @@ -0,0 +1,4 @@ +export interface Foo { + foo: string; +} +export declare const foo: Foo; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/foo.js b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/foo.js new file mode 100644 index 000000000000..aaae90ec5bfc --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/expected/sub/foo.js @@ -0,0 +1 @@ +export const foo = { foo: 'foo' }; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/package.json b/packages/kit/src/packaging/test/fixtures/resolve-alias/package.json new file mode 100644 index 000000000000..65358d9a9a8a --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/package.json @@ -0,0 +1,5 @@ +{ + "name": "resolve-alias", + "version": "1.0.0", + "description": "package using $lib alias" +} diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/src/app.html b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/app.html new file mode 100644 index 000000000000..245305c4ef5b --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %svelte.head% + + +
%svelte.body%
+ + diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/Test.svelte b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/Test.svelte new file mode 100644 index 000000000000..6ba757b638c1 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/Test.svelte @@ -0,0 +1,5 @@ + diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/baz.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/baz.ts new file mode 100644 index 000000000000..7fe0964e7187 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/baz.ts @@ -0,0 +1,5 @@ +export interface Baz { + baz: string; +} + +export const baz: Baz = { baz: 'baz' }; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/index.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/index.ts new file mode 100644 index 000000000000..abb9e1104b39 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/index.ts @@ -0,0 +1 @@ +export { default as Test } from '$lib/Test.svelte'; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/sub/bar.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/sub/bar.ts new file mode 100644 index 000000000000..335e08c551d3 --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/sub/bar.ts @@ -0,0 +1,5 @@ +import { baz } from '$lib/baz'; +import { foo } from '$lib/sub/foo'; + +export const bar1 = foo; +export const bar2 = baz; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/sub/foo.ts b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/sub/foo.ts new file mode 100644 index 000000000000..f1cea24ce4ef --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/src/lib/sub/foo.ts @@ -0,0 +1,5 @@ +export interface Foo { + foo: string; +} + +export const foo: Foo = { foo: 'foo' }; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/svelte.config.cjs b/packages/kit/src/packaging/test/fixtures/resolve-alias/svelte.config.cjs new file mode 100644 index 000000000000..d0526bbb674d --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/svelte.config.cjs @@ -0,0 +1,5 @@ +const preprocess = require('svelte-preprocess'); + +module.exports = { + preprocess: preprocess() +}; diff --git a/packages/kit/src/packaging/test/fixtures/resolve-alias/tsconfig.json b/packages/kit/src/packaging/test/fixtures/resolve-alias/tsconfig.json new file mode 100644 index 000000000000..0f54c3906f8b --- /dev/null +++ b/packages/kit/src/packaging/test/fixtures/resolve-alias/tsconfig.json @@ -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"] +} diff --git a/packages/kit/src/packaging/test/index.js b/packages/kit/src/packaging/test/index.js index df0f01eef027..c7e01dbb8c31 100644 --- a/packages/kit/src/packaging/test/index.js +++ b/packages/kit/src/packaging/test/index.js @@ -113,4 +113,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(); diff --git a/packages/kit/tsconfig.json b/packages/kit/tsconfig.json index b288e319af6f..e407884ba5f3 100644 --- a/packages/kit/tsconfig.json +++ b/packages/kit/tsconfig.json @@ -16,5 +16,6 @@ "types/*": ["./types/*"] } }, - "include": ["src/**/*", "test/**/*", "types/**/*"] + "include": ["src/**/*", "test/**/*", "types/**/*"], + "exclude": ["src/packaging/test/fixtures/**/*"] }