summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Drew Powers <1369770+drwpow@users.noreply.github.com> 2021-11-04 14:01:28 -0600
committerGravatar GitHub <noreply@github.com> 2021-11-04 14:01:28 -0600
commit2e1bded735f3e2149c3ff95b1c131a147dda0f34 (patch)
tree1f4433cad8db49e5be6ae8bbc4f277de9d5fa7e0
parent2c5e67bb44398080037c02fbdd756cc66e757f1e (diff)
downloadastro-2e1bded735f3e2149c3ff95b1c131a147dda0f34.tar.gz
astro-2e1bded735f3e2149c3ff95b1c131a147dda0f34.tar.zst
astro-2e1bded735f3e2149c3ff95b1c131a147dda0f34.zip
Get Tailwind HMR working (first cut) (#1736)
* Get Tailwind HMR working * PR feedback * perf: improve HMR `head` performance Co-authored-by: Nate Moore <nate@skypack.dev>
-rw-r--r--.changeset/shaggy-guests-type.md5
-rw-r--r--docs/src/pages/guides/styling.md8
-rw-r--r--examples/with-tailwindcss/package.json4
-rw-r--r--examples/with-tailwindcss/postcss.config.js6
-rw-r--r--examples/with-tailwindcss/src/components/Button.astro5
-rw-r--r--examples/with-tailwindcss/src/pages/index.astro4
-rw-r--r--packages/astro/src/@types/astro-core.ts8
-rw-r--r--packages/astro/src/core/dev/index.ts65
-rw-r--r--packages/astro/src/core/ssr/css.ts1
-rw-r--r--packages/astro/src/core/ssr/html.ts85
-rw-r--r--packages/astro/src/core/ssr/index.ts3
-rw-r--r--packages/astro/src/runtime/client/hmr.ts7
-rw-r--r--yarn.lock60
13 files changed, 176 insertions, 85 deletions
diff --git a/.changeset/shaggy-guests-type.md b/.changeset/shaggy-guests-type.md
new file mode 100644
index 000000000..062ba96be
--- /dev/null
+++ b/.changeset/shaggy-guests-type.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+fix: Improve Tailwind HMR
diff --git a/docs/src/pages/guides/styling.md b/docs/src/pages/guides/styling.md
index 98df62b8a..a42d759df 100644
--- a/docs/src/pages/guides/styling.md
+++ b/docs/src/pages/guides/styling.md
@@ -235,6 +235,14 @@ Now you're ready to write Tailwind! Our recommended approach is to create a `src
@tailwind utilities;
```
+Lastly, add it to your Astro page (or layout template):
+
+```astro
+<head>
+ <link rel="stylesheet" href={Astro.resolve('../styles/global.css')}>
+</head>
+```
+
As an alternative to `src/styles/global.css`, You may also add Tailwind utilities to individual `pages/*.astro` components in `<style>` tags, but be mindful of duplication! If you end up creating multiple Tailwind-managed stylesheets for your site, make sure you're not sending the same CSS to users over and over again in separate CSS files.
#### Migrating from v0.19
diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json
index 7132c4391..a7ee6a2bf 100644
--- a/examples/with-tailwindcss/package.json
+++ b/examples/with-tailwindcss/package.json
@@ -10,7 +10,7 @@
},
"devDependencies": {
"astro": "^0.21.0-next.1",
- "autoprefixer": "^10.3.7",
- "tailwindcss": "^2.2.17"
+ "autoprefixer": "^10.4.0",
+ "tailwindcss": "^2.2.19"
}
}
diff --git a/examples/with-tailwindcss/postcss.config.js b/examples/with-tailwindcss/postcss.config.js
index 12a703d90..7cffbeb55 100644
--- a/examples/with-tailwindcss/postcss.config.js
+++ b/examples/with-tailwindcss/postcss.config.js
@@ -1,6 +1,10 @@
+const path = require('path');
+
module.exports = {
plugins: {
- tailwindcss: {},
+ tailwindcss: {
+ config: path.join(__dirname, 'tailwind.config.js'), // update this if your path differs!
+ },
autoprefixer: {},
},
};
diff --git a/examples/with-tailwindcss/src/components/Button.astro b/examples/with-tailwindcss/src/components/Button.astro
index 64baa50ae..966c613aa 100644
--- a/examples/with-tailwindcss/src/components/Button.astro
+++ b/examples/with-tailwindcss/src/components/Button.astro
@@ -1,3 +1,6 @@
-<button class="py-2 px-4 bg-green-500 text-white font-semibold rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opacity-75">
+---
+let { type = 'button' } = Astro.props;
+---
+<button class="py-2 px-4 bg-purple-500 text-white font-semibold rounded-lg shadow-md hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-400 focus:ring-opacity-75" type={type}>
<slot />
</button>
diff --git a/examples/with-tailwindcss/src/pages/index.astro b/examples/with-tailwindcss/src/pages/index.astro
index 10f370ba3..28d5f3dec 100644
--- a/examples/with-tailwindcss/src/pages/index.astro
+++ b/examples/with-tailwindcss/src/pages/index.astro
@@ -8,9 +8,7 @@ import Button from '../components/Button.astro';
<html lang="en">
<head>
<meta charset="UTF-8" />
-
- <link rel="icon" type="image/x-icon" href="/favicon.ico" />
-
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<title>Astro + TailwindCSS</title>
<link rel="stylesheet" type="text/css" href={Astro.resolve("../styles/global.css")}>
</head>
diff --git a/packages/astro/src/@types/astro-core.ts b/packages/astro/src/@types/astro-core.ts
index 9a5d718fc..29eb7bba4 100644
--- a/packages/astro/src/@types/astro-core.ts
+++ b/packages/astro/src/@types/astro-core.ts
@@ -139,8 +139,11 @@ export interface CollectionRSS {
/** Generic interface for a component (Astro, Svelte, React, etc.) */
export interface ComponentInstance {
+ $$metadata: {
+ modules: { module: Record<string, unknown>; specifier: string }[];
+ fileURL: URL;
+ };
default: AstroComponentFactory;
- css?: string[];
getStaticPaths?: (options: GetStaticPathsOptions) => GetStaticPathsResult;
}
@@ -263,6 +266,9 @@ export interface Renderer {
knownEntrypoints?: string[];
}
+/** <link> tags with attributes represented by an object */
+export type Resource = Record<string, string>;
+
export interface RouteData {
component: string;
generate: (data?: any) => string;
diff --git a/packages/astro/src/core/dev/index.ts b/packages/astro/src/core/dev/index.ts
index a128fa1ec..f0e82df14 100644
--- a/packages/astro/src/core/dev/index.ts
+++ b/packages/astro/src/core/dev/index.ts
@@ -4,6 +4,7 @@ import type { AstroConfig, ManifestData, RouteCache, RouteData } from '../../@ty
import type { LogOptions } from '../logger';
import type { HmrContext, ModuleNode } from '../vite';
+import path from 'path';
import { fileURLToPath } from 'url';
import { promisify } from 'util';
import connect from 'connect';
@@ -13,6 +14,8 @@ import stripAnsi from 'strip-ansi';
import vite from '../vite.js';
import { defaultLogOptions, error, info } from '../logger.js';
import { ssr } from '../ssr/index.js';
+import { STYLE_EXTENSIONS } from '../ssr/css.js';
+import { collectResources } from '../ssr/html.js';
import { createRouteManifest, matchRoute } from '../ssr/routing.js';
import { createVite } from '../create-vite.js';
import * as msg from './messages.js';
@@ -51,7 +54,6 @@ export class AstroDevServer {
httpServer: http.Server | undefined;
hostname: string;
port: number;
-
private config: AstroConfig;
private logging: LogOptions;
private manifest: ManifestData;
@@ -92,49 +94,94 @@ export class AstroDevServer {
}
public async handleHotUpdate({ file, modules }: HmrContext): Promise<void | ModuleNode[]> {
- if (!this.viteServer) throw new Error(`AstroDevServer.start() not called`);
+ const { viteServer } = this;
+ if (!viteServer) throw new Error(`AstroDevServer.start() not called`);
for (const module of modules) {
- this.viteServer.moduleGraph.invalidateModule(module);
+ viteServer.moduleGraph.invalidateModule(module);
}
const route = this.mostRecentRoute;
const pathname = route?.pathname ?? '/';
if (!route) {
- this.viteServer.ws.send({
+ viteServer.ws.send({
type: 'full-reload',
});
return [];
}
try {
+ const filePath = new URL(`./${route.component}`, this.config.projectRoot);
// try to update the most recent route
const html = await ssr({
astroConfig: this.config,
- filePath: new URL(`./${route.component}`, this.config.projectRoot),
+ filePath,
logging: this.logging,
mode: 'development',
origin: this.origin,
pathname,
route,
routeCache: this.routeCache,
- viteServer: this.viteServer,
+ viteServer,
});
+ // collect style tags to be reloaded (needed for Tailwind HMR, etc.)
+ let invalidatedModules: vite.ModuleNode[] = [];
+ await Promise.all(
+ collectResources(html)
+ .filter(({ href }) => {
+ if (!href) return false;
+ const ext = path.extname(href);
+ return STYLE_EXTENSIONS.has(ext);
+ })
+ .map(async ({ href }) => {
+ const viteModule =
+ viteServer.moduleGraph.getModuleById(`${href}?direct`) ||
+ (await viteServer.moduleGraph.getModuleByUrl(`${href}?direct`)) ||
+ viteServer.moduleGraph.getModuleById(href) ||
+ (await viteServer.moduleGraph.getModuleByUrl(href));
+ if (viteModule) {
+ invalidatedModules.push(viteModule);
+ viteServer.moduleGraph.invalidateModule(viteModule);
+ }
+ })
+ );
+
// TODO: log update
- this.viteServer.ws.send({
+ viteServer.ws.send({
type: 'custom',
event: 'astro:reload',
data: { html },
});
+
+ for (const viteModule of invalidatedModules) {
+ // Note: from the time viteServer.moduleGraph.invalidateModule() is called above until now, CSS
+ // is building in the background. For things like Tailwind, this can take some time. If the
+ // CSS is still processing by the time HMR fires, we’ll end up with stale styles on the page.
+ // TODO: fix this hack by figuring out how to add these styles to the { modules } above
+ setTimeout(() => {
+ viteServer.ws.send({
+ type: 'update',
+ updates: [
+ {
+ type: viteModule.type === 'js' ? 'js-update' : 'css-update',
+ path: viteModule.id || viteModule.file || viteModule.url,
+ acceptedPath: viteModule.url,
+ timestamp: Date.now(),
+ },
+ ],
+ });
+ }, 150);
+ }
+
return [];
} catch (e) {
const err = e as Error;
- this.viteServer.ssrFixStacktrace(err);
+ viteServer.ssrFixStacktrace(err);
// eslint-disable-next-line
console.error(err.stack);
- this.viteServer.ws.send({
+ viteServer.ws.send({
type: 'full-reload',
});
return [];
diff --git a/packages/astro/src/core/ssr/css.ts b/packages/astro/src/core/ssr/css.ts
index 688fea2a6..9fba52fca 100644
--- a/packages/astro/src/core/ssr/css.ts
+++ b/packages/astro/src/core/ssr/css.ts
@@ -1,7 +1,6 @@
import type vite from '../../../vendor/vite';
import path from 'path';
-import htmlparser2 from 'htmlparser2';
// https://vitejs.dev/guide/features.html#css-pre-processors
export const STYLE_EXTENSIONS = new Set(['.css', '.pcss', '.scss', '.sass', '.styl', '.stylus', '.less']);
diff --git a/packages/astro/src/core/ssr/html.ts b/packages/astro/src/core/ssr/html.ts
index 6608bbb2f..faa6f055b 100644
--- a/packages/astro/src/core/ssr/html.ts
+++ b/packages/astro/src/core/ssr/html.ts
@@ -4,53 +4,68 @@ import htmlparser2 from 'htmlparser2';
/** Inject tags into HTML (note: for best performance, group as many tags as possible into as few calls as you can) */
export function injectTags(html: string, tags: vite.HtmlTagDescriptor[]): string {
- // TODO: this usually takes 5ms or less, but if it becomes a bottleneck we can create a WeakMap cache
let output = html;
if (!tags.length) return output;
const pos = { 'head-prepend': -1, head: -1, 'body-prepend': -1, body: -1 };
- try {
- // parse html
- const parser = new htmlparser2.Parser({
- onopentag(tagname) {
- if (tagname === 'head') pos['head-prepend'] = parser.endIndex + 1;
- if (tagname === 'body') pos['body-prepend'] = parser.endIndex + 1;
- },
- onclosetag(tagname) {
- if (tagname === 'head') pos['head'] = parser.startIndex;
- if (tagname === 'body') pos['body'] = parser.startIndex;
- },
- });
- parser.write(html);
- parser.end();
-
- // inject
- const lastToFirst = Object.entries(pos).sort((a, b) => b[1] - a[1]);
- lastToFirst.forEach(([name, i]) => {
- if (i === -1) {
- // TODO: warn on missing tag? Is this an HTML partial?
- return;
+ // parse html
+ const parser = new htmlparser2.Parser({
+ onopentag(tagname) {
+ if (tagname === 'head') pos['head-prepend'] = parser.endIndex + 1;
+ if (tagname === 'body') pos['body-prepend'] = parser.endIndex + 1;
+ },
+ onclosetag(tagname) {
+ if (tagname === 'head') pos['head'] = parser.startIndex;
+ if (tagname === 'body') pos['body'] = parser.startIndex;
+ },
+ });
+ parser.write(html);
+ parser.end();
+
+ // inject
+ const lastToFirst = Object.entries(pos).sort((a, b) => b[1] - a[1]);
+ lastToFirst.forEach(([name, i]) => {
+ if (i === -1) {
+ // TODO: warn on missing tag? Is this an HTML partial?
+ return;
+ }
+ let selected = tags.filter(({ injectTo }) => {
+ if (name === 'head-prepend' && !injectTo) {
+ return true; // "head-prepend" is the default
+ } else {
+ return injectTo === name;
}
- let selected = tags.filter(({ injectTo }) => {
- if (name === 'head-prepend' && !injectTo) {
- return true; // "head-prepend" is the default
- } else {
- return injectTo === name;
- }
- });
- if (!selected.length) return;
- output = output.substring(0, i) + serializeTags(selected) + html.substring(i);
});
- } catch (err) {
- // on invalid HTML, do nothing
- }
+ if (!selected.length) return;
+ output = output.substring(0, i) + serializeTags(selected) + html.substring(i);
+ });
return output;
}
-// Everything below © Vite
+type Resource = Record<string, string>;
+
+/** Collect resources (scans final, rendered HTML so expressions have been applied) */
+export function collectResources(html: string): Resource[] {
+ let resources: Resource[] = [];
+ const parser = new htmlparser2.Parser({
+ // <link> tags are self-closing, so only use onopentag (avoid onattribute or onclosetag)
+ onopentag(tagname, attrs) {
+ if (tagname === 'link') resources.push(attrs);
+ },
+ });
+ parser.write(html);
+ parser.end();
+ return resources;
+}
+
+// -------------------------------------------------------------------------------
+// Everything below © Vite. Rather than invent our own tag creating API, we borrow
+// Vite’s `transformIndexHtml()` API for ease-of-use and consistency. But we need
+// to borrow a few private methods in Vite to make that available here.
// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/html.ts
+// -------------------------------------------------------------------------------
// Vite is released under the MIT license:
diff --git a/packages/astro/src/core/ssr/index.ts b/packages/astro/src/core/ssr/index.ts
index e2c4b76c0..8823c483e 100644
--- a/packages/astro/src/core/ssr/index.ts
+++ b/packages/astro/src/core/ssr/index.ts
@@ -4,7 +4,6 @@ import type { AstroConfig, ComponentInstance, GetStaticPathsResult, Params, Prop
import type { AstroGlobal, TopLevelAstro, SSRResult, SSRElement } from '../../@types/astro-runtime';
import type { LogOptions } from '../logger';
-import { fileURLToPath } from 'url';
import fs from 'fs';
import path from 'path';
import { renderPage, renderSlot } from '../../runtime/server/index.js';
@@ -164,7 +163,7 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
// inject tags
const tags: vite.HtmlTagDescriptor[] = [];
- // inject Astro HMR client (dev only)
+ // dev only: inject Astro HMR client
if (mode === 'development') {
tags.push({
tag: 'script',
diff --git a/packages/astro/src/runtime/client/hmr.ts b/packages/astro/src/runtime/client/hmr.ts
index ea79c7dfc..e2f65da94 100644
--- a/packages/astro/src/runtime/client/hmr.ts
+++ b/packages/astro/src/runtime/client/hmr.ts
@@ -6,10 +6,17 @@ if (import.meta.hot) {
morphdom(document.head, doc.head, {
onBeforeElUpdated(fromEl, toEl) {
+ // Do not update identical tags
if (fromEl.isEqualNode(toEl)) {
return false;
}
+ // Do not update <link> or <script> tags
+ // to avoid re-fetching their contents
+ if (fromEl.tagName === toEl.tagName && (toEl.tagName === 'LINK' || toEl.tagName === 'SCRIPT')) {
+ return false;
+ }
+
return true;
},
});
diff --git a/yarn.lock b/yarn.lock
index 13a890689..a520e701f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2549,16 +2549,16 @@ at-least-node@^1.0.0:
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
-autoprefixer@^10.3.7:
- version "10.3.7"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.3.7.tgz#cef2562058406bd378c94aacda36bb46a97b3186"
- integrity sha512-EmGpu0nnQVmMhX8ROoJ7Mx8mKYPlcUHuxkwrRYEYMz85lu7H09v8w6R1P0JPdn/hKU32GjpLBFEOuIlDWCRWvg==
+autoprefixer@^10.4.0:
+ version "10.4.0"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.0.tgz#c3577eb32a1079a440ec253e404eaf1eb21388c8"
+ integrity sha512-7FdJ1ONtwzV1G43GDD0kpVMn/qbiNqyOPMFTX5nRffI+7vgWoFEc6DcXOxHJxrWNDXrZh18eDsZjvZGUljSRGA==
dependencies:
- browserslist "^4.17.3"
- caniuse-lite "^1.0.30001264"
+ browserslist "^4.17.5"
+ caniuse-lite "^1.0.30001272"
fraction.js "^4.1.1"
normalize-range "^0.1.2"
- picocolors "^0.2.1"
+ picocolors "^1.0.0"
postcss-value-parser "^4.1.0"
available-typed-arrays@^1.0.5:
@@ -2778,15 +2778,15 @@ browserslist@^4.16.6:
escalade "^3.1.1"
node-releases "^1.1.75"
-browserslist@^4.17.3:
- version "4.17.4"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.4.tgz#72e2508af2a403aec0a49847ef31bd823c57ead4"
- integrity sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==
+browserslist@^4.17.5:
+ version "4.17.5"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.5.tgz#c827bbe172a4c22b123f5e337533ceebadfdd559"
+ integrity sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==
dependencies:
- caniuse-lite "^1.0.30001265"
- electron-to-chromium "^1.3.867"
+ caniuse-lite "^1.0.30001271"
+ electron-to-chromium "^1.3.878"
escalade "^3.1.1"
- node-releases "^2.0.0"
+ node-releases "^2.0.1"
picocolors "^1.0.0"
buffer-crc32@~0.2.3:
@@ -2933,10 +2933,10 @@ caniuse-lite@^1.0.30001254:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001258.tgz#b604eed80cc54a578e4bf5a02ae3ed49f869d252"
integrity sha512-RBByOG6xWXUp0CR2/WU2amXz3stjKpSl5J1xU49F1n2OxD//uBZO4wCKUiG+QMGf7CHGfDDcqoKriomoGVxTeA==
-caniuse-lite@^1.0.30001264, caniuse-lite@^1.0.30001265:
- version "1.0.30001267"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001267.tgz#b1cf2937175afc0570e4615fc2d2f9069fa0ed30"
- integrity sha512-r1mjTzAuJ9W8cPBGbbus8E0SKcUP7gn03R14Wk8FlAlqhH9hroy9nLqmpuXlfKEw/oILW+FGz47ipXV2O7x8lg==
+caniuse-lite@^1.0.30001271, caniuse-lite@^1.0.30001272:
+ version "1.0.30001274"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001274.tgz#26ca36204d15b17601ba6fc35dbdad950a647cc7"
+ integrity sha512-+Nkvv0fHyhISkiMIjnyjmf5YJcQ1IQHZN6U9TLUMroWR38FNwpsC51Gb68yueafX1V6ifOisInSgP9WJFS13ew==
caseless@~0.12.0:
version "0.12.0"
@@ -3952,10 +3952,10 @@ electron-to-chromium@^1.3.830:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.843.tgz#671489bd2f59fd49b76adddc1aa02c88cd38a5c0"
integrity sha512-OWEwAbzaVd1Lk9MohVw8LxMXFlnYd9oYTYxfX8KS++kLLjDfbovLOcEEXwRhG612dqGQ6+44SZvim0GXuBRiKg==
-electron-to-chromium@^1.3.867:
- version "1.3.871"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz#6e87365fd72037a6c898fb46050ad4be3ac9ef62"
- integrity sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==
+electron-to-chromium@^1.3.878:
+ version "1.3.886"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.886.tgz#ac039c4001b665b1dd0f0ed9c2e4da90ff3c9267"
+ integrity sha512-+vYdeBosI63VkCtNWnEVFjgNd/IZwvnsWkKyPtWAvrhA+XfByKoBJcbsMgudVU/bUcGAF9Xp3aXn96voWlc3oQ==
emmet@^2.1.5:
version "2.3.4"
@@ -7729,10 +7729,10 @@ node-releases@^1.1.75:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe"
integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==
-node-releases@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.0.tgz#67dc74903100a7deb044037b8a2e5f453bb05400"
- integrity sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==
+node-releases@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
+ integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
node.extend@~2.0.2:
version "2.0.2"
@@ -10224,10 +10224,10 @@ svelte@^3.44.0:
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.44.0.tgz#e6176cb3ad93846ddb4140e93f43098136b23f3b"
integrity sha512-zWACSJBSncGiDvFfYOMFGNV5zDLOlyhftmO5yOZ0lEtQMptpElaRtl39MWz1+lYCpwUq4F3Q2lTzI9TrTL+eMA==
-tailwindcss@^2.2.17:
- version "2.2.17"
- resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.2.17.tgz#c6332731f9ff1b6628ff589c95c38685347775e3"
- integrity sha512-WgRpn+Pxn7eWqlruxnxEbL9ByVRWi3iC10z4b6dW0zSdnkPVC4hPMSWLQkkW8GCyBIv/vbJ0bxIi9dVrl4CfoA==
+tailwindcss@^2.2.19:
+ version "2.2.19"
+ resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-2.2.19.tgz#540e464832cd462bb9649c1484b0a38315c2653c"
+ integrity sha512-6Ui7JSVtXadtTUo2NtkBBacobzWiQYVjYW0ZnKaP9S1ZCKQ0w7KVNz+YSDI/j7O7KCMHbOkz94ZMQhbT9pOqjw==
dependencies:
arg "^5.0.1"
bytes "^3.0.0"