-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(sveltekit): Read adapter output directory from svelte.config.js
#7863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* eslint-disable @sentry-internal/sdk/no-optional-chaining */ | ||
|
||
import type { Builder, Config } from '@sveltejs/kit'; | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import * as url from 'url'; | ||
|
||
/** | ||
* Imports the svelte.config.js file and returns the config object. | ||
* The sveltekit plugins import the config in the same way. | ||
* See: https://github.com/sveltejs/kit/blob/master/packages/kit/src/core/config/index.js#L63 | ||
*/ | ||
export async function loadSvelteConfig(): Promise<Config> { | ||
// This can only be .js (see https://github.com/sveltejs/kit/pull/4031#issuecomment-1049475388) | ||
const SVELTE_CONFIG_FILE = 'svelte.config.js'; | ||
|
||
const configFile = path.join(process.cwd(), SVELTE_CONFIG_FILE); | ||
|
||
try { | ||
if (!fs.existsSync(configFile)) { | ||
return {}; | ||
} | ||
// @ts-ignore - we explicitly want to import the svelte config here. | ||
const svelteConfigModule = await import(`${url.pathToFileURL(configFile).href}`); | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access | ||
return (svelteConfigModule?.default as Config) || {}; | ||
} catch (e) { | ||
// eslint-disable-next-line no-console | ||
console.warn("[Source Maps Plugin] Couldn't load svelte.config.js:"); | ||
// eslint-disable-next-line no-console | ||
console.log(e); | ||
|
||
return {}; | ||
} | ||
} | ||
|
||
/** | ||
* Attempts to read a custom output directory that can be specidied in the options | ||
* of a SvelteKit adapter. If no custom output directory is specified, the default | ||
* directory is returned. | ||
* | ||
* To get the directory, we have to apply a hack and call the adapter's adapt method | ||
* with a custom adapter `Builder` that only calls the `writeClient` method. | ||
* This method is the first method that is called with the output directory. | ||
* Once we obtained the output directory, we throw an error to exit the adapter. | ||
* | ||
* see: https://github.com/sveltejs/kit/blob/master/packages/adapter-node/index.js#L17 | ||
* | ||
*/ | ||
export async function getAdapterOutputDir(svelteConfig: Config): Promise<string> { | ||
// 'build' is the default output dir for the node adapter | ||
let outputDir = 'build'; | ||
|
||
if (!svelteConfig.kit?.adapter) { | ||
return outputDir; | ||
} | ||
|
||
const adapter = svelteConfig.kit.adapter; | ||
|
||
const adapterBuilder: Builder = { | ||
writeClient(dest: string) { | ||
outputDir = dest.replace(/\/client.*/, ''); | ||
throw new Error('We got what we came for, throwing to exit the adapter'); | ||
}, | ||
// @ts-ignore - No need to implement the other methods | ||
log: { | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function -- this should be a noop | ||
minor() {}, | ||
}, | ||
getBuildDirectory: () => '', | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function -- this should be a noop | ||
rimraf: () => {}, | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function -- this should be a noop | ||
mkdirp: () => {}, | ||
|
||
config: { | ||
kit: { | ||
// @ts-ignore - the builder expects a validated config but for our purpose it's fine to just pass this partial config | ||
paths: { | ||
base: svelteConfig.kit?.paths?.base || '', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
try { | ||
await adapter.adapt(adapterBuilder); | ||
} catch (_) { | ||
// We expect the adapter to throw in writeClient! | ||
} | ||
|
||
return outputDir; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { vi } from 'vitest'; | ||
|
||
import { getAdapterOutputDir, loadSvelteConfig } from '../../src/vite/svelteConfig'; | ||
|
||
let existsFile; | ||
|
||
describe('loadSvelteConfig', () => { | ||
vi.mock('fs', () => { | ||
return { | ||
existsSync: () => existsFile, | ||
}; | ||
}); | ||
|
||
vi.mock(`${process.cwd()}/svelte.config.js`, () => { | ||
return { | ||
default: { | ||
kit: { | ||
adapter: {}, | ||
}, | ||
}, | ||
}; | ||
}); | ||
|
||
// url apparently doesn't exist in the test environment, therefore we mock it: | ||
vi.mock('url', () => { | ||
return { | ||
pathToFileURL: path => { | ||
return { | ||
href: path, | ||
}; | ||
}, | ||
}; | ||
}); | ||
|
||
beforeEach(() => { | ||
existsFile = true; | ||
vi.clearAllMocks(); | ||
}); | ||
|
||
it('returns the svelte config', async () => { | ||
const config = await loadSvelteConfig(); | ||
expect(config).toStrictEqual({ | ||
kit: { | ||
adapter: {}, | ||
}, | ||
}); | ||
}); | ||
|
||
it('returns an empty object if svelte.config.js does not exist', async () => { | ||
existsFile = false; | ||
|
||
const config = await loadSvelteConfig(); | ||
expect(config).toStrictEqual({}); | ||
}); | ||
}); | ||
|
||
describe('getAdapterOutputDir', () => { | ||
const mockedAdapter = { | ||
name: 'mocked-adapter', | ||
adapt(builder) { | ||
builder.writeClient('customBuildDir'); | ||
}, | ||
}; | ||
|
||
it('returns the output directory of the adapter', async () => { | ||
const outputDir = await getAdapterOutputDir({ kit: { adapter: mockedAdapter } }); | ||
expect(outputDir).toEqual('customBuildDir'); | ||
}); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is technically breaking as it changes the return type of the function but the good news is that noone has to await this function as the vite config is perfectly fine with taking a
Promise<Plugin[]>
. I should have done this already but for some reason decided to stay sync in #7811. I vote we go forward with making it async, not just because we need it for this change but also because it gives us more freedom in the future.Also, we're still in alpha, so yolo...