feat: scaffold Astro + Tailwind project

This commit is contained in:
TerryM
2026-05-12 16:16:03 +08:00
parent 906eb5c763
commit 03d3800c6c
12097 changed files with 1266600 additions and 0 deletions

9
node_modules/astro/dist/core/preview/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import type { AstroInlineConfig } from '../../types/public/config.js';
import type { PreviewServer } from '../../types/public/preview.js';
/**
* Starts a local server to serve your static dist/ directory. This command is useful for previewing
* your build locally, before deploying it. It is not designed to be run in production.
*
* @experimental The JavaScript API is experimental
*/
export default function preview(inlineConfig: AstroInlineConfig): Promise<PreviewServer>;

77
node_modules/astro/dist/core/preview/index.js generated vendored Normal file
View File

@@ -0,0 +1,77 @@
import fs from "node:fs";
import { createRequire } from "node:module";
import { fileURLToPath, pathToFileURL } from "node:url";
import { AstroIntegrationLogger } from "../logger/core.js";
import { telemetry } from "../../events/index.js";
import { eventCliSession } from "../../events/session.js";
import { runHookConfigDone, runHookConfigSetup } from "../../integrations/hooks.js";
import { resolveConfig } from "../config/config.js";
import { loadOrCreateNodeLogger } from "../logger/load.js";
import { createSettings } from "../config/settings.js";
import { createRoutesList } from "../routing/create-manifest.js";
import { getPrerenderDefault } from "../../prerender/utils.js";
import { ensureProcessNodeEnv } from "../util.js";
import createStaticPreviewServer from "./static-preview-server.js";
import { getResolvedHostForHttpServer } from "./util.js";
async function preview(inlineConfig) {
ensureProcessNodeEnv("production");
const { userConfig, astroConfig } = await resolveConfig(inlineConfig ?? {}, "preview");
const logger = await loadOrCreateNodeLogger(astroConfig, inlineConfig ?? {});
telemetry.record(eventCliSession("preview", userConfig));
const _settings = await createSettings(
astroConfig,
inlineConfig.logLevel,
fileURLToPath(astroConfig.root)
);
const settings = await runHookConfigSetup({
settings: _settings,
command: "preview",
logger
});
await createRoutesList({ settings, cwd: inlineConfig.root }, logger);
settings.buildOutput = getPrerenderDefault(settings.config) ? "static" : "server";
await runHookConfigDone({ settings, logger, command: "preview" });
if (settings.buildOutput === "static") {
if (!fs.existsSync(settings.config.outDir)) {
const outDirPath = fileURLToPath(settings.config.outDir);
throw new Error(
`[preview] The output directory ${outDirPath} does not exist. Did you run \`astro build\`?`
);
}
const server2 = await createStaticPreviewServer(settings, logger);
return server2;
}
if (!settings.adapter) {
throw new Error(`[preview] No adapter found.`);
}
if (!settings.adapter.previewEntrypoint) {
throw new Error(
`[preview] The ${settings.adapter.name} adapter does not support the preview command.`
);
}
const require2 = createRequire(settings.config.root);
const previewEntrypointUrl = pathToFileURL(
require2.resolve(settings.adapter.previewEntrypoint.toString())
).href;
const previewModule = await import(previewEntrypointUrl);
if (typeof previewModule.default !== "function") {
throw new Error(`[preview] ${settings.adapter.name} cannot preview your app.`);
}
const server = await previewModule.default({
outDir: settings.config.outDir,
client: settings.config.build.client,
server: settings.config.build.server,
serverEntrypoint: new URL(settings.config.build.serverEntry, settings.config.build.server),
host: getResolvedHostForHttpServer(settings.config.server.host),
port: settings.config.server.port,
base: settings.config.base,
logger: new AstroIntegrationLogger(logger.options, settings.adapter.name),
headers: settings.config.server.headers,
allowedHosts: settings.config.server.allowedHosts,
root: settings.config.root
});
return server;
}
export {
preview as default
};

View File

@@ -0,0 +1,12 @@
import type http from 'node:http';
import type { AstroSettings } from '../../types/astro.js';
import type { AstroLogger } from '../logger/core.js';
interface PreviewServer {
host?: string;
port: number;
server: http.Server;
closed(): Promise<void>;
stop(): Promise<void>;
}
export default function createStaticPreviewServer(settings: AstroSettings, logger: AstroLogger): Promise<PreviewServer>;
export {};

View File

