Extract Astro styles to external stylesheets (#43)
* Extract Astro styles to external stylesheets * Require relative URLs in Markdown layouts
This commit is contained in:
parent
a3b20a9aff
commit
3fa6396a7b
54 changed files with 201 additions and 164 deletions
|
@ -3,12 +3,15 @@ module.exports = {
|
||||||
extends: ['plugin:@typescript-eslint/recommended', 'prettier'],
|
extends: ['plugin:@typescript-eslint/recommended', 'prettier'],
|
||||||
plugins: ['@typescript-eslint', 'prettier'],
|
plugins: ['@typescript-eslint', 'prettier'],
|
||||||
rules: {
|
rules: {
|
||||||
|
'@typescript-eslint/ban-ts-comment': 'warn',
|
||||||
'@typescript-eslint/camelcase': 'off',
|
'@typescript-eslint/camelcase': 'off',
|
||||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
'@typescript-eslint/no-use-before-define': 'off',
|
'@typescript-eslint/no-use-before-define': 'off',
|
||||||
'@typescript-eslint/no-var-requires': 'off',
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
|
'no-shadow': 'warn',
|
||||||
'prettier/prettier': 'error',
|
'prettier/prettier': 'error',
|
||||||
'prefer-const': 'off',
|
'prefer-const': 'off',
|
||||||
'prefer-rest-params': 'off',
|
'prefer-rest-params': 'off',
|
||||||
|
'require-jsdoc': 'warn',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
7
.github/workflows/nodejs.yml
vendored
7
.github/workflows/nodejs.yml
vendored
|
@ -27,3 +27,10 @@ jobs:
|
||||||
npm test
|
npm test
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- uses: actions/setup-node@v1
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run lint
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: The Build Pipeline
|
title: The Build Pipeline
|
||||||
description: Snowpack Build creates a production-ready website with or without a bundler
|
description: Snowpack Build creates a production-ready website with or without a bundler
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: The Dev Server
|
title: The Dev Server
|
||||||
description: Snowpack's dev server is fast because it only rebuilds the files you change. Powered by ESM (ES modules).
|
description: Snowpack's dev server is fast because it only rebuilds the files you change. Powered by ESM (ES modules).
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: HMR + Fast Refresh
|
title: HMR + Fast Refresh
|
||||||
description: Snowpack's ESM-powered unbundled development means near-instant single file builds that only take 10-25ms to load and update in the browser.
|
description: Snowpack's ESM-powered unbundled development means near-instant single file builds that only take 10-25ms to load and update in the browser.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: How Snowpack Works
|
title: How Snowpack Works
|
||||||
description: Snowpack serves your application unbundled during development. Each file is built only once and is cached until it changes.
|
description: Snowpack serves your application unbundled during development. Each file is built only once and is cached until it changes.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'Babel'
|
title: 'Babel'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: The Snowpack Guide to connecting your favorite tools
|
title: The Snowpack Guide to connecting your favorite tools
|
||||||
description: 'How do you use your favorite tools in Snowpack? This Guide will help you get started'
|
description: 'How do you use your favorite tools in Snowpack? This Guide will help you get started'
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Hot Module Replacement (HMR)
|
title: Hot Module Replacement (HMR)
|
||||||
description: Enable Snowpack's Hot Module Replacement (HMR) on your development server.
|
description: Enable Snowpack's Hot Module Replacement (HMR) on your development server.
|
||||||
published: false
|
published: false
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: SSL Certificates
|
title: SSL Certificates
|
||||||
description: How to use HTTPs during development and generate SSL certifcates for your Snowpack build.
|
description: How to use HTTPs during development and generate SSL certifcates for your Snowpack build.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'Jest'
|
title: 'Jest'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
img: '/img/logos/jest.svg'
|
img: '/img/logos/jest.svg'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Optimize & Bundle for Production
|
title: Optimize & Bundle for Production
|
||||||
published: true
|
published: true
|
||||||
description: How to optimize your Snowpack build for production, with or without a bundler.
|
description: How to optimize your Snowpack build for production, with or without a bundler.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Creating Your Own Plugin
|
title: Creating Your Own Plugin
|
||||||
description: Learn the basics of our Plugin API through working examples.
|
description: Learn the basics of our Plugin API through working examples.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'PostCSS'
|
title: 'PostCSS'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Preact
|
title: Preact
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
img: '/img/logos/preact.svg'
|
img: '/img/logos/preact.svg'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: React + babel-plugin-import-global
|
title: React + babel-plugin-import-global
|
||||||
published: false
|
published: false
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: React + Loadable Components
|
title: React + Loadable Components
|
||||||
published: false
|
published: false
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Routing
|
title: Routing
|
||||||
published: true
|
published: true
|
||||||
description: This guide will walk you through some common routing scenarios and how to configure the routes option to support them in development.
|
description: This guide will walk you through some common routing scenarios and how to configure the routes option to support them in development.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'Sass'
|
title: 'Sass'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Server-Side Rendering (SSR)
|
title: Server-Side Rendering (SSR)
|
||||||
description: This guide will walk you through three different options for setting up Snowpack with your own custom server.
|
description: This guide will walk you through three different options for setting up Snowpack with your own custom server.
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Streaming Imports
|
title: Streaming Imports
|
||||||
published: true
|
published: true
|
||||||
stream: Fetch your npm dependencies on-demand from a remote ESM CDN.
|
stream: Fetch your npm dependencies on-demand from a remote ESM CDN.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'Tailwind CSS'
|
title: 'Tailwind CSS'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Testing
|
title: Testing
|
||||||
published: true
|
published: true
|
||||||
description: How to choose and use a JavaScript test runner for your Snowpack site.
|
description: How to choose and use a JavaScript test runner for your Snowpack site.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Snowpack Upgrade Guide
|
title: Snowpack Upgrade Guide
|
||||||
published: true
|
published: true
|
||||||
description: How to upgrade to Snowpack v3 from older versions of Snowpack.
|
description: How to upgrade to Snowpack v3 from older versions of Snowpack.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Vue
|
title: Vue
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
img: '/img/logos/vue.png'
|
img: '/img/logos/vue.png'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'WASM'
|
title: 'WASM'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: '@web/test-runner'
|
title: '@web/test-runner'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
img: '/img/logos/modern-web.svg'
|
img: '/img/logos/modern-web.svg'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'Web Workers'
|
title: 'Web Workers'
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
published: true
|
published: true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Workbox
|
title: Workbox
|
||||||
tags: communityGuide
|
tags: communityGuide
|
||||||
description: The Workbox CLI integrates well with Snowpack.
|
description: The Workbox CLI integrates well with Snowpack.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/post.astro
|
layout: ../../layouts/post.astro
|
||||||
bannerVideo: '/img/extra-space-4.mp4'
|
bannerVideo: '/img/extra-space-4.mp4'
|
||||||
permalink: '/posts/2020-05-26-snowpack-2-0-release/'
|
permalink: '/posts/2020-05-26-snowpack-2-0-release/'
|
||||||
title: Snowpack v2.0
|
title: Snowpack v2.0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/post.astro
|
layout: ../../layouts/post.astro
|
||||||
title: Snowpack 2.7
|
title: Snowpack 2.7
|
||||||
description: 'A new plugin API plus smaller, faster production builds.'
|
description: 'A new plugin API plus smaller, faster production builds.'
|
||||||
tagline: v2.7.0 release post
|
tagline: v2.7.0 release post
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/post.astro
|
layout: ../../layouts/post.astro
|
||||||
title: 'Snowpack v3.0 Release Candidate'
|
title: 'Snowpack v3.0 Release Candidate'
|
||||||
tagline: New features to change the way you build for the web.
|
tagline: New features to change the way you build for the web.
|
||||||
description: 'New features to change the way you build for the web. Snowpack v3.0 will release on January 6th, 2021 (the one-year anniversary of its original launch post). This is our biggest release yet with some serious new features, including a new way to load npm packages on-demand that lets you skip the `npm install` step entirely.'
|
description: 'New features to change the way you build for the web. Snowpack v3.0 will release on January 6th, 2021 (the one-year anniversary of its original launch post). This is our biggest release yet with some serious new features, including a new way to load npm packages on-demand that lets you skip the `npm install` step entirely.'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/post.astro
|
layout: ../../layouts/post.astro
|
||||||
title: 'Snowpack v3.0'
|
title: 'Snowpack v3.0'
|
||||||
description: Snowpack v3.0 is here! Our biggest release yet with some serious new features, including pre-bundled streaming imports, built-in bundling & optimizations, new JavaScript APIs, and more.'
|
description: Snowpack v3.0 is here! Our biggest release yet with some serious new features, including pre-bundled streaming imports, built-in bundling & optimizations, new JavaScript APIs, and more.'
|
||||||
date: 2021-01-13
|
date: 2021-01-13
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Command Line API
|
title: Command Line API
|
||||||
description: The Snowpack Command Line tool's API, commands, and flags.
|
description: The Snowpack Command Line tool's API, commands, and flags.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Common Error Details
|
title: Common Error Details
|
||||||
description: How to troubleshoot common issues and error messagesm, plus our resources for getting help.
|
description: How to troubleshoot common issues and error messagesm, plus our resources for getting help.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: snowpack.config.js
|
title: snowpack.config.js
|
||||||
description: The Snowpack configuration API reference.
|
description: The Snowpack configuration API reference.
|
||||||
---
|
---
|
||||||
|
@ -20,7 +20,7 @@ To generate a basic configuration file scaffold in your Snowpack project run `sn
|
||||||
|
|
||||||
## root
|
## root
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `/`
|
**Default**: `/`
|
||||||
|
|
||||||
Specify the root of a project using Snowpack. (Previously: `config.cwd`)
|
Specify the root of a project using Snowpack. (Previously: `config.cwd`)
|
||||||
|
@ -47,7 +47,7 @@ Can be a relative file path, an npm package, or a file within an npm package. Yo
|
||||||
|
|
||||||
## exclude
|
## exclude
|
||||||
|
|
||||||
**Type**: `string[]`
|
**Type**: `string[]`
|
||||||
**Default**: `['**/node_modules/**/*']`
|
**Default**: `['**/node_modules/**/*']`
|
||||||
|
|
||||||
Exclude any files from the Snowpack pipeline.
|
Exclude any files from the Snowpack pipeline.
|
||||||
|
@ -151,28 +151,28 @@ Configure the Snowpack dev server.
|
||||||
|
|
||||||
### devOptions.secure
|
### devOptions.secure
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `false`
|
**Default**: `false`
|
||||||
|
|
||||||
Toggles whether Snowpack dev server should use HTTPS with HTTP2 enabled.
|
Toggles whether Snowpack dev server should use HTTPS with HTTP2 enabled.
|
||||||
|
|
||||||
### devOptions.hostname
|
### devOptions.hostname
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `localhost`
|
**Default**: `localhost`
|
||||||
|
|
||||||
The hostname that the dev server is running on. Snowpack uses this information to configure the HMR websocket and properly open your browser on startup (see: [`devOptions.open`](#devoptions.open)).
|
The hostname that the dev server is running on. Snowpack uses this information to configure the HMR websocket and properly open your browser on startup (see: [`devOptions.open`](#devoptions.open)).
|
||||||
|
|
||||||
### devOptions.port
|
### devOptions.port
|
||||||
|
|
||||||
**Type**: `number`
|
**Type**: `number`
|
||||||
**Default**: `8080`
|
**Default**: `8080`
|
||||||
|
|
||||||
The port the dev server runs on.
|
The port the dev server runs on.
|
||||||
|
|
||||||
### devOptions.fallback
|
### devOptions.fallback
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `"index.html"`
|
**Default**: `"index.html"`
|
||||||
|
|
||||||
The HTML file to serve for non-resource routes.
|
The HTML file to serve for non-resource routes.
|
||||||
|
@ -183,7 +183,7 @@ When using the Single-Page Application (SPA) pattern, this is the HTML "shell" f
|
||||||
|
|
||||||
### devOptions.open
|
### devOptions.open
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `"**Default**"`
|
**Default**: `"**Default**"`
|
||||||
|
|
||||||
Configures how the dev server opens in the browser when it starts.
|
Configures how the dev server opens in the browser when it starts.
|
||||||
|
@ -192,7 +192,7 @@ Any installed browser, e.g., "chrome", "firefox", "brave". Set "none" to disable
|
||||||
|
|
||||||
### devOptions.output
|
### devOptions.output
|
||||||
|
|
||||||
**Type**: `"stream" | "dashboard"`
|
**Type**: `"stream" | "dashboard"`
|
||||||
**Default**: `"dashboard"`
|
**Default**: `"dashboard"`
|
||||||
|
|
||||||
Set the output mode of the `dev` console:
|
Set the output mode of the `dev` console:
|
||||||
|
@ -202,35 +202,35 @@ Set the output mode of the `dev` console:
|
||||||
|
|
||||||
### devOptions.hmr
|
### devOptions.hmr
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `true`
|
**Default**: `true`
|
||||||
|
|
||||||
Toggles HMR on the Snowpack dev server.
|
Toggles HMR on the Snowpack dev server.
|
||||||
|
|
||||||
### devOptions.hmrDelay
|
### devOptions.hmrDelay
|
||||||
|
|
||||||
**Type**: `number` (milliseconds)
|
**Type**: `number` (milliseconds)
|
||||||
**Default**: `0`
|
**Default**: `0`
|
||||||
|
|
||||||
Milliseconds to delay HMR-triggered browser update.
|
Milliseconds to delay HMR-triggered browser update.
|
||||||
|
|
||||||
### devOptions.hmrPort
|
### devOptions.hmrPort
|
||||||
|
|
||||||
**Type**: `number`
|
**Type**: `number`
|
||||||
**Default**: [`devOptions.port`](#devoptions.port)
|
**Default**: [`devOptions.port`](#devoptions.port)
|
||||||
|
|
||||||
The port where Snowpack's HMR Websocket runs.
|
The port where Snowpack's HMR Websocket runs.
|
||||||
|
|
||||||
### devOptions.hmrErrorOverlay
|
### devOptions.hmrErrorOverlay
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `true`
|
**Default**: `true`
|
||||||
|
|
||||||
Toggles a browser overlay that displays JavaScript runtime errors when running HMR.
|
Toggles a browser overlay that displays JavaScript runtime errors when running HMR.
|
||||||
|
|
||||||
### devOptions.out
|
### devOptions.out
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `"build"`
|
**Default**: `"build"`
|
||||||
|
|
||||||
_NOTE:_ Deprecated, see `buildOptions.out`.
|
_NOTE:_ Deprecated, see `buildOptions.out`.
|
||||||
|
@ -249,7 +249,7 @@ Configure how npm packages are installed and used.
|
||||||
|
|
||||||
### packageOptions.external
|
### packageOptions.external
|
||||||
|
|
||||||
**Type**: `string[]`
|
**Type**: `string[]`
|
||||||
**Example**: `"external": ["fs"]`
|
**Example**: `"external": ["fs"]`
|
||||||
|
|
||||||
Mark some imports as external. Snowpack will ignore these imports and leave them as-is in your final build.
|
Mark some imports as external. Snowpack will ignore these imports and leave them as-is in your final build.
|
||||||
|
@ -258,7 +258,7 @@ This is an advanced feature: Bare imports are not supported in any major browser
|
||||||
|
|
||||||
### packageOptions.source
|
### packageOptions.source
|
||||||
|
|
||||||
**Type**: `"local" | "remote"`
|
**Type**: `"local" | "remote"`
|
||||||
**Default**: `"local"`
|
**Default**: `"local"`
|
||||||
**Example**: `"source": "local"`
|
**Example**: `"source": "local"`
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ Known dependencies to install with Snowpack. Used for installing packages any de
|
||||||
|
|
||||||
#### packageOptions.polyfillNode
|
#### packageOptions.polyfillNode
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `false`
|
**Default**: `false`
|
||||||
|
|
||||||
This will automatically polyfill any Node.js dependencies as much as possible for the browser
|
This will automatically polyfill any Node.js dependencies as much as possible for the browser
|
||||||
|
@ -313,7 +313,7 @@ This option is only supported in `source="local"` mode. `source="remote"` does n
|
||||||
|
|
||||||
#### packageOptions.packageLookupFields
|
#### packageOptions.packageLookupFields
|
||||||
|
|
||||||
**Type**: `string[]`
|
**Type**: `string[]`
|
||||||
**Example**: `"packageLookupFields": ["svelte"]`
|
**Example**: `"packageLookupFields": ["svelte"]`
|
||||||
|
|
||||||
Set custom lookup fields for dependency `package.json` file entrypoints, in addition to the defaults like "module", "main", etc.
|
Set custom lookup fields for dependency `package.json` file entrypoints, in addition to the defaults like "module", "main", etc.
|
||||||
|
@ -322,7 +322,7 @@ This option is only supported in `source="local"` mode. `source="remote"` does n
|
||||||
|
|
||||||
#### packageOptions.packageExportLookupFields
|
#### packageOptions.packageExportLookupFields
|
||||||
|
|
||||||
**Type**: `string[]`
|
**Type**: `string[]`
|
||||||
**Example**: `"packageExportLookupFields": ["svelte"]`
|
**Example**: `"packageExportLookupFields": ["svelte"]`
|
||||||
|
|
||||||
Set custom lookup fields for dependency `package.json` ["exports" mappings.](https://nodejs.org/api/packages.html#packages_package_entry_points)
|
Set custom lookup fields for dependency `package.json` ["exports" mappings.](https://nodejs.org/api/packages.html#packages_package_entry_points)
|
||||||
|
@ -351,7 +351,7 @@ Enable streaming package imports. Load dependencies from our remote CDN. Manage
|
||||||
|
|
||||||
#### packageOptions.origin
|
#### packageOptions.origin
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `https://pkg.snowpack.dev`
|
**Default**: `https://pkg.snowpack.dev`
|
||||||
|
|
||||||
The remote origin to import packages from. When you import a new package, Snowpack will fetch those resources from this URL.
|
The remote origin to import packages from. When you import a new package, Snowpack will fetch those resources from this URL.
|
||||||
|
@ -360,14 +360,14 @@ Currently, the origin must implement a specific response format that Snowpack ca
|
||||||
|
|
||||||
#### packageOptions.cache
|
#### packageOptions.cache
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `.snowpack`
|
**Default**: `.snowpack`
|
||||||
|
|
||||||
The location of your project cache folder, relative to the project root. Snowpack will save cached data to this folder. For example, if `packageOptions.types` is set to true, Snowpack will save TypeScript types to a `types` directory within this folder.
|
The location of your project cache folder, relative to the project root. Snowpack will save cached data to this folder. For example, if `packageOptions.types` is set to true, Snowpack will save TypeScript types to a `types` directory within this folder.
|
||||||
|
|
||||||
#### packageOptions.types
|
#### packageOptions.types
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `false`
|
**Default**: `false`
|
||||||
|
|
||||||
If true, Snowpack will download TypeScript types for every package.
|
If true, Snowpack will download TypeScript types for every package.
|
||||||
|
@ -387,7 +387,7 @@ The local directory that we output your final build to.
|
||||||
|
|
||||||
### buildOptions.baseUrl
|
### buildOptions.baseUrl
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `/`
|
**Default**: `/`
|
||||||
|
|
||||||
In your HTML, replace all instances of `%PUBLIC_URL%` with this
|
In your HTML, replace all instances of `%PUBLIC_URL%` with this
|
||||||
|
@ -396,7 +396,7 @@ Inspired by the same [Create React App](https://create-react-app.dev/docs/using-
|
||||||
|
|
||||||
### buildOptions.clean
|
### buildOptions.clean
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `true`
|
**Default**: `true`
|
||||||
|
|
||||||
Set to `false` to prevent Snowpack from deleting the build output folder (`buildOptions.out`) between builds.
|
Set to `false` to prevent Snowpack from deleting the build output folder (`buildOptions.out`) between builds.
|
||||||
|
@ -411,7 +411,7 @@ _NOTE:_ Deprecated, see `buildOptions.metaUrlPath`.
|
||||||
|
|
||||||
### buildOptions.metaUrlPath
|
### buildOptions.metaUrlPath
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `_snowpack`
|
**Default**: `_snowpack`
|
||||||
|
|
||||||
Rename the default directory for Snowpack metadata. In every build, Snowpack creates meta files for loading things like [HMR](/concepts/hot-module-replacement), [Environment Variables](/reference/environment-variables), and your built npm packages.
|
Rename the default directory for Snowpack metadata. In every build, Snowpack creates meta files for loading things like [HMR](/concepts/hot-module-replacement), [Environment Variables](/reference/environment-variables), and your built npm packages.
|
||||||
|
@ -420,7 +420,7 @@ When you build your project, this will be a path on disk relative to the `buildO
|
||||||
|
|
||||||
### buildOptions.sourcemap
|
### buildOptions.sourcemap
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `false`
|
**Default**: `false`
|
||||||
|
|
||||||
Generates source maps.
|
Generates source maps.
|
||||||
|
@ -429,14 +429,14 @@ Generates source maps.
|
||||||
|
|
||||||
### buildOptions.watch
|
### buildOptions.watch
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `false`
|
**Default**: `false`
|
||||||
|
|
||||||
Run Snowpack's build pipeline through a file watcher. This option works best for local development when you have a custom frontend server (ex: Rails, PHP, etc.) and the Snowpack dev server cannot be used.
|
Run Snowpack's build pipeline through a file watcher. This option works best for local development when you have a custom frontend server (ex: Rails, PHP, etc.) and the Snowpack dev server cannot be used.
|
||||||
|
|
||||||
### buildOptions.htmlFragments
|
### buildOptions.htmlFragments
|
||||||
|
|
||||||
**Type**: `boolean`
|
**Type**: `boolean`
|
||||||
**Default**: `false`
|
**Default**: `false`
|
||||||
|
|
||||||
Toggles whether HTML fragments are transformed like full HTML pages.
|
Toggles whether HTML fragments are transformed like full HTML pages.
|
||||||
|
@ -445,14 +445,14 @@ HTML fragments are HTML files not starting with "<!doctype html>".
|
||||||
|
|
||||||
### buildOptions.jsxFactory
|
### buildOptions.jsxFactory
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `React.createElement` (or `h` if Preact import is detected)
|
**Default**: `React.createElement` (or `h` if Preact import is detected)
|
||||||
|
|
||||||
Set the name of the function used to create JSX elements.
|
Set the name of the function used to create JSX elements.
|
||||||
|
|
||||||
### buildOptions.jsxFragment
|
### buildOptions.jsxFragment
|
||||||
|
|
||||||
**Type**: `string`
|
**Type**: `string`
|
||||||
**Default**: `React.Fragment` (or `Fragment` if Preact import is detected)
|
**Default**: `React.Fragment` (or `Fragment` if Preact import is detected)
|
||||||
|
|
||||||
Set the name of the function used to create JSX fragments.
|
Set the name of the function used to create JSX fragments.
|
||||||
|
@ -463,7 +463,7 @@ Configure your tests.
|
||||||
|
|
||||||
### testOptions.files
|
### testOptions.files
|
||||||
|
|
||||||
**Type**: `string[]`
|
**Type**: `string[]`
|
||||||
**Default**: `["__tests__/**/*", "**/*.@(spec|test).*"]`
|
**Default**: `["__tests__/**/*", "**/*.@(spec|test).*"]`
|
||||||
|
|
||||||
Specifies your test files. If `NODE_ENV` is set to "test", Snowpack includes these files in your site build and scan them for installable dependencies. Otherwise, Snowpack excludes these files.
|
Specifies your test files. If `NODE_ENV` is set to "test", Snowpack includes these files in your site build and scan them for installable dependencies. Otherwise, Snowpack excludes these files.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Environment Variables
|
title: Environment Variables
|
||||||
description: Using environment variables with Snowpack
|
description: Using environment variables with Snowpack
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Hot Module Replacement (HMR) API
|
title: Hot Module Replacement (HMR) API
|
||||||
description: Snowpack implements HMR via the esm-hmr spec, an attempted standard for ESM-based Hot Module Replacement (HMR).
|
description: Snowpack implements HMR via the esm-hmr spec, an attempted standard for ESM-based Hot Module Replacement (HMR).
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: JavaScript API
|
title: JavaScript API
|
||||||
description: Snowpack's JavaScript API is for anyone who wants to integrate with some custom build pipeline or server-side rendering engine.
|
description: Snowpack's JavaScript API is for anyone who wants to integrate with some custom build pipeline or server-side rendering engine.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Plugin API
|
title: Plugin API
|
||||||
description: The Snowpack Plugin API and how to use it.
|
description: The Snowpack Plugin API and how to use it.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Supported Files
|
title: Supported Files
|
||||||
description: Snowpack ships with built-in support for many file types including json, js, ts, jsx, css, css modules, and images.
|
description: Snowpack ships with built-in support for many file types including json, js, ts, jsx, css, css modules, and images.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: 'Starting a New Project'
|
title: 'Starting a New Project'
|
||||||
description: This guide shows you how to set up Snowpack from scratch in a Node.js project. Along the way learn key concepts of Snowpack and unbundled development.
|
description: This guide shows you how to set up Snowpack from scratch in a Node.js project. Along the way learn key concepts of Snowpack and unbundled development.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../../layouts/content.astro
|
||||||
title: Quick Start
|
title: Quick Start
|
||||||
description: A very basic guide for developers who want to run Snowpack as quickly as possible.
|
description: A very basic guide for developers who want to run Snowpack as quickly as possible.
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content-with-cover.astro
|
layout: ../../layouts/content-with-cover.astro
|
||||||
title: 'Getting Started with React'
|
title: 'Getting Started with React'
|
||||||
description: 'Get started with this in-depth tutorial on how to build React applications and websites with Snowpack and developer tools like React Fast Refresh'
|
description: 'Get started with this in-depth tutorial on how to build React applications and websites with Snowpack and developer tools like React Fast Refresh'
|
||||||
date: 2020-12-01
|
date: 2020-12-01
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content-with-cover.astro
|
layout: ../../layouts/content-with-cover.astro
|
||||||
title: 'Getting Started with Svelte'
|
title: 'Getting Started with Svelte'
|
||||||
description: 'Get started with this in-depth tutorial on how to build Svelte applications and websites with Snowpack'
|
description: 'Get started with this in-depth tutorial on how to build Svelte applications and websites with Snowpack'
|
||||||
date: 2020-12-01
|
date: 2020-12-01
|
||||||
|
|
|
@ -9,7 +9,7 @@ module.exports = function (snowpackConfig, { resolve, extensions, astroConfig }
|
||||||
knownEntrypoints: ['deepmerge'],
|
knownEntrypoints: ['deepmerge'],
|
||||||
resolve: {
|
resolve: {
|
||||||
input: ['.astro', '.md'],
|
input: ['.astro', '.md'],
|
||||||
output: ['.js'],
|
output: ['.js', '.css'],
|
||||||
},
|
},
|
||||||
async load({ filePath }) {
|
async load({ filePath }) {
|
||||||
const { compileComponent } = await transformPromise;
|
const { compileComponent } = await transformPromise;
|
||||||
|
@ -21,7 +21,11 @@ module.exports = function (snowpackConfig, { resolve, extensions, astroConfig }
|
||||||
extensions,
|
extensions,
|
||||||
};
|
};
|
||||||
const result = await compileComponent(contents, { compileOptions, filename: filePath, projectRoot });
|
const result = await compileComponent(contents, { compileOptions, filename: filePath, projectRoot });
|
||||||
return result.contents;
|
const output = {
|
||||||
|
'.js': result.contents,
|
||||||
|
};
|
||||||
|
if (result.css) output['.css'] = result.css;
|
||||||
|
return output;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,9 +25,11 @@ export interface TransformResult {
|
||||||
script: string;
|
script: string;
|
||||||
imports: string[];
|
imports: string[];
|
||||||
items: JsxItem[];
|
items: JsxItem[];
|
||||||
|
css?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CompileResult {
|
export interface CompileResult {
|
||||||
result: TransformResult;
|
result: TransformResult;
|
||||||
contents: string;
|
contents: string;
|
||||||
|
css?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ interface Attribute {
|
||||||
end: number;
|
end: number;
|
||||||
type: 'Attribute';
|
type: 'Attribute';
|
||||||
name: string;
|
name: string;
|
||||||
value: any;
|
value: TemplateNode[] | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CodeGenOptions {
|
interface CodeGenOptions {
|
||||||
|
@ -41,7 +41,8 @@ function getAttributes(attrs: Attribute[]): Record<string, string> {
|
||||||
result[attr.name] = JSON.stringify(attr.value);
|
result[attr.name] = JSON.stringify(attr.value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (attr.value === false) {
|
if (attr.value === false || attr.value === undefined) {
|
||||||
|
// note: attr.value shouldn’t be `undefined`, but a bad transform would cause a compile error here, so prevent that
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (attr.value.length > 1) {
|
if (attr.value.length > 1) {
|
||||||
|
@ -59,7 +60,7 @@ function getAttributes(attrs: Attribute[]): Record<string, string> {
|
||||||
')';
|
')';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const val: TemplateNode = attr.value[0];
|
const val = attr.value[0];
|
||||||
if (!val) {
|
if (!val) {
|
||||||
result[attr.name] = '(' + val + ')';
|
result[attr.name] = '(' + val + ')';
|
||||||
continue;
|
continue;
|
||||||
|
@ -72,7 +73,7 @@ function getAttributes(attrs: Attribute[]): Record<string, string> {
|
||||||
result[attr.name] = JSON.stringify(getTextFromAttribute(val));
|
result[attr.name] = JSON.stringify(getTextFromAttribute(val));
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
throw new Error('UNKNOWN V');
|
throw new Error(`UNKNOWN: ${val.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -253,7 +254,7 @@ async function acquireDynamicComponentImports(plugins: Set<ValidExtensionPlugins
|
||||||
return importMap;
|
return importMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function codegen(ast: Ast, { compileOptions, filename }: CodeGenOptions): Promise<TransformResult> {
|
export async function codegen(ast: Ast, { compileOptions, filename, fileID }: CodeGenOptions): Promise<TransformResult> {
|
||||||
const { extensions = defaultExtensions, astroConfig } = compileOptions;
|
const { extensions = defaultExtensions, astroConfig } = compileOptions;
|
||||||
await eslexer.init;
|
await eslexer.init;
|
||||||
|
|
||||||
|
@ -334,6 +335,21 @@ export async function codegen(ast: Ast, { compileOptions, filename }: CodeGenOpt
|
||||||
let collectionItem: JsxItem | undefined;
|
let collectionItem: JsxItem | undefined;
|
||||||
let currentItemName: string | undefined;
|
let currentItemName: string | undefined;
|
||||||
let currentDepth = 0;
|
let currentDepth = 0;
|
||||||
|
let css: string[] = [];
|
||||||
|
|
||||||
|
walk(ast.css, {
|
||||||
|
enter(node: TemplateNode) {
|
||||||
|
if (node.type === 'Style') {
|
||||||
|
css.push(node.content.styles); // if multiple <style> tags, combine together
|
||||||
|
this.skip();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leave(node: TemplateNode) {
|
||||||
|
if (node.type === 'Style') {
|
||||||
|
this.remove(); // this will be optimized in a global CSS file; remove so it‘s not accidentally inlined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
walk(ast.html, {
|
walk(ast.html, {
|
||||||
enter(node: TemplateNode) {
|
enter(node: TemplateNode) {
|
||||||
|
@ -419,9 +435,9 @@ export async function codegen(ast: Ast, { compileOptions, filename }: CodeGenOpt
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 'Style': {
|
case 'Style': {
|
||||||
const attributes = getAttributes(node.attributes);
|
css.push(node.content.styles); // if multiple <style> tags, combine together
|
||||||
items.push({ name: 'style', jsx: `h("style", ${attributes ? generateAttributes(attributes) : 'null'}, ${JSON.stringify(node.content.styles)})` });
|
this.skip();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case 'Text': {
|
case 'Text': {
|
||||||
const text = getTextFromAttribute(node);
|
const text = getTextFromAttribute(node);
|
||||||
|
@ -469,6 +485,7 @@ export async function codegen(ast: Ast, { compileOptions, filename }: CodeGenOpt
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case 'Style': {
|
case 'Style': {
|
||||||
|
this.remove(); // this will be optimized in a global CSS file; remove so it‘s not accidentally inlined
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -481,5 +498,6 @@ export async function codegen(ast: Ast, { compileOptions, filename }: CodeGenOpt
|
||||||
script: script,
|
script: script,
|
||||||
imports: Array.from(importExportStatements),
|
imports: Array.from(importExportStatements),
|
||||||
items,
|
items,
|
||||||
|
css: css.length ? css.join('\n\n') : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { CompileResult, TransformResult } from '../@types/astro';
|
||||||
import { parse } from '../parser/index.js';
|
import { parse } from '../parser/index.js';
|
||||||
import { createMarkdownHeadersCollector } from '../micromark-collect-headers.js';
|
import { createMarkdownHeadersCollector } from '../micromark-collect-headers.js';
|
||||||
import { encodeMarkdown } from '../micromark-encode.js';
|
import { encodeMarkdown } from '../micromark-encode.js';
|
||||||
import { defaultLogOptions } from '../logger.js';
|
|
||||||
import { optimize } from './optimize/index.js';
|
import { optimize } from './optimize/index.js';
|
||||||
import { codegen } from './codegen.js';
|
import { codegen } from './codegen.js';
|
||||||
|
|
||||||
|
@ -75,14 +74,14 @@ async function convertMdToJsx(
|
||||||
|
|
||||||
const raw = `---
|
const raw = `---
|
||||||
${imports}
|
${imports}
|
||||||
${frontmatterData.layout ? `export const __layout = ${JSON.stringify(frontmatterData.layout)};` : ''}
|
${frontmatterData.layout ? `import {__renderPage as __layout} from '${frontmatterData.layout}';` : 'const __layout = undefined;'}
|
||||||
export const __content = ${stringifiedSetupContext};
|
export const __content = ${stringifiedSetupContext};
|
||||||
---
|
---
|
||||||
<section>${mdHtml}</section>`;
|
<section>${mdHtml}</section>`;
|
||||||
|
|
||||||
const convertOptions = { compileOptions, filename, fileID };
|
const convertOptions = { compileOptions, filename, fileID };
|
||||||
|
|
||||||
return convertAstroToJsx(raw, convertOptions);
|
return await convertAstroToJsx(raw, convertOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
type SupportedExtensions = '.astro' | '.md';
|
type SupportedExtensions = '.astro' | '.md';
|
||||||
|
@ -94,9 +93,9 @@ async function transformFromSource(
|
||||||
const fileID = path.relative(projectRoot, filename);
|
const fileID = path.relative(projectRoot, filename);
|
||||||
switch (path.extname(filename) as SupportedExtensions) {
|
switch (path.extname(filename) as SupportedExtensions) {
|
||||||
case '.astro':
|
case '.astro':
|
||||||
return convertAstroToJsx(contents, { compileOptions, filename, fileID });
|
return await convertAstroToJsx(contents, { compileOptions, filename, fileID });
|
||||||
case '.md':
|
case '.md':
|
||||||
return convertMdToJsx(contents, { compileOptions, filename, fileID });
|
return await convertMdToJsx(contents, { compileOptions, filename, fileID });
|
||||||
default:
|
default:
|
||||||
throw new Error('Not Supported!');
|
throw new Error('Not Supported!');
|
||||||
}
|
}
|
||||||
|
@ -108,8 +107,6 @@ export async function compileComponent(
|
||||||
): Promise<CompileResult> {
|
): Promise<CompileResult> {
|
||||||
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
|
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
|
||||||
const isPage = path.extname(filename) === '.md' || sourceJsx.items.some((item) => item.name === 'html');
|
const isPage = path.extname(filename) === '.md' || sourceJsx.items.some((item) => item.name === 'html');
|
||||||
// sort <style> tags first
|
|
||||||
sourceJsx.items.sort((a, b) => (a.name === 'style' && b.name !== 'style' ? -1 : 0));
|
|
||||||
|
|
||||||
// return template
|
// return template
|
||||||
let modJsx = `
|
let modJsx = `
|
||||||
|
@ -144,8 +141,7 @@ export async function __renderPage({request, children, props}) {
|
||||||
|
|
||||||
// find layout, if one was given.
|
// find layout, if one was given.
|
||||||
if (currentChild.layout) {
|
if (currentChild.layout) {
|
||||||
const layoutComponent = (await import('/_astro/layouts/' + currentChild.layout.replace(/.*layouts\\//, "").replace(/\.astro$/, '.js')));
|
return currentChild.layout({
|
||||||
return layoutComponent.__renderPage({
|
|
||||||
request,
|
request,
|
||||||
props: {content: currentChild.content},
|
props: {content: currentChild.content},
|
||||||
children: [childBodyResult],
|
children: [childBodyResult],
|
||||||
|
@ -162,5 +158,6 @@ export async function __renderPage() { throw new Error("No <html> page element f
|
||||||
return {
|
return {
|
||||||
result: sourceJsx,
|
result: sourceJsx,
|
||||||
contents: modJsx,
|
contents: modJsx,
|
||||||
|
css: sourceJsx.css,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ const getStyleType: Map<string, StyleType> = new Map([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const SASS_OPTIONS: Partial<sass.Options> = {
|
const SASS_OPTIONS: Partial<sass.Options> = {
|
||||||
outputStyle: 'compressed',
|
outputStyle: process.env.NODE_ENV === 'production' ? 'compressed' : undefined,
|
||||||
};
|
};
|
||||||
/** HTML tags that should never get scoped classes */
|
/** HTML tags that should never get scoped classes */
|
||||||
const NEVER_SCOPED_TAGS = new Set<string>(['html', 'head', 'body', 'script', 'style', 'link', 'meta']);
|
const NEVER_SCOPED_TAGS = new Set<string>(['html', 'head', 'body', 'script', 'style', 'link', 'meta']);
|
||||||
|
@ -95,11 +95,10 @@ async function transformStyle(code: string, { type, filename, scopedClass }: { t
|
||||||
return { css, type: styleType };
|
return { css, type: styleType };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Style optimizer */
|
||||||
export default function ({ filename, fileID }: { filename: string; fileID: string }): Optimizer {
|
export default function ({ filename, fileID }: { filename: string; fileID: string }): Optimizer {
|
||||||
const styleNodes: TemplateNode[] = []; // <style> tags to be updated
|
const styleNodes: TemplateNode[] = []; // <style> tags to be updated
|
||||||
const styleTransformPromises: Promise<StyleTransformResult>[] = []; // async style transform results to be finished in finalize();
|
const styleTransformPromises: Promise<StyleTransformResult>[] = []; // async style transform results to be finished in finalize();
|
||||||
let rootNode: TemplateNode; // root node which needs <style> tags
|
|
||||||
|
|
||||||
const scopedClass = `astro-${hashFromFilename(fileID)}`; // this *should* generate same hash from fileID every time
|
const scopedClass = `astro-${hashFromFilename(fileID)}`; // this *should* generate same hash from fileID every time
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -124,15 +123,7 @@ export default function ({ filename, fileID }: { filename: string; fileID: strin
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. find the root node to inject the <style> tag in later
|
// 2. add scoped HTML classes
|
||||||
// TODO: remove this when we are injecting <link> tags into <head>
|
|
||||||
if (node.name === 'head') {
|
|
||||||
rootNode = node; // If this is <head>, this is what we want. Always take this if found. However, this may not always exist (it won’t for Component subtrees).
|
|
||||||
} else if (!rootNode) {
|
|
||||||
rootNode = node; // If no <head> (yet), then take the first element we come to and assume it‘s the “root” (but if we find a <head> later, then override this per the above)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. add scoped HTML classes
|
|
||||||
if (NEVER_SCOPED_TAGS.has(node.name)) return; // only continue if this is NOT a <script> tag, etc.
|
if (NEVER_SCOPED_TAGS.has(node.name)) return; // only continue if this is NOT a <script> tag, etc.
|
||||||
// Note: currently we _do_ scope web components/custom elements. This seems correct?
|
// Note: currently we _do_ scope web components/custom elements. This seems correct?
|
||||||
|
|
||||||
|
@ -175,10 +166,6 @@ export default function ({ filename, fileID }: { filename: string; fileID: strin
|
||||||
scopedClass,
|
scopedClass,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: we should delete the old untransformed <style> node after we’re done.
|
|
||||||
// However, the svelte parser left it in ast.css, not ast.html. At the final step, this just gets ignored, so it will be deleted, in a sense.
|
|
||||||
// If we ever end up scanning ast.css for something else, then we’ll need to actually delete the node (or transform it to the processed version)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -186,14 +173,9 @@ export default function ({ filename, fileID }: { filename: string; fileID: strin
|
||||||
async finalize() {
|
async finalize() {
|
||||||
const styleTransforms = await Promise.all(styleTransformPromises);
|
const styleTransforms = await Promise.all(styleTransformPromises);
|
||||||
|
|
||||||
if (!rootNode) {
|
|
||||||
throw new Error(`No root node found`); // TODO: remove this eventually; we should always find it, but for now alert if there’s a bug in our code
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. transform <style> tags
|
|
||||||
styleTransforms.forEach((result, n) => {
|
styleTransforms.forEach((result, n) => {
|
||||||
if (styleNodes[n].attributes) {
|
if (styleNodes[n].attributes) {
|
||||||
// 1b. Inject final CSS
|
// 1. Replace with final CSS
|
||||||
const isHeadStyle = !styleNodes[n].content;
|
const isHeadStyle = !styleNodes[n].content;
|
||||||
if (isHeadStyle) {
|
if (isHeadStyle) {
|
||||||
// Note: <style> tags in <head> have different attributes/rules, because of the parser. Unknown why
|
// Note: <style> tags in <head> have different attributes/rules, because of the parser. Unknown why
|
||||||
|
@ -202,22 +184,22 @@ export default function ({ filename, fileID }: { filename: string; fileID: strin
|
||||||
styleNodes[n].content.styles = result.css;
|
styleNodes[n].content.styles = result.css;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3b. Update <style> attributes
|
// 2. Update <style> attributes
|
||||||
const styleTypeIndex = styleNodes[n].attributes.findIndex(({ name }: any) => name === 'type');
|
const styleTypeIndex = styleNodes[n].attributes.findIndex(({ name }: any) => name === 'type');
|
||||||
|
// add type="text/css"
|
||||||
if (styleTypeIndex !== -1) {
|
if (styleTypeIndex !== -1) {
|
||||||
styleNodes[n].attributes[styleTypeIndex].value[0].raw = 'text/css';
|
styleNodes[n].attributes[styleTypeIndex].value[0].raw = 'text/css';
|
||||||
styleNodes[n].attributes[styleTypeIndex].value[0].data = 'text/css';
|
styleNodes[n].attributes[styleTypeIndex].value[0].data = 'text/css';
|
||||||
} else {
|
} else {
|
||||||
styleNodes[n].attributes.push({ name: 'type', type: 'Attribute', value: [{ type: 'Text', raw: 'text/css', data: 'text/css' }] });
|
styleNodes[n].attributes.push({ name: 'type', type: 'Attribute', value: [{ type: 'Text', raw: 'text/css', data: 'text/css' }] });
|
||||||
}
|
}
|
||||||
|
// remove lang="*"
|
||||||
const styleLangIndex = styleNodes[n].attributes.findIndex(({ name }: any) => name === 'lang');
|
const styleLangIndex = styleNodes[n].attributes.findIndex(({ name }: any) => name === 'lang');
|
||||||
if (styleLangIndex !== -1) styleNodes[n].attributes.splice(styleLangIndex, 1);
|
if (styleLangIndex !== -1) styleNodes[n].attributes.splice(styleLangIndex, 1);
|
||||||
|
// TODO: add data-astro for later
|
||||||
|
// styleNodes[n].attributes.push({ name: 'data-astro', type: 'Attribute', value: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. inject finished <style> tags into root node
|
|
||||||
// TODO: pull out into <link> tags for deduping
|
|
||||||
rootNode.children = [...styleNodes, ...(rootNode.children || [])];
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ export interface Parser {
|
||||||
html: Node;
|
html: Node;
|
||||||
css: Node;
|
css: Node;
|
||||||
js: Node;
|
js: Node;
|
||||||
meta_tags: {};
|
meta_tags: Map<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Script extends BaseNode {
|
export interface Script extends BaseNode {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import type { SnowpackDevServer, ServerRuntime as SnowpackServerRuntime, LoadResult as SnowpackLoadResult, SnowpackConfig } from 'snowpack';
|
import type { SnowpackDevServer, ServerRuntime as SnowpackServerRuntime, SnowpackConfig } from 'snowpack';
|
||||||
import type { AstroConfig } from './@types/astro';
|
import type { AstroConfig } from './@types/astro';
|
||||||
import type { LogOptions } from './logger';
|
import type { LogOptions } from './logger';
|
||||||
import type { CompileError } from './parser/utils/error.js';
|
import type { CompileError } from './parser/utils/error.js';
|
||||||
import { info } from './logger.js';
|
import { debug, info } from './logger.js';
|
||||||
|
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { loadConfiguration, logger as snowpackLogger, startServer as startSnowpackServer } from 'snowpack';
|
import { loadConfiguration, logger as snowpackLogger, startServer as startSnowpackServer } from 'snowpack';
|
||||||
|
@ -39,7 +39,6 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
|
||||||
|
|
||||||
const selectedPageLoc = new URL(`./pages/${selectedPage}.astro`, astroRoot);
|
const selectedPageLoc = new URL(`./pages/${selectedPage}.astro`, astroRoot);
|
||||||
const selectedPageMdLoc = new URL(`./pages/${selectedPage}.md`, astroRoot);
|
const selectedPageMdLoc = new URL(`./pages/${selectedPage}.md`, astroRoot);
|
||||||
const selectedPageUrl = `/_astro/pages/${selectedPage}.js`;
|
|
||||||
|
|
||||||
// Non-Astro pages (file resources)
|
// Non-Astro pages (file resources)
|
||||||
if (!existsSync(selectedPageLoc) && !existsSync(selectedPageMdLoc)) {
|
if (!existsSync(selectedPageLoc) && !existsSync(selectedPageMdLoc)) {
|
||||||
|
@ -62,49 +61,61 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
for (const url of [`/_astro/pages/${selectedPage}.astro.js`, `/_astro/pages/${selectedPage}.md.js`]) {
|
||||||
const mod = await snowpackRuntime.importModule(selectedPageUrl);
|
try {
|
||||||
let html = (await mod.exports.__renderPage({
|
const mod = await snowpackRuntime.importModule(url);
|
||||||
request: {
|
debug(logging, 'resolve', `${reqPath} -> ${url}`);
|
||||||
host: fullurl.hostname,
|
let html = (await mod.exports.__renderPage({
|
||||||
path: fullurl.pathname,
|
request: {
|
||||||
href: fullurl.toString(),
|
host: fullurl.hostname,
|
||||||
},
|
path: fullurl.pathname,
|
||||||
children: [],
|
href: fullurl.toString(),
|
||||||
props: {},
|
},
|
||||||
})) as string;
|
children: [],
|
||||||
|
props: {},
|
||||||
|
})) as string;
|
||||||
|
|
||||||
// inject styles
|
// inject styles
|
||||||
// TODO: handle this in compiler
|
// TODO: handle this in compiler
|
||||||
const styleTags = Array.isArray(mod.css) && mod.css.length ? mod.css.reduce((markup, url) => `${markup}\n<link rel="stylesheet" type="text/css" href="${url}" />`, '') : ``;
|
const styleTags = Array.isArray(mod.css) && mod.css.length ? mod.css.reduce((markup, href) => `${markup}\n<link rel="stylesheet" type="text/css" href="${href}" />`, '') : ``;
|
||||||
if (html.indexOf('</head>') !== -1) {
|
if (html.indexOf('</head>') !== -1) {
|
||||||
html = html.replace('</head>', `${styleTags}</head>`);
|
html = html.replace('</head>', `${styleTags}</head>`);
|
||||||
} else {
|
} else {
|
||||||
html = styleTags + html;
|
html = styleTags + html;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
contents: html,
|
contents: html,
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
switch (err.code) {
|
// if this is a 404, try the next URL (will be caught at the end)
|
||||||
case 'parse-error': {
|
const notFoundError = err.toString().startsWith('Error: Not Found');
|
||||||
|
if (notFoundError) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.code === 'parse-error') {
|
||||||
return {
|
return {
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
type: 'parse-error',
|
type: 'parse-error',
|
||||||
error: err,
|
error: err,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default: {
|
return {
|
||||||
return {
|
statusCode: 500,
|
||||||
statusCode: 500,
|
type: 'unknown',
|
||||||
type: 'unknown',
|
error: err,
|
||||||
error: err,
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// couldn‘t find match; 404
|
||||||
|
return {
|
||||||
|
statusCode: 404,
|
||||||
|
type: 'unknown',
|
||||||
|
error: new Error(`Could not locate ${selectedPage}`),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AstroRuntime {
|
export interface AstroRuntime {
|
||||||
|
|
|
@ -8,6 +8,16 @@ const StylesSSR = suite('Styles SSR');
|
||||||
|
|
||||||
let runtime;
|
let runtime;
|
||||||
|
|
||||||
|
/** Basic CSS minification; removes some flakiness in testing CSS */
|
||||||
|
function cssMinify(css) {
|
||||||
|
return css
|
||||||
|
.trim() // remove whitespace
|
||||||
|
.replace(/\n\s*/g, '') // collapse lines
|
||||||
|
.replace(/\s*\{/g, '{') // collapse selectors
|
||||||
|
.replace(/:\s*/g, ':') // collapse attributes
|
||||||
|
.replace(/;}/g, '}'); // collapse block
|
||||||
|
}
|
||||||
|
|
||||||
StylesSSR.before(async () => {
|
StylesSSR.before(async () => {
|
||||||
const astroConfig = await loadConfig(new URL('./fixtures/astro-styles-ssr', import.meta.url).pathname);
|
const astroConfig = await loadConfig(new URL('./fixtures/astro-styles-ssr', import.meta.url).pathname);
|
||||||
|
|
||||||
|
@ -54,12 +64,15 @@ StylesSSR('CSS Module support in .astro', async () => {
|
||||||
let scopedClass;
|
let scopedClass;
|
||||||
|
|
||||||
// test 1: <style> tag in <head> is transformed
|
// test 1: <style> tag in <head> is transformed
|
||||||
const css = $('style')
|
const css = cssMinify(
|
||||||
.html()
|
$('style')
|
||||||
.replace(/\.astro-[A-Za-z0-9-]+/, (match) => {
|
.html()
|
||||||
scopedClass = match;
|
.replace(/\.astro-[A-Za-z0-9-]+/, (match) => {
|
||||||
return match;
|
scopedClass = match; // get class hash from result
|
||||||
}); // remove class hash (should be deterministic / the same every time, but even still don‘t cause this test to flake)
|
return match;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
assert.equal(css, `.wrapper${scopedClass}{margin-left:auto;margin-right:auto;max-width:1200px}`);
|
assert.equal(css, `.wrapper${scopedClass}{margin-left:auto;margin-right:auto;max-width:1200px}`);
|
||||||
|
|
||||||
// test 2: element received .astro-XXXXXX class (this selector will succeed if transformed correctly)
|
// test 2: element received .astro-XXXXXX class (this selector will succeed if transformed correctly)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
layout: layouts/content.astro
|
layout: ../layouts/content.astro
|
||||||
title: My Blog Post
|
title: My Blog Post
|
||||||
description: This is a post about some stuff.
|
description: This is a post about some stuff.
|
||||||
import:
|
import:
|
||||||
|
@ -10,4 +10,4 @@ import:
|
||||||
|
|
||||||
<div id="first">Some content</div>
|
<div id="first">Some content</div>
|
||||||
|
|
||||||
<Example />
|
<Example />
|
||||||
|
|
Loading…
Reference in a new issue