diff --git a/docs/src/pages/reference/renderer-reference.md b/docs/src/pages/reference/renderer-reference.md
index 15c90a3c2..cf0b37fd9 100644
--- a/docs/src/pages/reference/renderer-reference.md
+++ b/docs/src/pages/reference/renderer-reference.md
@@ -38,8 +38,8 @@ A renderer should include any framework dependencies as package dependencies. Fo
// package.json
"name": "@astrojs/renderer-react",
"dependencies": {
- "react": "^17.0.0",
- "react-dom": "^17.0.0"
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2"
}
```
@@ -56,8 +56,6 @@ export default {
name: '@astrojs/renderer-xxx', // the renderer name
client: './client.js', // relative path to the client entrypoint
server: './server.js', // optional, relative path to the server entrypoint
- snowpackPlugin: '@snowpack/plugin-xxx', // optional, the name of a snowpack plugin to inject
- snowpackPluginOptions: { example: true }, // optional, any options to be forwarded to the snowpack plugin
knownEntrypoint: ['framework'], // optional, entrypoint modules that will be used by compiled source
external: ['dep'], // optional, dependencies that should not be built by snowpack
polyfills: ['./shadow-dom-polyfill.js'], // optional, module scripts that should be loaded before client hydration.
@@ -72,6 +70,7 @@ export default {
plugins: [jsx({}, { runtime: 'automatic', importSource: 'preact' })],
};
},
+ vitePlugins: [], // optional, inject Vite plugins here (https://vitejs.dev/plugins/#plugins)
};
```
diff --git a/examples/blog-multiple-authors/src/components/MainHead.astro b/examples/blog-multiple-authors/src/components/MainHead.astro
index 0392f6d94..3e56774e0 100644
--- a/examples/blog-multiple-authors/src/components/MainHead.astro
+++ b/examples/blog-multiple-authors/src/components/MainHead.astro
@@ -18,7 +18,7 @@ const { title, description, image, type, next, prev, canonicalURL } = Astro.prop
-
+
diff --git a/examples/blog/src/pages/posts/introducing-astro.md b/examples/blog/src/pages/posts/introducing-astro.md
deleted file mode 100644
index 114161cd9..000000000
--- a/examples/blog/src/pages/posts/introducing-astro.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-title: 'Introducing Astro: Ship Less JavaScript'
-description: "We're excited to announce Astro as a new way to build static websites and deliver lightning-fast performance without sacrificing a modern developer experience."
-publishDate: 'Tuesday, June 8 2021'
-author: 'fred'
-heroImage: '/social.jpg'
-alt: 'Astro'
-layout: '../../layouts/BlogPost.astro'
----
-
-There's a simple secret to building a faster website — _just ship less_.
-
-Unfortunately, modern web development has been trending in the opposite direction—towards _more._ More JavaScript, more features, more moving parts, and ultimately more complexity needed to keep it all running smoothly.
-
-Today I'm excited to publicly share Astro: a new kind of static site builder that delivers lightning-fast performance with a modern developer experience. To design Astro, we borrowed the best parts of our favorite tools and then added a few innovations of our own, including:
-
-- **Bring Your Own Framework (BYOF):** Build your site using React, Svelte, Vue, Preact, web components, or just plain ol' HTML + JavaScript.
-- **100% Static HTML, No JS:** Astro renders your entire page to static HTML, removing all JavaScript from your final build by default.
-- **On-Demand Components:** Need some JS? Astro can automatically hydrate interactive components when they become visible on the page. If the user never sees it, they never load it.
-- **Fully-Featured:** Astro supports TypeScript, Scoped CSS, CSS Modules, Sass, Tailwind, Markdown, MDX, and any of your favorite npm packages.
-- **SEO Enabled:** Automatic sitemaps, RSS feeds, pagination and collections take the pain out of SEO and syndication.
-
-This post marks the first public beta release of Astro. **Missing features and bugs are still to be expected at this early stage.** There are still some months to go before an official 1.0 release, but there are already several fast sites built with Astro in production today. We would love your early feedback as we move towards a v1.0 release later this year.
-
-> To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides).
-
-## Getting Started
-
-Starting a new project in Astro is easy:
-
-```shell
-# create your project
-mkdir new-project-directory
-cd new-project-directory
-npm init astro
-
-# install your dependencies
-npm install
-
-# start the dev server and open your browser
-npm run dev
-```
-
-> To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides).
-
-## How Astro Works
-
-Astro works a lot like a static site generator. If you have ever used Eleventy, Hugo, or Jekyll (or even a server-side web framework like Rails, Laravel, or Django) then you should feel right at home with Astro.
-
-In Astro, you compose your website using UI components from your favorite JavaScript web framework (React, Svelte, Vue, etc). Astro renders your entire site to static HTML during the build. The result is a fully static website with all JavaScript removed from the final page. No monolithic JavaScript application required, just static HTML that loads as fast as possible in the browser regardless of how many UI components you used to generate it.
-
-Of course, sometimes client-side JavaScript is inevitable. Image carousels, shopping carts, and auto-complete search bars are just a few examples of things that require some JavaScript to run in the browser. This is where Astro really shines: When a component needs some JavaScript, Astro only loads that one component (and any dependencies). The rest of your site continues to exist as static, lightweight HTML.
-
-In other full-stack web frameworks this level of per-component optimization would be impossible without loading the entire page in JavaScript, delaying interactivity. In Astro, this kind of [partial hydration](https://addyosmani.com/blog/rehydration/) is built into the tool itself.
-
-You can even [automatically defer components](https://codepen.io/jonneal/full/ZELvMvw) to only load once they become visible on the page with the `client:visible` directive.
-
-This new approach to web architecture is called [islands architecture](https://jasonformat.com/islands-architecture/). We didn't coin the term, but Astro may have perfected the technique. We are confident that an HTML-first, JavaScript-only-as-needed approach is the best solution for the majority of content-based websites.
-
-> To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides)
-
-## Embracing the Pit of Success
-
-> A well-designed system makes it easy to do the right things and annoying (but not impossible) to do the wrong things
– Jeff Atwood
[Falling Into The Pit of Success](https://blog.codinghorror.com/falling-into-the-pit-of-success/)
-
-Poor performance is often framed as a failure of the developer, but we respectfully disagree. In many cases, poor performance is a failure of tooling. It should be difficult to build a slow website.
-
-Astro's main design principle is to lead developers into what [Rico Mariani](https://twitter.com/ricomariani) dubbed "the pit of success". It is our goal to build every site "fast by default" while also delivering a familiar, modern developer experience.
-
-By building your site to static HTML by default, Astro makes it difficult (but never impossible 😉) to build a slow site.
-
-## Long-Term Sustainability
-
-Astro is built by the team of open source developers behind [Snowpack](https://snowpack.dev) and [Skypack](https://skypack.dev), with additional contributions from the community.
-
-**Astro is and always will be free.** It is an open source project released under the [MIT license](https://github.com/snowpackjs/astro/blob/main/LICENSE).
-
-We care deeply about building a more sustainable future for open source software. At the same time, we need to support Astro's development long-term. This requires money (donations alone aren't enough.)
-
-We're inspired by the early success of projects like [Tailwind](https://tailwindcss.com/), [Rome](https://rome.tools/), [Remix](https://remix.run/), [Ionic](https://ionicframework.com/), and others who are experimenting with long-term financial sustainability on top of Open Source. Over the next year we'll be exploring how we can create a sustainable business to support a 100% free, open source Astro for years to come.
-
-If your company is as excited about Astro as we are, [we'd love to hear from you.](https://astro.build/chat)
-
-Finally, I'd like to give a **HUGE** thanks to the 300+ developers who joined our earliest private beta. Your feedback has been essential in shaping Astro into the tool it is today. If you're interested in getting involved (or just following along with development) please [join us on Discord.](https://astro.build/chat)
-
-> To learn more about Astro and start building your first site, check out [the project README.](https://github.com/snowpackjs/astro#-guides)
diff --git a/package.json b/package.json
index 63c408091..cc71dc224 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"test:templates": "lerna run test --scope create-astro --stream"
},
"workspaces": [
+ "compiled/*",
"packages/renderers/*",
"packages/*",
"examples/*",
@@ -44,7 +45,6 @@
"devDependencies": {
"@changesets/cli": "^2.16.0",
"@octokit/action": "^3.15.4",
- "@snowpack/plugin-postcss": "^1.4.3",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.18.0",
"autoprefixer": "^10.2.6",
@@ -57,12 +57,9 @@
"eslint-plugin-prettier": "^3.4.0",
"execa": "^5.0.0",
"lerna": "^4.0.0",
- "postcss": "^8.2.15",
- "postcss-icss-keyframes": "^0.2.1",
- "prettier": "^2.2.1",
- "svelte": "^3.38.0",
+ "prettier": "^2.3.2",
"tiny-glob": "^0.2.8",
- "typescript": "^4.2.4",
+ "typescript": "^4.4.2",
"uvu": "^0.5.1"
},
"engines": {
diff --git a/packages/astro/astro.js b/packages/astro/astro.js
index c5dec5f66..7725c1366 100755
--- a/packages/astro/astro.js
+++ b/packages/astro/astro.js
@@ -13,6 +13,7 @@ const CI_INTRUCTIONS = {
VERCEL: 'https://vercel.com/docs/runtimes#official-runtimes/node-js/node-js-version',
};
+/** `astro *` */
async function main() {
// Check for ESM support.
// Load the "supports-esm" package in an way that works in both ESM & CJS.
@@ -29,7 +30,7 @@ async function main() {
// Preflight check complete. Enjoy! ✨
if (supportsESM) {
- return import('./dist/cli.js')
+ return import('./dist/cli/index.js')
.then(({ cli }) => cli(process.argv))
.catch((error) => {
console.error(error);
diff --git a/packages/astro/components/Markdown.astro b/packages/astro/components/Markdown.astro
index b2639804d..609d015d4 100644
--- a/packages/astro/components/Markdown.astro
+++ b/packages/astro/components/Markdown.astro
@@ -1,5 +1,24 @@
----
+
+import fetch from 'node-fetch';
import { renderMarkdown } from '@astrojs/markdown-support';
+import { __astro_slot } from 'astro/runtime/__astro_slot.js';
+
+if(!('fetch' in globalThis)) {
+ globalThis.fetch = fetch;
+}
+
+
+const __TopLevelAstro = {
+ site: new URL("http://localhost:3000"),
+ fetchContent: (globResult) => fetchContent(globResult, import.meta.url),
+ resolve(...segments) {
+ return segments.reduce(
+ (url, segment) => new URL(segment, url),
+ new URL("http://localhost:3000/packages/astro/components/Markdown.astro")
+ ).pathname
+ },
+};
+const Astro = __TopLevelAstro;
export interface Props {
content?: string;
@@ -13,10 +32,43 @@ interface InternalProps extends Props {
const { content, $scope } = Astro.props as InternalProps;
let html = null;
-// This flow is only triggered if a user passes ``
+
+
+
+// `__render()`: Render the contents of the Astro module.
+import { h, Fragment } from 'astro/runtime/h.js';
+const __astroInternal = Symbol('astro.internal');
+const __astroContext = Symbol.for('astro.context');
+async function __render(props, ...children) {
+ const Astro = Object.create(__TopLevelAstro, {
+ props: {
+ value: props,
+ enumerable: true
+ },
+ pageCSS: {
+ value: (props[__astroContext] && props[__astroContext].pageCSS) || [],
+ enumerable: true
+ },
+ isPage: {
+ value: (props[__astroInternal] && props[__astroInternal].isPage) || false,
+ enumerable: true
+ },
+ request: {
+ value: (props[__astroContext] && props[__astroContext].request) || {},
+ enumerable: true
+ },
+ });
+
+ const {
+ content,
+ $scope
+} = Astro.props;
+let html = null;
if (content) {
- const { content: htmlContent } = await renderMarkdown(content, {
- mode: 'md',
+ const {
+ content: htmlContent
+ } = await renderMarkdown(content, {
+ mode: "md",
$: {
scopedClassName: $scope
}
@@ -24,9 +76,55 @@ if (content) {
html = htmlContent;
}
-/*
- If we have rendered `html` for `content`, render that
- Otherwise, just render the slotted content
-*/
----
-{html ? html : }
+ return h(Fragment, null, h(Fragment, null,(html ? html : h(Fragment, null, h(__astro_slot, { [__astroContext]: props[__astroContext] }, children)))));
+}
+export default { isAstroComponent: true, __render };
+
+// `__renderPage()`: Render the contents of the Astro module as a page. This is a special flow,
+// triggered by loading a component directly by URL.
+export async function __renderPage({request, children, props, css}) {
+ const currentChild = {
+ isAstroComponent: true,
+ layout: typeof __layout === 'undefined' ? undefined : __layout,
+ content: typeof __content === 'undefined' ? undefined : __content,
+ __render,
+ };
+
+ const isLayout = (__astroContext in props);
+ if(!isLayout) {
+ let astroRootUIDCounter = 0;
+ Object.defineProperty(props, __astroContext, {
+ value: {
+ pageCSS: css,
+ request,
+ createAstroRootUID(seed) { return seed + astroRootUIDCounter++; },
+ },
+ writable: false,
+ enumerable: false
+ });
+ }
+
+ Object.defineProperty(props, __astroInternal, {
+ value: {
+ isPage: !isLayout
+ },
+ writable: false,
+ enumerable: false
+ });
+
+ const childBodyResult = await currentChild.__render(props, children);
+
+ // find layout, if one was given.
+ if (currentChild.layout) {
+ return currentChild.layout({
+ request,
+ props: {content: currentChild.content, [__astroContext]: props[__astroContext]},
+ children: [childBodyResult],
+ });
+ }
+
+ return childBodyResult;
+};
+
+
+
diff --git a/packages/astro/components/Prism.astro b/packages/astro/components/Prism.astro
index ba4b22ec3..5942a0428 100644
--- a/packages/astro/components/Prism.astro
+++ b/packages/astro/components/Prism.astro
@@ -1,7 +1,12 @@
----
-import Prism from 'prismjs';
-import { addAstro } from '@astrojs/prism';
+
+import fetch from 'node-fetch';
import loadLanguages from 'prismjs/components/index.js';
+import { addAstro } from '@astrojs/prism';
+import Prism from 'prismjs';
+
+if(!('fetch' in globalThis)) {
+ globalThis.fetch = fetch;
+}
export interface Props {
class?: string;
@@ -13,40 +18,128 @@ const { class: className, lang, code } = Astro.props as Props;
let classLanguage = `language-${lang}`
-const languageMap = new Map([
- ['ts', 'typescript']
-]);
+const __TopLevelAstro = {
+ site: new URL("http://localhost:3000"),
+ fetchContent: (globResult) => fetchContent(globResult, import.meta.url),
+ resolve(...segments) {
+ return segments.reduce(
+ (url, segment) => new URL(segment, url),
+ new URL("http://localhost:3000/packages/astro/components/Prism.astro")
+ ).pathname
+ },
+};
+const Astro = __TopLevelAstro;
+
+
+
+
+// `__render()`: Render the contents of the Astro module.
+import { h, Fragment } from 'astro/runtime/h.js';
+const __astroInternal = Symbol('astro.internal');
+const __astroContext = Symbol.for('astro.context');
+async function __render(props, ...children) {
+ const Astro = Object.create(__TopLevelAstro, {
+ props: {
+ value: props,
+ enumerable: true
+ },
+ pageCSS: {
+ value: (props[__astroContext] && props[__astroContext].pageCSS) || [],
+ enumerable: true
+ },
+ isPage: {
+ value: (props[__astroInternal] && props[__astroInternal].isPage) || false,
+ enumerable: true
+ },
+ request: {
+ value: (props[__astroContext] && props[__astroContext].request) || {},
+ enumerable: true
+ },
+ });
+
+ const {
+ class: className,
+ lang,
+ code
+} = Astro.props;
+let classLanguage = `language-${lang}`;
+const languageMap = new Map([["ts", "typescript"]]);
if (lang == null) {
- console.warn('Prism.astro: No language provided.');
+ console.warn("Prism.astro: No language provided.");
}
-
-const ensureLoaded = lang => {
- if(lang && !Prism.languages[lang]) {
- loadLanguages([lang]);
+const ensureLoaded = (lang2) => {
+ if (lang2 && !Prism.languages[lang2]) {
+ loadLanguages([lang2]);
}
};
-
-if(languageMap.has(lang)) {
+if (languageMap.has(lang)) {
ensureLoaded(languageMap.get(lang));
-} else if(lang === 'astro') {
- ensureLoaded('typescript');
+} else if (lang === "astro") {
+ ensureLoaded("typescript");
addAstro(Prism);
} else {
- ensureLoaded('markup-templating'); // Prism expects this to exist for a number of other langs
+ ensureLoaded("markup-templating");
ensureLoaded(lang);
}
-
-if(lang && !Prism.languages[lang]) {
+if (lang && !Prism.languages[lang]) {
console.warn(`Unable to load the language: ${lang}`);
}
-
const grammar = Prism.languages[lang];
let html = code;
if (grammar) {
html = Prism.highlight(code, grammar, lang);
}
----
+ return h(Fragment, null, h(Fragment, null,h("pre", {"class":([className, classLanguage].join(" ")),[__astroContext]:props[__astroContext]},h("code", {"class":(classLanguage),[__astroContext]:props[__astroContext]},(html)))));
+}
+export default { isAstroComponent: true, __render };
+
+// `__renderPage()`: Render the contents of the Astro module as a page. This is a special flow,
+// triggered by loading a component directly by URL.
+export async function __renderPage({request, children, props, css}) {
+ const currentChild = {
+ isAstroComponent: true,
+ layout: typeof __layout === 'undefined' ? undefined : __layout,
+ content: typeof __content === 'undefined' ? undefined : __content,
+ __render,
+ };
+
+ const isLayout = (__astroContext in props);
+ if(!isLayout) {
+ let astroRootUIDCounter = 0;
+ Object.defineProperty(props, __astroContext, {
+ value: {
+ pageCSS: css,
+ request,
+ createAstroRootUID(seed) { return seed + astroRootUIDCounter++; },
+ },
+ writable: false,
+ enumerable: false
+ });
+ }
+
+ Object.defineProperty(props, __astroInternal, {
+ value: {
+ isPage: !isLayout
+ },
+ writable: false,
+ enumerable: false
+ });
+
+ const childBodyResult = await currentChild.__render(props, children);
+
+ // find layout, if one was given.
+ if (currentChild.layout) {
+ return currentChild.layout({
+ request,
+ props: {content: currentChild.content, [__astroContext]: props[__astroContext]},
+ children: [childBodyResult],
+ });
+ }
+
+ return childBodyResult;
+};
+
+
-
{html}
diff --git a/packages/astro/internal.d.ts b/packages/astro/internal.d.ts
deleted file mode 100644
index 40b65ffb3..000000000
--- a/packages/astro/internal.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-declare module '#astro/compiler' {
- export * from 'astro/dist/types/compiler';
-}
-declare module '#astro/ast' {
- export * from 'astro/dist/types/ast';
-}
-declare module '#astro/build' {
- export * from 'astro/dist/types/build';
-}
-declare module '#astro/cli' {
- export * from 'astro/dist/types/cli';
-}
-declare module '#astro/config' {
- export * from 'astro/dist/types/config';
-}
-declare module '#astro/dev' {
- export * from 'astro/dist/types/dev';
-}
-declare module '#astro/logger' {
- export * from 'astro/dist/types/logger';
-}
-declare module '#astro/runtime' {
- export * from 'astro/dist/types/runtime';
-}
-declare module '#astro/search' {
- export * from 'astro/dist/types/search';
-}
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 718cd938f..77b1499dc 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -12,18 +12,14 @@
},
"exports": {
".": "./astro.js",
- "./package.json": "./package.json",
- "./snowpack-plugin": "./snowpack-plugin.cjs",
- "./snowpack-plugin-jsx": "./snowpack-plugin-jsx.cjs",
+ "./client/*": "./dist/client/*",
"./components": "./components/index.js",
"./debug": "./components/Debug.astro",
"./components/*": "./components/*",
- "./runtime/svelte": "./dist/frontend/runtime/svelte.js",
- "./internal/*": "./dist/internal/*",
- "./dist/internal/*": "./dist/internal/*"
+ "./package.json": "./package.json",
+ "./runtime/*": "./dist/runtime/*"
},
"imports": {
- "#astro/compiler": "./dist/compiler/index.js",
"#astro/*": "./dist/*.js"
},
"bin": {
@@ -32,8 +28,6 @@
"files": [
"components",
"dist",
- "snowpack-plugin-jsx.cjs",
- "snowpack-plugin.cjs",
"astro.js"
],
"scripts": {
@@ -44,81 +38,46 @@
"test": "uvu test -i fixtures -i benchmark -i test-utils.js"
},
"dependencies": {
- "@astrojs/markdown-support": "0.3.1",
- "@astrojs/parser": "0.20.2",
- "@astrojs/prism": "0.2.2",
- "@astrojs/renderer-preact": "0.2.2",
- "@astrojs/renderer-react": "0.2.1",
- "@astrojs/renderer-svelte": "0.1.2",
- "@astrojs/renderer-vue": "0.1.8",
- "@babel/code-frame": "^7.12.13",
- "@babel/core": "^7.14.6",
- "@babel/generator": "^7.13.9",
- "@babel/parser": "^7.13.15",
- "@babel/traverse": "^7.13.15",
- "@snowpack/plugin-postcss": "^1.4.3",
- "@snowpack/plugin-sass": "^1.4.0",
- "@types/send": "^0.17.1",
- "acorn": "^7.4.0",
- "astring": "^1.7.4",
- "autoprefixer": "^10.2.5",
- "babel-plugin-module-resolver": "^4.1.0",
+ "@astrojs/markdown-support": "^0.3.1",
+ "@babel/core": "^7.15.0",
+ "@web/rollup-plugin-html": "^1.9.1",
+ "astring": "^1.7.5",
"camel-case": "^4.1.2",
- "cheerio": "^1.0.0-rc.6",
+ "chokidar": "^3.5.2",
"ci-info": "^3.2.0",
+ "connect": "^3.7.0",
"del": "^6.0.0",
- "es-module-lexer": "^0.4.1",
- "esbuild": "^0.12.12",
+ "es-module-lexer": "^0.7.1",
+ "esbuild": "^0.12.23",
"estree-util-value-to-estree": "^1.2.0",
- "estree-walker": "^3.0.0",
"fast-xml-parser": "^3.19.0",
- "fdir": "^5.0.0",
- "find-up": "^5.0.0",
- "get-port": "^5.1.1",
- "gzip-size": "^6.0.0",
+ "fdir": "^5.1.0",
"kleur": "^4.1.4",
- "magic-string": "^0.25.3",
"mime": "^2.5.2",
- "moize": "^6.0.1",
- "nanoid": "^3.1.23",
"node-fetch": "^2.6.1",
"path-to-regexp": "^6.2.0",
- "picomatch": "^2.2.3",
- "postcss": "^8.2.15",
- "postcss-icss-keyframes": "^0.2.1",
- "pretty-bytes": "^5.6.0",
- "prismjs": "^1.23.0",
- "resolve": "^1.20.0",
- "rollup": "^2.43.1",
- "rollup-plugin-terser": "^7.0.2",
- "sass": "^1.32.13",
+ "picomatch": "^2.3.0",
+ "sass": "^1.38.1",
"semver": "^7.3.5",
"send": "^0.17.1",
"shiki": "^0.9.10",
"shorthash": "^0.0.2",
"slash": "^4.0.0",
- "snowpack": "^3.8.6",
"srcset-parse": "^1.1.0",
+ "source-map": "^0.7.3",
"string-width": "^5.0.0",
"supports-esm": "^1.0.0",
- "tiny-glob": "^0.2.8",
- "yargs-parser": "^20.2.7",
+ "vite": "^2.5.1",
+ "yargs-parser": "^20.2.9",
"zod": "^3.8.1"
},
"devDependencies": {
- "@babel/types": "^7.14.0",
- "@types/babel__code-frame": "^7.0.2",
- "@types/babel__generator": "^7.6.2",
- "@types/babel__parser": "^7.1.1",
- "@types/babel__traverse": "^7.11.1",
- "@types/estree": "0.0.46",
+ "@types/babel__core": "^7.1.15",
+ "@types/connect": "^3.4.35",
"@types/mime": "^2.0.3",
- "@types/node": "^14.14.31",
- "@types/sass": "^1.16.0",
- "@types/yargs-parser": "^20.2.0",
- "astro-scripts": "0.0.1",
- "is-windows": "^1.0.2",
- "strip-ansi": "^7.0.0"
+ "@types/node-fetch": "^2.5.12",
+ "@types/send": "^0.17.1",
+ "@types/yargs-parser": "^20.2.1"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0",
diff --git a/packages/astro/snowpack-plugin-jsx.cjs b/packages/astro/snowpack-plugin-jsx.cjs
deleted file mode 100644
index da373e131..000000000
--- a/packages/astro/snowpack-plugin-jsx.cjs
+++ /dev/null
@@ -1,190 +0,0 @@
-const esbuild = require('esbuild');
-const colors = require('kleur/colors');
-const loggerPromise = import('./dist/logger.js');
-const { promises: fs } = require('fs');
-
-const babel = require('@babel/core');
-const eslexer = require('es-module-lexer');
-let error = (...args) => {};
-
-/**
- * @typedef {Object} PluginOptions - creates a new type named 'SpecialType'
- * @prop {import('./src/config_manager').ConfigManager} configManager
- * @prop {'development' | 'production'} mode
- */
-
-/**
- * Returns esbuild loader for a given file
- * @param filePath {string}
- * @returns {import('esbuild').Loader}
- */
-function getLoader(fileExt) {
- /** @type {any} */
- return fileExt.substr(1);
-}
-
-// The `tsx` loader in esbuild will remove unused imports, so we need to
-// be careful about esbuild not treating h, React, Fragment, etc. as unused.
-const PREVENT_UNUSED_IMPORTS = ';;(React,Fragment,h);';
-
-/**
- * @type {import('snowpack').SnowpackPluginFactory}
- */
-module.exports = function jsxPlugin(config, options = {}) {
- const { configManager, logging } = options;
-
- let didInit = false;
- return {
- name: '@astrojs/snowpack-plugin-jsx',
- resolve: {
- input: ['.jsx', '.tsx'],
- output: ['.js'],
- },
- async load({ filePath, fileExt, ...transformContext }) {
- if (!didInit) {
- const logger = await loggerPromise;
- error = logger.error;
- await eslexer.init;
- didInit = true;
- }
-
- const contents = await fs.readFile(filePath, 'utf8');
- const loader = getLoader(fileExt);
-
- const { code, warnings } = await esbuild.transform(contents, {
- loader,
- jsx: 'preserve',
- sourcefile: filePath,
- sourcemap: config.buildOptions.sourcemap ? 'inline' : undefined,
- charset: 'utf8',
- sourcesContent: config.mode !== 'production',
- });
- for (const warning of warnings) {
- error(
- logging,
- 'renderer',
- `${colors.bold('!')} ${filePath}
- ${warning.text}`
- );
- }
-
- let renderers = await configManager.getRenderers();
- const importSources = new Set(renderers.map(({ jsxImportSource }) => jsxImportSource).filter((i) => i));
- const getRenderer = (importSource) => renderers.find(({ jsxImportSource }) => jsxImportSource === importSource);
- const getTransformOptions = async (importSource) => {
- const { name } = getRenderer(importSource);
- const { default: renderer } = await import(name);
- return renderer.jsxTransformOptions(transformContext);
- };
-
- if (importSources.size === 0) {
- throw new Error(`${colors.yellow(filePath)}
-Unable to resolve a renderer that handles JSX transforms! Please include a \`renderer\` plugin which supports JSX in your \`astro.config.mjs\` file.`);
- }
-
- // If we only have a single renderer, we can skip a bunch of work!
- if (importSources.size === 1) {
- const result = transform(code, filePath, await getTransformOptions(Array.from(importSources)[0]));
-
- return {
- '.js': {
- code: result.code || '',
- },
- };
- }
-
- // we need valid JS here, so we can use `h` and `Fragment` as placeholders
- // NOTE(fks, matthewp): Make sure that you're transforming the original contents here.
- const { code: codeToScan } = await esbuild.transform(contents + PREVENT_UNUSED_IMPORTS, {
- loader,
- jsx: 'transform',
- jsxFactory: 'h',
- jsxFragment: 'Fragment',
- });
-
- let imports = [];
- if (/import/.test(codeToScan)) {
- let [i] = eslexer.parse(codeToScan);
- // @ts-ignore
- imports = i;
- }
-
- let importSource;
-
- if (imports.length > 0) {
- for (let { n: name } of imports) {
- if (name.indexOf('/') > -1) name = name.split('/')[0];
- if (importSources.has(name)) {
- importSource = name;
- break;
- }
- }
- }
-
- if (!importSource) {
- const multiline = contents.match(/\/\*\*[\S\s]*\*\//gm) || [];
-
- for (const comment of multiline) {
- const [_, lib] = comment.match(/@jsxImportSource\s*(\S+)/) || [];
- if (lib) {
- importSource = lib;
- break;
- }
- }
- }
-
- if (!importSource) {
- const importStatements = {
- react: "import React from 'react'",
- preact: "import { h } from 'preact'",
- 'solid-js': "import 'solid-js/web'",
- };
- if (importSources.size > 1) {
- const defaultRenderer = Array.from(importSources)[0];
- error(
- logging,
- 'renderer',
- `${colors.yellow(filePath)}
-Unable to resolve a renderer that handles this file! With more than one renderer enabled, you should include an import or use a pragma comment.
-Add ${colors.cyan(importStatements[defaultRenderer] || `import '${defaultRenderer}';`)} or ${colors.cyan(`/* jsxImportSource: ${defaultRenderer} */`)} to this file.
-`
- );
- }
-
- return {
- '.js': {
- code: contents,
- },
- };
- }
-
- const result = transform(code, filePath, await getTransformOptions(importSource));
-
- return {
- '.js': {
- code: result.code || '',
- },
- };
- },
- cleanup() {},
- };
-};
-
-/**
- *
- * @param code {string}
- * @param id {string}
- * @param opts {{ plugins?: import('@babel/core').PluginItem[], presets?: import('@babel/core').PluginItem[] }|undefined}
- */
-const transform = (code, id, { alias, plugins = [], presets = [] } = {}) =>
- babel.transformSync(code, {
- presets,
- plugins: [...plugins, alias ? ['babel-plugin-module-resolver', { root: process.cwd(), alias }] : undefined].filter((v) => v),
- cwd: process.cwd(),
- filename: id,
- ast: false,
- compact: false,
- sourceMaps: false,
- configFile: false,
- babelrc: false,
- });
diff --git a/packages/astro/snowpack-plugin.cjs b/packages/astro/snowpack-plugin.cjs
deleted file mode 100644
index eb3c00281..000000000
--- a/packages/astro/snowpack-plugin.cjs
+++ /dev/null
@@ -1,69 +0,0 @@
-const { readFile } = require('fs').promises;
-const getPort = require('get-port');
-// Snowpack plugins must be CommonJS :(
-const transformPromise = import('./dist/compiler/index.js');
-
-const DEFAULT_HMR_PORT = 12321;
-
-/**
- * @typedef {Object} PluginOptions - creates a new type named 'SpecialType'
- * @prop {import('./src/config_manager').ConfigManager} configManager
- * @prop {'development' | 'production'} mode
- */
-
-/**
- * @type {import('snowpack').SnowpackPluginFactory}
- */
-module.exports = (snowpackConfig, options = {}) => {
- const { resolvePackageUrl, astroConfig, configManager, mode } = options;
- let hmrPort = DEFAULT_HMR_PORT;
- return {
- name: 'snowpack-astro',
- knownEntrypoints: ['astro/dist/internal/h.js', 'astro/components/Prism.astro', 'shorthash', 'estree-util-value-to-estree', 'astring'],
- resolve: {
- input: ['.astro', '.md'],
- output: ['.js', '.css'],
- },
- async transform({ contents, id, fileExt }) {
- if (configManager.isConfigModule(fileExt, id)) {
- configManager.configModuleId = id;
- const source = await configManager.buildSource(contents);
- return source;
- }
- },
- onChange({ filePath }) {
- // If the astro.config.mjs file changes, mark the generated config module as changed.
- if (configManager.isAstroConfig(filePath) && configManager.configModuleId) {
- this.markChanged(configManager.configModuleId);
- configManager.markDirty();
- }
- },
- async config(snowpackConfig) {
- if (!isNaN(snowpackConfig.devOptions.hmrPort)) {
- hmrPort = snowpackConfig.devOptions.hmrPort;
- } else {
- hmrPort = await getPort({ port: DEFAULT_HMR_PORT, host: snowpackConfig.devOptions.hostname });
- snowpackConfig.devOptions.hmrPort = hmrPort;
- }
- },
- async load({ filePath }) {
- const { compileComponent } = await transformPromise;
- const projectRoot = snowpackConfig.root;
- const contents = await readFile(filePath, 'utf-8');
-
- /** @type {import('./src/@types/compiler').CompileOptions} */
- const compileOptions = {
- astroConfig,
- hmrPort,
- mode,
- resolvePackageUrl,
- };
- const result = await compileComponent(contents, { compileOptions, filename: filePath, projectRoot });
- const output = {
- '.js': { code: result.contents },
- };
- if (result.css) output['.css'] = result.css;
- return output;
- },
- };
-};
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 0d1f1c0de..07fbfdebd 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -1,92 +1,286 @@
-import type { ImportSpecifier, ImportDefaultSpecifier, ImportNamespaceSpecifier } from '@babel/types';
-import type { AstroUserConfig, AstroConfig } from './config';
+import type { AstroMarkdownOptions } from '@astrojs/markdown-support';
+import type babel from '@babel/core';
+import type vite from 'vite';
+import type { z } from 'zod';
+import type { AstroConfigSchema } from '../config';
-export { AstroUserConfig, AstroConfig };
-export interface RouteData {
- type: 'page';
- pattern: RegExp;
- params: string[];
- path: string | null;
- component: string;
- generate: (data?: any) => string;
+export { AstroMarkdownOptions };
+
+export interface AstroComponentMetadata {
+ displayName: string;
+ hydrate?: 'load' | 'idle' | 'visible' | 'media' | 'only';
+ componentUrl?: string;
+ componentExport?: { value: string; namespace?: boolean };
+ value?: undefined | string;
}
+/**
+ * The Astro User Config Format:
+ * This is the type interface for your astro.config.mjs default export.
+ */
+export interface AstroUserConfig {
+ /**
+ * Where to resolve all URLs relative to. Useful if you have a monorepo project.
+ * Default: '.' (current working directory)
+ */
+ projectRoot?: string;
+ /**
+ * Path to the `astro build` output.
+ * Default: './dist'
+ */
+ dist?: string;
+ /**
+ * Path to all of your Astro components, pages, and data.
+ * Default: './src'
+ */
+ src?: string;
+ /**
+ * Path to your Astro/Markdown pages. Each file in this directory
+ * becomes a page in your final build.
+ * Default: './src/pages'
+ */
+ pages?: string;
+ /**
+ * Path to your public files. These are copied over into your build directory, untouched.
+ * Useful for favicons, images, and other files that don't need processing.
+ * Default: './public'
+ */
+ public?: string;
+ /**
+ * Framework component renderers enable UI framework rendering (static and dynamic).
+ * When you define this in your configuration, all other defaults are disabled.
+ * Default: [
+ * '@astrojs/renderer-svelte',
+ * '@astrojs/renderer-vue',
+ * '@astrojs/renderer-react',
+ * '@astrojs/renderer-preact',
+ * ],
+ */
+ renderers?: string[];
+ /** Options for rendering markdown content */
+ markdownOptions?: Partial;
+ /** Options specific to `astro build` */
+ buildOptions?: {
+ /** Your public domain, e.g.: https://my-site.dev/. Used to generate sitemaps and canonical URLs. */
+ site?: string;
+ /** Generate an automatically-generated sitemap for your build.
+ * Default: true
+ */
+ sitemap?: boolean;
+ /**
+ * Control the output file URL format of each page.
+ * If 'file', Astro will generate a matching HTML file (ex: "/foo.html") instead of a directory.
+ * If 'directory', Astro will generate a directory with a nested index.html (ex: "/foo/index.html") for each page.
+ * Default: 'directory'
+ */
+ pageUrlFormat?: 'file' | 'directory';
+ };
+ /** Options for the development server run with `astro dev`. */
+ devOptions?: {
+ hostname?: string;
+ /** The port to run the dev server on. */
+ port?: number;
+ /** Path to tailwind.config.js, if used */
+ tailwindConfig?: string;
+ /**
+ * Configure The trailing slash behavior of URL route matching:
+ * 'always' - Only match URLs that include a trailing slash (ex: "/foo/")
+ * 'never' - Never match URLs that include a trailing slash (ex: "/foo")
+ * 'ignore' - Match URLs regardless of whether a trailing "/" exists
+ * Default: 'always'
+ */
+ trailingSlash?: 'always' | 'never' | 'ignore';
+ };
+}
+
+// NOTE(fks): We choose to keep our hand-generated AstroUserConfig interface so that
+// we can add JSDoc-style documentation and link to the definition file in our repo.
+// However, Zod comes with the ability to auto-generate AstroConfig from the schema
+// above. If we ever get to the point where we no longer need the dedicated
+// @types/config.ts file, consider replacing it with the following lines:
+//
+// export interface AstroUserConfig extends z.input {
+// markdownOptions?: Partial;
+// }
+export interface AstroConfig extends z.output {
+ markdownOptions: Partial;
+}
+
+export type AsyncRendererComponentFn = (Component: any, props: any, children: string | undefined, metadata?: AstroComponentMetadata) => Promise;
+
+export interface CollectionRSS {
+ /** (required) Title of the RSS Feed */
+ title: string;
+ /** (required) Description of the RSS Feed */
+ description: string;
+ /** Specify arbitrary metadata on opening tag */
+ xmlns?: Record;
+ /** Specify custom data in opening of file */
+ customData?: string;
+ /**
+ * Specify where the RSS xml file should be written.
+ * Relative to final build directory. Example: '/foo/bar.xml'
+ * Defaults to '/rss.xml'.
+ */
+ dest?: string;
+ /** Return data about each item */
+ items: {
+ /** (required) Title of item */
+ title: string;
+ /** (required) Link to item */
+ link: string;
+ /** Publication date of item */
+ pubDate?: Date;
+ /** Item description */
+ description?: string;
+ /** Append some other XML-valid data to this item */
+ customData?: string;
+ }[];
+}
+
+/** Generic interface for a component (Astro, Svelte, React, etc.) */
+export interface ComponentInstance {
+ default: {
+ isAstroComponent: boolean;
+ __render?(props: Props, ...children: any[]): string;
+ __renderer?: Renderer;
+ };
+ __renderPage?: (options: RenderPageOptions) => string;
+ css?: string[];
+ getStaticPaths?: (options: GetStaticPathsOptions) => GetStaticPathsResult;
+}
+
+export type GetStaticPathsArgs = { paginate: PaginateFunction; rss: RSSFunction };
+
+export interface GetStaticPathsOptions {
+ paginate?: PaginateFunction;
+ rss?: (...args: any[]) => any;
+}
+
+export type GetStaticPathsResult = { params: Params; props?: Props }[] | { params: Params; props?: Props }[];
+
+export interface JSXTransformConfig {
+ /** Babel presets */
+ presets?: babel.PluginItem[];
+ /** Babel plugins */
+ plugins?: babel.PluginItem[];
+}
+
+export type JSXTransformFn = (options: { isSSR: boolean }) => Promise;
+
export interface ManifestData {
routes: RouteData[];
}
-export interface JsxItem {
+export interface PaginatedCollectionProp {
+ /** result */
+ data: T[];
+ /** metadata */
+ /** the count of the first item on the page, starting from 0 */
+ start: number;
+ /** the count of the last item on the page, starting from 0 */
+ end: number;
+ /** total number of results */
+ total: number;
+ /** the current page number, starting from 1 */
+ currentPage: number;
+ /** number of items per page (default: 25) */
+ size: number;
+ /** number of last page */
+ lastPage: number;
+ url: {
+ /** url of the current page */
+ current: string;
+ /** url of the previous page (if there is one) */
+ prev: string | undefined;
+ /** url of the next page (if there is one) */
+ next: string | undefined;
+ };
+}
+
+export interface PaginatedCollectionResult {
+ /** result */
+ data: T[];
+ /** metadata */
+ /** the count of the first item on the page, starting from 0 */
+ start: number;
+ /** the count of the last item on the page, starting from 0 */
+ end: number;
+ /** total number of results */
+ total: number;
+ /** the current page number, starting from 1 */
+ currentPage: number;
+ /** number of items per page (default: 25) */
+ size: number;
+ /** number of last page */
+ lastPage: number;
+ url: {
+ /** url of the current page */
+ current: string;
+ /** url of the previous page (if there is one) */
+ prev: string | undefined;
+ /** url of the next page (if there is one) */
+ next: string | undefined;
+ };
+}
+
+export type PaginateFunction = (data: [], args?: { pageSize?: number; params?: Params; props?: Props }) => GetStaticPathsResult;
+
+export type Params = Record;
+
+export type Props = Record;
+
+export interface RenderPageOptions {
+ request: {
+ params?: Params;
+ url: URL;
+ canonicalURL: URL;
+ };
+ children: any[];
+ props: Props;
+ css?: string[];
+}
+
+export interface Renderer {
+ /** Name of the renderer (required) */
name: string;
- jsx: string;
+ hydrationPolyfills?: string[];
+ /** Don’t try and build these dependencies for client */
+ external?: string[];
+ /** Clientside requirements */
+ knownEntrypoints?: string[];
+ polyfills?: string[];
+ /** Import statement for renderer */
+ source?: string;
+ /** JSX identifier (e.g. 'react' or 'solid-js') */
+ jsxImportSource?: string;
+ /** Babel transform options */
+ jsxTransformOptions?: JSXTransformFn;
+ /** Utilies for server-side rendering */
+ ssr: {
+ check: AsyncRendererComponentFn;
+ renderToStaticMarkup: AsyncRendererComponentFn<{
+ html: string;
+ }>;
+ };
+ /** Add plugins to Vite, if any */
+ vitePlugins?: vite.Plugin[];
}
-export interface InlineScriptInfo {
- content: string;
+export interface RouteData {
+ component: string;
+ generate: (data?: any) => string;
+ params: string[];
+ pathname?: string;
+ pattern: RegExp;
+ type: 'page';
}
-export interface ExternalScriptInfo {
- src: string;
-}
-
-export type ScriptInfo = InlineScriptInfo | ExternalScriptInfo;
-
-export interface TransformResult {
- script: string;
- imports: string[];
- exports: string[];
- components: string[];
- html: string;
- css?: string;
- hoistedScripts: ScriptInfo[];
- getStaticPaths?: string;
- hasCustomElements: boolean;
- customElementCandidates: Map;
-}
-
-export interface CompileResult {
- result: TransformResult;
- contents: string;
- css?: string;
-}
+export type RouteCache = Record;
export type RuntimeMode = 'development' | 'production';
-export type Params = Record;
-export type Props = Record;
-
-/** Entire output of `astro build`, stored in memory */
-export interface BuildOutput {
- [dist: string]: BuildFile;
-}
-
-export interface BuildFile {
- /** The original location. Needed for code frame errors. */
- srcPath: URL;
- /** File contents */
- contents: string | Buffer;
- /** File content type (to determine encoding, etc) */
- contentType: string;
- /** Encoding */
- encoding?: 'utf8';
- /** Extracted scripts */
- hoistedScripts?: ScriptInfo[];
-}
-
-/** Mapping of every URL and its required assets. All URLs are absolute relative to the project. */
-export type BundleMap = {
- [pageUrl: string]: PageDependencies;
-};
-
-export interface PageDependencies {
- /** JavaScript files needed for page. No distinction between blocking/non-blocking or sync/async. */
- js: Set;
- /** CSS needed for page, whether imported via , JS, or Astro component. */
- css: Set;
- /** Images needed for page. Can be loaded via CSS, , or otherwise. */
- images: Set;
- /** Async hoisted Javascript */
- hoistedJS: Map;
-}
+export type RSSFunction = (args: RSSFunctionArgs) => void;
export interface RSSFunctionArgs {
/** (required) Title of the RSS Feed */
@@ -118,57 +312,14 @@ export interface RSSFunctionArgs {
}[];
}
-export interface PaginatedCollectionProp {
- /** result */
- data: T[];
- /** metadata */
- /** the count of the first item on the page, starting from 0 */
- start: number;
- /** the count of the last item on the page, starting from 0 */
- end: number;
- /** total number of results */
- total: number;
- /** the current page number, starting from 1 */
- currentPage: number;
- /** number of items per page (default: 25) */
- size: number;
- /** number of last page */
- lastPage: number;
- url: {
- /** url of the current page */
- current: string;
- /** url of the previous page (if there is one) */
- prev: string | undefined;
- /** url of the next page (if there is one) */
- next: string | undefined;
- };
+export type RSSResult = { url: string; xml?: string };
+
+export type ScriptInfo = ScriptInfoInline | ScriptInfoExternal;
+
+export interface ScriptInfoInline {
+ content: string;
}
-export type RSSFunction = (args: RSSFunctionArgs) => void;
-export type PaginateFunction = (data: [], args?: { pageSize?: number; params?: Params; props?: Props }) => GetStaticPathsResult;
-export type GetStaticPathsArgs = { paginate: PaginateFunction; rss: RSSFunction };
-export type GetStaticPathsResult = { params: Params; props?: Props }[] | { params: Params; props?: Props }[];
-
-export interface ComponentInfo {
- url: string;
- importSpecifier: ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier;
-}
-
-export type Components = Map;
-
-export interface AstroComponentMetadata {
- displayName: string;
- hydrate?: 'load' | 'idle' | 'visible' | 'media' | 'only';
- componentUrl?: string;
- componentExport?: { value: string; namespace?: boolean };
- value?: undefined | string;
-}
-
-type AsyncRendererComponentFn = (Component: any, props: any, children: string | undefined, metadata?: AstroComponentMetadata) => Promise;
-
-export interface Renderer {
- check: AsyncRendererComponentFn;
- renderToStaticMarkup: AsyncRendererComponentFn<{
- html: string;
- }>;
+export interface ScriptInfoExternal {
+ src: string;
}
diff --git a/packages/astro/src/@types/compiler.ts b/packages/astro/src/@types/compiler.ts
deleted file mode 100644
index d35dcfd09..000000000
--- a/packages/astro/src/@types/compiler.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import type { LogOptions } from '../logger';
-import type { AstroConfig, RuntimeMode } from './astro';
-
-export interface CompileOptions {
- logging: LogOptions;
- resolvePackageUrl: (p: string) => Promise;
- astroConfig: AstroConfig;
- hmrPort?: number;
- mode: RuntimeMode;
-}
diff --git a/packages/astro/src/@types/estree-walker.d.ts b/packages/astro/src/@types/estree-walker.d.ts
deleted file mode 100644
index a3b7da859..000000000
--- a/packages/astro/src/@types/estree-walker.d.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { BaseNode } from 'estree-walker';
-
-declare module 'estree-walker' {
- export function walk(
- ast: T,
- {
- enter,
- leave,
- }: {
- enter?: (this: { skip: () => void; remove: () => void; replace: (node: T) => void }, node: T, parent: T, key: string, index: number) => void;
- leave?: (this: { skip: () => void; remove: () => void; replace: (node: T) => void }, node: T, parent: T, key: string, index: number) => void;
- }
- ): T;
-
- export function asyncWalk(
- ast: T,
- {
- enter,
- leave,
- }: {
- enter?: (this: { skip: () => void; remove: () => void; replace: (node: T) => void }, node: T, parent: T, key: string, index: number) => void;
- leave?: (this: { skip: () => void; remove: () => void; replace: (node: T) => void }, node: T, parent: T, key: string, index: number) => void;
- }
- ): T;
-}
diff --git a/packages/astro/src/@types/micromark-extension-gfm.d.ts b/packages/astro/src/@types/micromark-extension-gfm.d.ts
deleted file mode 100644
index ebdfe3b3a..000000000
--- a/packages/astro/src/@types/micromark-extension-gfm.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// TODO: add types (if helpful)
-declare module 'micromark-extension-gfm';
-declare module 'micromark-extension-gfm/html.js';
diff --git a/packages/astro/src/@types/micromark.ts b/packages/astro/src/@types/micromark.ts
deleted file mode 100644
index 5060ab468..000000000
--- a/packages/astro/src/@types/micromark.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-export interface MicromarkExtensionContext {
- sliceSerialize(node: any): string;
- raw(value: string): void;
- tag(value: string): void;
- data(value: string): void;
- resume(): any;
-}
-
-export type MicromarkExtensionCallback = (this: MicromarkExtensionContext, node: any) => void;
-
-export interface MicromarkExtension {
- enter?: Record;
- exit?: Record;
-}
diff --git a/packages/astro/src/@types/postcss-icss-keyframes.d.ts b/packages/astro/src/@types/postcss-icss-keyframes.d.ts
deleted file mode 100644
index 14c330b6e..000000000
--- a/packages/astro/src/@types/postcss-icss-keyframes.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-declare module 'postcss-icss-keyframes' {
- import type { Plugin } from 'postcss';
-
- export default function (options: { generateScopedName(keyframesName: string, filepath: string, css: string): string }): Plugin;
-}
diff --git a/packages/astro/src/@types/resolve.d.ts b/packages/astro/src/@types/resolve.d.ts
deleted file mode 100644
index a4cc7d062..000000000
--- a/packages/astro/src/@types/resolve.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-declare module 'resolve';
diff --git a/packages/astro/src/@types/tailwind.d.ts b/packages/astro/src/@types/tailwind.d.ts
deleted file mode 100644
index d25eaae2f..000000000
--- a/packages/astro/src/@types/tailwind.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// we shouldn‘t have this as a dependency for Astro, but we may dynamically import it if a user requests it, so let TS know about it
-declare module 'tailwindcss';
diff --git a/packages/astro/src/@types/transformer.ts b/packages/astro/src/@types/transformer.ts
deleted file mode 100644
index 6bb453c1d..000000000
--- a/packages/astro/src/@types/transformer.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import type { TemplateNode } from '@astrojs/parser';
-import type { CompileOptions } from './compiler';
-
-export type VisitorFn = (this: { skip: () => void; remove: () => void; replace: (node: T) => void }, node: T, parent: T, type: string, index: number) => void;
-
-export interface NodeVisitor {
- enter?: VisitorFn;
- leave?: VisitorFn;
-}
-
-export interface Transformer {
- visitors?: {
- html?: Record;
- css?: Record;
- };
- finalize: () => Promise;
-}
-
-export interface TransformOptions {
- compileOptions: CompileOptions;
- filename: string;
- fileID: string;
-}
diff --git a/packages/astro/src/ast.ts b/packages/astro/src/ast.ts
deleted file mode 100644
index bf73c8508..000000000
--- a/packages/astro/src/ast.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { Attribute } from '@astrojs/parser';
-
-// AST utility functions
-
-/** Get TemplateNode attribute from name */
-export function getAttr(attributes: Attribute[], name: string): Attribute | undefined {
- const attr = attributes.find((a) => a.name === name);
- return attr;
-}
-
-/** Get TemplateNode attribute by value */
-export function getAttrValue(attributes: Attribute[], name: string): string | undefined {
- if (attributes.length === 0) return '';
- const attr = getAttr(attributes, name);
- if (attr) {
- return attr.value[0]?.data;
- }
-}
-
-/** Set TemplateNode attribute value */
-export function setAttrValue(attributes: Attribute[], name: string, value: string): void {
- const attr = attributes.find((a) => a.name === name);
- if (attr && attr.value[0]) {
- attr.value[0].data = value;
- attr.value[0].raw = value;
- }
-}
diff --git a/packages/astro/src/build.ts b/packages/astro/src/build.ts
deleted file mode 100644
index ea3b03b77..000000000
--- a/packages/astro/src/build.ts
+++ /dev/null
@@ -1,365 +0,0 @@
-import cheerio from 'cheerio';
-import del from 'del';
-import eslexer from 'es-module-lexer';
-import fs from 'fs';
-import { bold, green, red, underline, yellow } from 'kleur/colors';
-import mime from 'mime';
-import path from 'path';
-import { performance } from 'perf_hooks';
-import glob from 'tiny-glob';
-import hash from 'shorthash';
-import srcsetParse from 'srcset-parse';
-import { fileURLToPath } from 'url';
-import type { AstroConfig, BuildOutput, BundleMap, PageDependencies, RouteData, RuntimeMode, ScriptInfo } from './@types/astro';
-import { bundleCSS } from './build/bundle/css.js';
-import { bundleJS, bundleHoistedJS, collectJSImports } from './build/bundle/js.js';
-import { buildStaticPage, getStaticPathsForPage } from './build/page.js';
-import { generateSitemap } from './build/sitemap.js';
-import { collectBundleStats, logURLStats, mapBundleStatsToURLStats } from './build/stats.js';
-import { getDistPath, stopTimer } from './build/util.js';
-import type { LogOptions } from './logger';
-import { debug, defaultLogDestination, defaultLogLevel, error, info, warn } from './logger.js';
-import { createRuntime, LoadResult } from './runtime.js';
-
-// This package isn't real ESM, so have to coerce it
-const matchSrcset: typeof srcsetParse = (srcsetParse as any).default;
-
-const defaultLogging: LogOptions = {
- level: defaultLogLevel,
- dest: defaultLogDestination,
-};
-
-/** Is this URL remote or embedded? */
-function isRemoteOrEmbedded(url: string) {
- return url.startsWith('http://') || url.startsWith('https://') || url.startsWith('//') || url.startsWith('data:');
-}
-
-/** The primary build action */
-export async function build(astroConfig: AstroConfig, logging: LogOptions = defaultLogging): Promise<0 | 1> {
- const { projectRoot } = astroConfig;
- const buildState: BuildOutput = {};
- const depTree: BundleMap = {};
- const timer: Record = {};
-
- const runtimeLogging: LogOptions = {
- level: 'error',
- dest: defaultLogDestination,
- };
-
- // warn users if missing config item in build that may result in broken SEO (can’t disable, as they should provide this)
- if (!astroConfig.buildOptions.site) {
- warn(logging, 'config', `Set "buildOptions.site" to generate correct canonical URLs and sitemap`);
- }
-
- const mode: RuntimeMode = 'production';
- const astroRuntime = await createRuntime(astroConfig, { mode, logging: runtimeLogging });
- const { runtimeConfig } = astroRuntime;
- const { snowpackRuntime } = runtimeConfig;
-
- try {
- // 0. erase build directory
- await del(fileURLToPath(astroConfig.dist));
-
- /**
- * 1. Build Pages
- * Source files are built in parallel and stored in memory. Most assets are also gathered here, too.
- */
- timer.build = performance.now();
- info(logging, 'build', yellow('! building pages...'));
- const allRoutesAndPaths = await Promise.all(
- runtimeConfig.manifest.routes.map(async (route): Promise<[RouteData, string[]]> => {
- if (route.path) {
- return [route, [route.path]];
- } else {
- const result = await getStaticPathsForPage({
- astroConfig,
- astroRuntime,
- route,
- snowpackRuntime,
- logging,
- });
- if (result.rss.xml) {
- if (buildState[result.rss.url]) {
- throw new Error(`[getStaticPaths] RSS feed ${result.rss.url} already exists.\nUse \`rss(data, {url: '...'})\` to choose a unique, custom URL. (${route.component})`);
- }
- buildState[result.rss.url] = {
- srcPath: new URL(result.rss.url, projectRoot),
- contents: result.rss.xml,
- contentType: 'text/xml',
- encoding: 'utf8',
- };
- }
- return [route, result.paths];
- }
- })
- );
- try {
- await Promise.all(
- allRoutesAndPaths.map(async ([route, paths]: [RouteData, string[]]) => {
- for (const p of paths) {
- await buildStaticPage({
- astroConfig,
- buildState,
- route,
- path: p,
- astroRuntime,
- });
- }
- })
- );
- } catch (e) {
- if (e.filename) {
- let stack = e.stack
- .replace(/Object\.__render \(/gm, '')
- .replace(/\/_astro\/(.+)\.astro\.js\:\d+\:\d+\)/gm, (_: string, $1: string) => 'file://' + fileURLToPath(projectRoot) + $1 + '.astro')
- .split('\n');
- stack.splice(1, 0, ` at file://${e.filename}`);
- stack = stack.join('\n');
- error(
- logging,
- 'build',
- `${red(`Unable to render ${underline(e.filename.replace(fileURLToPath(projectRoot), ''))}`)}
-
-${stack}
-`
- );
- } else {
- error(logging, 'build', e.message);
- }
- error(logging, 'build', red('✕ building pages failed!'));
-
- await astroRuntime.shutdown();
- return 1;
- }
- info(logging, 'build', green('✔'), 'pages built.');
- debug(logging, 'build', `built pages [${stopTimer(timer.build)}]`);
-
- // after pages are built, build depTree
- timer.deps = performance.now();
- const scanPromises: Promise[] = [];
-
- await eslexer.init;
- for (const id of Object.keys(buildState)) {
- if (buildState[id].contentType !== 'text/html') continue; // only scan HTML files
- const pageDeps = findDeps(buildState[id].contents as string, {
- astroConfig,
- srcPath: buildState[id].srcPath,
- id,
- });
- depTree[id] = pageDeps;
-
- // while scanning we will find some unbuilt files; make sure those are all built while scanning
- for (const url of [...pageDeps.js, ...pageDeps.css, ...pageDeps.images]) {
- if (!buildState[url])
- scanPromises.push(
- astroRuntime.load(url).then((result: LoadResult) => {
- if (result.statusCode === 404) {
- if (url.startsWith('/_astro/')) {
- throw new Error(`${buildState[id].srcPath.href}: could not find file "${url}".`);
- }
- warn(logging, 'build', `${buildState[id].srcPath.href}: could not find file "${url}". Marked as external.`);
- return;
- }
- if (result.statusCode !== 200) {
- // there shouldn’t be a build error here
- throw (result as any).error || new Error(`unexpected ${result.statusCode} response from "${url}".`);
- }
- buildState[url] = {
- srcPath: new URL(url, projectRoot),
- contents: result.contents,
- contentType: result.contentType || mime.getType(url) || '',
- };
- })
- );
- }
- }
- await Promise.all(scanPromises);
- debug(logging, 'build', `scanned deps [${stopTimer(timer.deps)}]`);
-
- /**
- * 2. Bundling 1st Pass: In-memory
- * Bundle CSS, and anything else that can happen in memory (for now, JS bundling happens after writing to disk)
- */
- info(logging, 'build', yellow('! optimizing css...'));
- timer.prebundleCSS = performance.now();
- await Promise.all([
- bundleCSS({ buildState, astroConfig, logging, depTree }).then(() => {
- debug(logging, 'build', `bundled CSS [${stopTimer(timer.prebundleCSS)}]`);
- }),
- bundleHoistedJS({ buildState, astroConfig, logging, depTree, runtime: astroRuntime, dist: astroConfig.dist }),
- // TODO: optimize images?
- ]);
- // TODO: minify HTML?
- info(logging, 'build', green('✔'), 'css optimized.');
-
- /**
- * 3. Write to disk
- * Also clear in-memory bundle
- */
- // collect stats output
- const urlStats = await collectBundleStats(buildState, depTree);
-
- // collect JS imports for bundling
- const jsImports = await collectJSImports(buildState);
-
- // write sitemap
- if (astroConfig.buildOptions.sitemap && astroConfig.buildOptions.site) {
- timer.sitemap = performance.now();
- info(logging, 'build', yellow('! creating sitemap...'));
- const sitemap = generateSitemap(buildState, astroConfig.buildOptions.site);
- const sitemapPath = new URL('sitemap.xml', astroConfig.dist);
- await fs.promises.mkdir(path.dirname(fileURLToPath(sitemapPath)), { recursive: true });
- await fs.promises.writeFile(sitemapPath, sitemap, 'utf8');
- info(logging, 'build', green('✔'), 'sitemap built.');
- debug(logging, 'build', `built sitemap [${stopTimer(timer.sitemap)}]`);
- }
-
- // write to disk and free up memory
- timer.write = performance.now();
- for (const id of Object.keys(buildState)) {
- const outPath = new URL(`.${id}`, astroConfig.dist);
- const parentDir = path.dirname(fileURLToPath(outPath));
- await fs.promises.mkdir(parentDir, { recursive: true });
- const handle = await fs.promises.open(outPath, 'w');
- await fs.promises.writeFile(handle, buildState[id].contents, buildState[id].encoding);
-
- // Ensure the file handle is not left hanging which will
- // result in the garbage collector loggin errors in the console
- // when it eventually has to close them.
- await handle.close();
-
- delete buildState[id];
- delete depTree[id];
- }
- debug(logging, 'build', `wrote files to disk [${stopTimer(timer.write)}]`);
-
- /**
- * 4. Copy Public Assets
- */
- if (fs.existsSync(astroConfig.public)) {
- info(logging, 'build', yellow(`! copying public folder...`));
- timer.public = performance.now();
- const cwd = fileURLToPath(astroConfig.public);
- const publicFiles = await glob('**/*', { cwd, filesOnly: true });
- await Promise.all(
- publicFiles.map(async (filepath) => {
- const srcPath = new URL(filepath, astroConfig.public);
- const distPath = new URL(filepath, astroConfig.dist);
- await fs.promises.mkdir(path.dirname(fileURLToPath(distPath)), { recursive: true });
- await fs.promises.copyFile(srcPath, distPath);
- })
- );
- debug(logging, 'build', `copied public folder [${stopTimer(timer.public)}]`);
- info(logging, 'build', green('✔'), 'public folder copied.');
- } else {
- if (path.basename(astroConfig.public.toString()) !== 'public') {
- info(logging, 'tip', yellow(`! no public folder ${astroConfig.public} found...`));
- }
- }
-
- /**
- * 5. Bundling 2nd Pass: On disk
- * Bundle JS, which requires hard files to optimize
- */
- info(logging, 'build', yellow(`! bundling...`));
- if (jsImports.size > 0) {
- timer.bundleJS = performance.now();
- const jsStats = await bundleJS(jsImports, { dist: astroConfig.dist, astroRuntime });
- mapBundleStatsToURLStats({ urlStats, depTree, bundleStats: jsStats });
- debug(logging, 'build', `bundled JS [${stopTimer(timer.bundleJS)}]`);
- info(logging, 'build', green(`✔`), 'bundling complete.');
- }
-
- /**
- * 6. Print stats
- */
- logURLStats(logging, urlStats);
- await astroRuntime.shutdown();
- info(logging, 'build', bold(green('▶ Build Complete!')));
- return 0;
- } catch (err) {
- error(logging, 'build', err.message);
- await astroRuntime.shutdown();
- return 1;
- }
-}
-
-/** Given an HTML string, collect and tags */
-export function findDeps(html: string, { astroConfig, srcPath }: { astroConfig: AstroConfig; srcPath: URL; id: string }): PageDependencies {
- const pageDeps: PageDependencies = {
- js: new Set(),
- css: new Set(),
- images: new Set(),
- hoistedJS: new Map(),
- };
-
- const $ = cheerio.load(html);
-
- $('script').each((_i, el) => {
- const src = $(el).attr('src');
- const hoist = $(el).attr('data-astro') === 'hoist';
- if (hoist) {
- if (src) {
- pageDeps.hoistedJS.set(src, {
- src,
- });
- } else {
- let content = $(el).html() || '';
- pageDeps.hoistedJS.set(`astro-virtual:${hash.unique(content)}`, {
- content,
- });
- }
- } else if (src) {
- if (isRemoteOrEmbedded(src)) return;
- pageDeps.js.add(getDistPath(src, { astroConfig, srcPath }));
- } else {
- const text = $(el).html();
- if (!text) return;
- const [imports] = eslexer.parse(text);
- for (const spec of imports) {
- const importSrc = spec.n;
- if (importSrc && !isRemoteOrEmbedded(importSrc)) {
- pageDeps.js.add(getDistPath(importSrc, { astroConfig, srcPath }));
- }
- }
- }
- });
-
- $('link[href]').each((_i, el) => {
- const href = $(el).attr('href');
- if (href && !isRemoteOrEmbedded(href) && ($(el).attr('rel') === 'stylesheet' || $(el).attr('type') === 'text/css' || href.endsWith('.css'))) {
- const dist = getDistPath(href, { astroConfig, srcPath });
- pageDeps.css.add(dist);
- }
- });
-
- $('img[src]').each((_i, el) => {
- const src = $(el).attr('src');
- if (src && !isRemoteOrEmbedded(src)) {
- pageDeps.images.add(getDistPath(src, { astroConfig, srcPath }));
- }
- });
-
- $('img[srcset]').each((_i, el) => {
- const srcset = $(el).attr('srcset') || '';
- for (const src of matchSrcset(srcset)) {
- if (!isRemoteOrEmbedded(src.url)) {
- pageDeps.images.add(getDistPath(src.url, { astroConfig, srcPath }));
- }
- }
- });
-
- // Add in srcset check for