@@ -0,0 +1,82 @@
import { performance } from "node:perf_hooks";
import { fileURLToPath } from "node:url";
import { mergeConfig, preview } from "vite";
import * as msg from "../messages/runtime.js";
import { getResolvedHostForHttpServer } from "./util.js";
import { vitePluginAstroPreview } from "./vite-plugin-astro-preview.js";
import { BuildTimeAstroVersionProvider } from "../../cli/infra/build-time-astro-version-provider.js";
import { piccoloreTextStyler } from "../../cli/infra/piccolore-text-styler.js";
async function createStaticPreviewServer(settings, logger) {
const startServerTime = performance.now();
let previewServer;
try {
const astroPreviewConfig = {
configFile: false,
base: settings.config.base,
appType: "mpa",
build: {
outDir: fileURLToPath(settings.config.outDir)
},
root: fileURLToPath(settings.config.root),
preview: {
host: settings.config.server.host,
port: settings.config.server.port,
headers: settings.config.server.headers,
open: settings.config.server.open
},
plugins: [vitePluginAstroPreview(settings)]
};
const { plugins: _plugins, ...userViteConfig } = settings.config.vite ?? {};
const mergedViteConfig = mergeConfig(userViteConfig, astroPreviewConfig);
const { allowedHosts } = settings.config.server;
if (typeof allowedHosts === "boolean" || Array.isArray(allowedHosts) && allowedHosts.length > 0) {
mergedViteConfig.preview ??= {};
mergedViteConfig.preview.allowedHosts = allowedHosts;
}
previewServer = await preview(mergedViteConfig);
} catch (err) {
if (err instanceof Error) {
logger.error(null, err.stack || err.message);
}
throw err;
}
const customShortcuts = [
// Disable default Vite shortcuts that don't work well with Astro
{ key: "r", description: "" },
{ key: "u", description: "" },
{ key: "c", description: "" },
{ key: "s", description: "" }
];
previewServer.bindCLIShortcuts({
customShortcuts
});
logger.info(
"SKIP_FORMAT",
msg.serverStart({
startupTime: performance.now() - startServerTime,
resolvedUrls: previewServer.resolvedUrls ?? { local: [], network: [] },
host: settings.config.server.host,
base: settings.config.base,
astroVersionProvider: new BuildTimeAstroVersionProvider(),
textStyler: piccoloreTextStyler
})
);
function closed() {
return new Promise((resolve, reject) => {
previewServer.httpServer.addListener("close", resolve);
previewServer.httpServer.addListener("error", reject);
});
}
const address = previewServer.httpServer.address();
const actualPort = address && typeof address === "object" ? address.port : settings.config.server.port;
return {
host: getResolvedHostForHttpServer(settings.config.server.host),
port: actualPort,
closed,
server: previewServer.httpServer,
stop: previewServer.close.bind(previewServer)
};
}
export {
createStaticPreviewServer as default
};

2
node_modules/astro/dist/core/preview/util.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare function getResolvedHostForHttpServer(host: string | boolean): string | undefined;
export declare function stripBase(path: string, base: string): string;

20
node_modules/astro/dist/core/preview/util.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
function getResolvedHostForHttpServer(host) {
if (host === false) {
return "localhost";
} else if (host === true) {
return void 0;
} else {
return host;
}
}
function stripBase(path, base) {
if (path === base) {
return "/";
}
const baseWithSlash = base.endsWith("/") ? base : base + "/";
return path.replace(RegExp("^" + baseWithSlash), "/");
}
export {
getResolvedHostForHttpServer,
stripBase
};

View File

@@ -0,0 +1,3 @@
import type { Plugin } from 'vite';
import type { AstroSettings } from '../../types/astro.js';
export declare function vitePluginAstroPreview(settings: AstroSettings): Plugin;

View File

@@ -0,0 +1,77 @@
import fs from "node:fs";
import { fileURLToPath } from "node:url";
import { notFoundTemplate, subpathNotUsedTemplate } from "../../template/4xx.js";
import { cleanUrl } from "../../vite-plugin-utils/index.js";
import { stripBase } from "./util.js";
const HAS_FILE_EXTENSION_REGEXP = /\.[^/]+$/;
function vitePluginAstroPreview(settings) {
const { base, outDir, trailingSlash } = settings.config;
function handle404(req, res) {
const errorPagePath = fileURLToPath(outDir + "/404.html");
if (fs.existsSync(errorPagePath)) {
res.statusCode = 404;
res.setHeader("Content-Type", "text/html");
res.end(fs.readFileSync(errorPagePath));
} else {
res.statusCode = 404;
res.end(notFoundTemplate(req.url, "Not Found"));
}
}
return {
name: "astro:preview",
apply: "serve",
configurePreviewServer(server) {
server.middlewares.use((req, res, next) => {
if (!req.url.startsWith(base)) {
res.statusCode = 404;
res.end(subpathNotUsedTemplate(base, req.url));
return;
}
const pathname = cleanUrl(stripBase(req.url, base));
const isRoot = pathname === "/";
if (!isRoot) {
const hasTrailingSlash = pathname.endsWith("/");
if (hasTrailingSlash && trailingSlash === "never") {
res.statusCode = 404;
res.end(notFoundTemplate(pathname, 'Not Found (trailingSlash is set to "never")'));
return;
}
if (!hasTrailingSlash && trailingSlash === "always" && !HAS_FILE_EXTENSION_REGEXP.test(pathname)) {
res.statusCode = 404;
res.end(notFoundTemplate(pathname, 'Not Found (trailingSlash is set to "always")'));
return;
}
}
for (const middleware of server.middlewares.stack) {
if (middleware.handle.name === "vite404Middleware") {
middleware.handle = handle404;
}
}
next();
});
return () => {
server.middlewares.use((req, _res, next) => {
const pathname = cleanUrl(req.url);
if (pathname.endsWith("/")) {
const pathnameWithoutSlash = pathname.slice(0, -1);
const htmlPath = fileURLToPath(outDir + pathnameWithoutSlash + ".html");
if (fs.existsSync(htmlPath)) {
req.url = pathnameWithoutSlash + ".html";
return next();
}
} else {
const htmlPath = fileURLToPath(outDir + pathname + "/index.html");
if (fs.existsSync(htmlPath)) {
req.url = pathname + "/index.html";
return next();
}
}
next();
});
};
}
};
}
export {
vitePluginAstroPreview
};