feat: expose locals to render api and from requests in dev mode (#7385)
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: wrapperup <wrapperup4@gmail.com>
This commit is contained in:
parent
61d6e45cef
commit
8e2923cc62
22 changed files with 254 additions and 87 deletions
6
.changeset/smooth-jokes-watch.md
Normal file
6
.changeset/smooth-jokes-watch.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'astro': minor
|
||||
'@astrojs/node': minor
|
||||
---
|
||||
|
||||
`Astro.locals` is now exposed to the adapter API. Node Adapter can now pass in a `locals` object in the SSR handler middleware.
|
|
@ -115,7 +115,7 @@ export class App {
|
|||
return undefined;
|
||||
}
|
||||
}
|
||||
async render(request: Request, routeData?: RouteData): Promise<Response> {
|
||||
async render(request: Request, routeData?: RouteData, locals?: object): Promise<Response> {
|
||||
let defaultStatus = 200;
|
||||
if (!routeData) {
|
||||
routeData = this.match(request);
|
||||
|
@ -131,7 +131,7 @@ export class App {
|
|||
}
|
||||
}
|
||||
|
||||
Reflect.set(request, clientLocalsSymbol, {});
|
||||
Reflect.set(request, clientLocalsSymbol, locals ?? {});
|
||||
|
||||
// Use the 404 status code for 404.astro components
|
||||
if (routeData.route === '/404') {
|
||||
|
@ -243,7 +243,7 @@ export class App {
|
|||
page.onRequest as MiddlewareResponseHandler,
|
||||
apiContext,
|
||||
() => {
|
||||
return renderPage({ mod, renderContext, env: this.#env, apiContext });
|
||||
return renderPage({ mod, renderContext, env: this.#env, cookies: apiContext.cookies });
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
@ -251,7 +251,7 @@ export class App {
|
|||
mod,
|
||||
renderContext,
|
||||
env: this.#env,
|
||||
apiContext,
|
||||
cookies: apiContext.cookies,
|
||||
});
|
||||
}
|
||||
Reflect.set(request, responseSentSymbol, true);
|
||||
|
|
|
@ -41,11 +41,12 @@ export class NodeApp extends App {
|
|||
match(req: NodeIncomingMessage | Request, opts: MatchOptions = {}) {
|
||||
return super.match(req instanceof Request ? req : createRequestFromNodeRequest(req), opts);
|
||||
}
|
||||
render(req: NodeIncomingMessage | Request, routeData?: RouteData) {
|
||||
render(req: NodeIncomingMessage | Request, routeData?: RouteData, locals?: object) {
|
||||
if (typeof req.body === 'string' && req.body.length > 0) {
|
||||
return super.render(
|
||||
req instanceof Request ? req : createRequestFromNodeRequest(req, Buffer.from(req.body)),
|
||||
routeData
|
||||
routeData,
|
||||
locals
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -54,7 +55,8 @@ export class NodeApp extends App {
|
|||
req instanceof Request
|
||||
? req
|
||||
: createRequestFromNodeRequest(req, Buffer.from(JSON.stringify(req.body))),
|
||||
routeData
|
||||
routeData,
|
||||
locals
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -75,13 +77,15 @@ export class NodeApp extends App {
|
|||
return reqBodyComplete.then(() => {
|
||||
return super.render(
|
||||
req instanceof Request ? req : createRequestFromNodeRequest(req, body),
|
||||
routeData
|
||||
routeData,
|
||||
locals
|
||||
);
|
||||
});
|
||||
}
|
||||
return super.render(
|
||||
req instanceof Request ? req : createRequestFromNodeRequest(req),
|
||||
routeData
|
||||
routeData,
|
||||
locals
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -603,8 +603,8 @@ async function generatePath(
|
|||
mod,
|
||||
renderContext,
|
||||
env,
|
||||
apiContext,
|
||||
isCompressHTML: settings.config.compressHTML,
|
||||
cookies: apiContext.cookies,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -613,8 +613,8 @@ async function generatePath(
|
|||
mod,
|
||||
renderContext,
|
||||
env,
|
||||
apiContext,
|
||||
isCompressHTML: settings.config.compressHTML,
|
||||
cookies: apiContext.cookies,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
|
@ -78,6 +78,7 @@ export function createAPIContext({
|
|||
|
||||
// We define a custom property, so we can check the value passed to locals
|
||||
Object.defineProperty(context, 'locals', {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return Reflect.get(request, clientLocalsSymbol);
|
||||
},
|
||||
|
|
|
@ -7,9 +7,12 @@ import type {
|
|||
SSRElement,
|
||||
SSRResult,
|
||||
} from '../../@types/astro';
|
||||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||
import { getParamsAndPropsOrThrow } from './core.js';
|
||||
import type { Environment } from './environment';
|
||||
|
||||
const clientLocalsSymbol = Symbol.for('astro.locals');
|
||||
|
||||
/**
|
||||
* The RenderContext represents the parts of rendering that are specific to one request.
|
||||
*/
|
||||
|
@ -27,6 +30,7 @@ export interface RenderContext {
|
|||
cookies?: AstroCookies;
|
||||
params: Params;
|
||||
props: Props;
|
||||
locals?: object;
|
||||
}
|
||||
|
||||
export type CreateRenderContextArgs = Partial<RenderContext> & {
|
||||
|
@ -51,7 +55,8 @@ export async function createRenderContext(
|
|||
logging: options.env.logging,
|
||||
ssr: options.env.ssr,
|
||||
});
|
||||
return {
|
||||
|
||||
let context = {
|
||||
...options,
|
||||
origin,
|
||||
pathname,
|
||||
|
@ -59,4 +64,21 @@ export async function createRenderContext(
|
|||
params,
|
||||
props,
|
||||
};
|
||||
|
||||
// We define a custom property, so we can check the value passed to locals
|
||||
Object.defineProperty(context, 'locals', {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return Reflect.get(request, clientLocalsSymbol);
|
||||
},
|
||||
set(val) {
|
||||
if (typeof val !== 'object') {
|
||||
throw new AstroError(AstroErrorData.LocalsNotAnObject);
|
||||
} else {
|
||||
Reflect.set(request, clientLocalsSymbol, val);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { APIContext, ComponentInstance, Params, Props, RouteData } from '../../@types/astro';
|
||||
import { renderPage as runtimeRenderPage } from '../../runtime/server/index.js';
|
||||
import type { AstroCookies, ComponentInstance, Params, Props, RouteData } from '../../@types/astro';
|
||||
import { render, renderPage as runtimeRenderPage } from '../../runtime/server/index.js';
|
||||
import { attachToResponse } from '../cookies/index.js';
|
||||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||
import type { LogOptions } from '../logger/core.js';
|
||||
|
@ -108,15 +108,15 @@ export type RenderPage = {
|
|||
mod: ComponentInstance;
|
||||
renderContext: RenderContext;
|
||||
env: Environment;
|
||||
apiContext?: APIContext;
|
||||
isCompressHTML?: boolean;
|
||||
cookies: AstroCookies;
|
||||
};
|
||||
|
||||
export async function renderPage({
|
||||
mod,
|
||||
renderContext,
|
||||
env,
|
||||
apiContext,
|
||||
cookies,
|
||||
isCompressHTML = false,
|
||||
}: RenderPage) {
|
||||
if (routeIsRedirect(renderContext.route)) {
|
||||
|
@ -133,8 +133,6 @@ export async function renderPage({
|
|||
if (!Component)
|
||||
throw new Error(`Expected an exported Astro component but received typeof ${typeof Component}`);
|
||||
|
||||
let locals = apiContext?.locals ?? {};
|
||||
|
||||
const result = createResult({
|
||||
adapterName: env.adapterName,
|
||||
links: renderContext.links,
|
||||
|
@ -155,8 +153,8 @@ export async function renderPage({
|
|||
scripts: renderContext.scripts,
|
||||
ssr: env.ssr,
|
||||
status: renderContext.status ?? 200,
|
||||
cookies: apiContext?.cookies,
|
||||
locals,
|
||||
cookies,
|
||||
locals: renderContext.locals ?? {},
|
||||
});
|
||||
|
||||
// Support `export const components` for `MDX` pages
|
||||
|
|
|
@ -180,22 +180,31 @@ export async function renderPage(options: SSROptions): Promise<Response> {
|
|||
mod,
|
||||
env,
|
||||
});
|
||||
const apiContext = createAPIContext({
|
||||
request: options.request,
|
||||
params: renderContext.params,
|
||||
props: renderContext.props,
|
||||
adapterName: options.env.adapterName,
|
||||
});
|
||||
if (options.middleware) {
|
||||
if (options.middleware && options.middleware.onRequest) {
|
||||
const apiContext = createAPIContext({
|
||||
request: options.request,
|
||||
params: renderContext.params,
|
||||
props: renderContext.props,
|
||||
adapterName: options.env.adapterName,
|
||||
});
|
||||
|
||||
const onRequest = options.middleware.onRequest as MiddlewareResponseHandler;
|
||||
const response = await callMiddleware<Response>(env.logging, onRequest, apiContext, () => {
|
||||
return coreRenderPage({ mod, renderContext, env: options.env, apiContext });
|
||||
return coreRenderPage({
|
||||
mod,
|
||||
renderContext,
|
||||
env: options.env,
|
||||
cookies: apiContext.cookies,
|
||||
});
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
return await coreRenderPage({ mod, renderContext, env: options.env }); // NOTE: without "await", errors won’t get caught below
|
||||
return await coreRenderPage({
|
||||
mod,
|
||||
renderContext,
|
||||
env: options.env,
|
||||
cookies: apiContext.cookies,
|
||||
}); // NOTE: without "await", errors won’t get caught below
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ export interface CreateRequestOptions {
|
|||
body?: RequestBody | undefined;
|
||||
logging: LogOptions;
|
||||
ssr: boolean;
|
||||
locals?: object | undefined;
|
||||
}
|
||||
|
||||
const clientAddressSymbol = Symbol.for('astro.clientAddress');
|
||||
|
@ -26,6 +27,7 @@ export function createRequest({
|
|||
body = undefined,
|
||||
logging,
|
||||
ssr,
|
||||
locals,
|
||||
}: CreateRequestOptions): Request {
|
||||
let headersObj =
|
||||
headers instanceof Headers
|
||||
|
@ -66,7 +68,7 @@ export function createRequest({
|
|||
Reflect.set(request, clientAddressSymbol, clientAddress);
|
||||
}
|
||||
|
||||
Reflect.set(request, clientLocalsSymbol, {});
|
||||
Reflect.set(request, clientLocalsSymbol, locals ?? {});
|
||||
|
||||
return request;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ import { isServerLikeOutput } from '../prerender/utils.js';
|
|||
import { log404 } from './common.js';
|
||||
import { handle404Response, writeSSRResult, writeWebResponse } from './response.js';
|
||||
|
||||
const clientLocalsSymbol = Symbol.for('astro.locals');
|
||||
|
||||
type AsyncReturnType<T extends (...args: any) => Promise<any>> = T extends (
|
||||
...args: any
|
||||
) => Promise<infer R>
|
||||
|
@ -153,6 +155,7 @@ export async function handleRoute(
|
|||
logging,
|
||||
ssr: buildingToSSR,
|
||||
clientAddress: buildingToSSR ? req.socket.remoteAddress : undefined,
|
||||
locals: Reflect.get(req, clientLocalsSymbol), // Allows adapters to pass in locals in dev mode.
|
||||
});
|
||||
|
||||
// Set user specified headers to response object.
|
||||
|
|
8
packages/astro/test/fixtures/ssr-locals/package.json
vendored
Normal file
8
packages/astro/test/fixtures/ssr-locals/package.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "@test/ssr-locals",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"astro": "workspace:*"
|
||||
}
|
||||
}
|
10
packages/astro/test/fixtures/ssr-locals/src/pages/api.js
vendored
Normal file
10
packages/astro/test/fixtures/ssr-locals/src/pages/api.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
export async function get({ locals }) {
|
||||
let out = { ...locals };
|
||||
|
||||
return new Response(JSON.stringify(out), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
4
packages/astro/test/fixtures/ssr-locals/src/pages/foo.astro
vendored
Normal file
4
packages/astro/test/fixtures/ssr-locals/src/pages/foo.astro
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
const { foo } = Astro.locals;
|
||||
---
|
||||
<h1 id="foo">{ foo }</h1>
|
40
packages/astro/test/ssr-locals.test.js
Normal file
40
packages/astro/test/ssr-locals.test.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { expect } from 'chai';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
import testAdapter from './test-adapter.js';
|
||||
|
||||
describe('SSR Astro.locals from server', () => {
|
||||
/** @type {import('./test-utils').Fixture} */
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({
|
||||
root: './fixtures/ssr-locals/',
|
||||
output: 'server',
|
||||
adapter: testAdapter(),
|
||||
});
|
||||
await fixture.build();
|
||||
});
|
||||
|
||||
it('Can access Astro.locals in page', async () => {
|
||||
const app = await fixture.loadTestAdapterApp();
|
||||
const request = new Request('http://example.com/foo');
|
||||
const locals = { foo: 'bar' };
|
||||
const response = await app.render(request, undefined, locals);
|
||||
const html = await response.text();
|
||||
|
||||
const $ = cheerio.load(html);
|
||||
expect($('#foo').text()).to.equal('bar');
|
||||
});
|
||||
|
||||
it('Can access Astro.locals in api context', async () => {
|
||||
const app = await fixture.loadTestAdapterApp();
|
||||
const request = new Request('http://example.com/api');
|
||||
const locals = { foo: 'bar' };
|
||||
const response = await app.render(request, undefined, locals);
|
||||
expect(response.status).to.equal(200);
|
||||
const body = await response.json();
|
||||
|
||||
expect(body.foo).to.equal('bar');
|
||||
});
|
||||
});
|
|
@ -34,7 +34,7 @@ export default function ({ provideAddress = true, extendAdapter } = { provideAdd
|
|||
this.#manifest = manifest;
|
||||
}
|
||||
|
||||
async render(request, routeData) {
|
||||
async render(request, routeData, locals) {
|
||||
const url = new URL(request.url);
|
||||
if(this.#manifest.assets.has(url.pathname)) {
|
||||
const filePath = new URL('../client/' + this.removeBase(url.pathname), import.meta.url);
|
||||
|
@ -42,9 +42,8 @@ export default function ({ provideAddress = true, extendAdapter } = { provideAdd
|
|||
return new Response(data);
|
||||
}
|
||||
|
||||
Reflect.set(request, Symbol.for('astro.locals'), {});
|
||||
${provideAddress ? `request[Symbol.for('astro.clientAddress')] = '0.0.0.0';` : ''}
|
||||
return super.render(request, routeData);
|
||||
return super.render(request, routeData, locals);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,25 @@ app.use(ssrHandler);
|
|||
app.listen({ port: 8080 });
|
||||
```
|
||||
|
||||
Additionally, you can also pass in an object to be accessed with `Astro.locals` or in Astro middleware:
|
||||
|
||||
```js
|
||||
import express from 'express';
|
||||
import { handler as ssrHandler } from './dist/server/entry.mjs';
|
||||
|
||||
const app = express();
|
||||
app.use(express.static('dist/client/'))
|
||||
app.use((req, res, next) => {
|
||||
const locals = {
|
||||
title: 'New title'
|
||||
};
|
||||
|
||||
ssrHandler(req, res, next, locals);
|
||||
);
|
||||
|
||||
app.listen(8080);
|
||||
```
|
||||
|
||||
Note that middleware mode does not do file serving. You'll need to configure your HTTP framework to do that for you. By default the client assets are written to `./dist/client/`.
|
||||
|
||||
### Standalone
|
||||
|
|
|
@ -9,14 +9,15 @@ export default function (app: NodeApp, mode: Options['mode']) {
|
|||
return async function (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next?: (err?: unknown) => void
|
||||
next?: (err?: unknown) => void,
|
||||
locals?: object
|
||||
) {
|
||||
try {
|
||||
const route =
|
||||
mode === 'standalone' ? app.match(req, { matchNotFound: true }) : app.match(req);
|
||||
if (route) {
|
||||
try {
|
||||
const response = await app.render(req);
|
||||
const response = await app.render(req, route, locals);
|
||||
await writeWebResponse(app, res, response);
|
||||
} catch (err: unknown) {
|
||||
if (next) {
|
||||
|
|
9
packages/integrations/node/test/fixtures/locals/package.json
vendored
Normal file
9
packages/integrations/node/test/fixtures/locals/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@test/locals",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"astro": "workspace:*",
|
||||
"@astrojs/node": "workspace:*"
|
||||
}
|
||||
}
|
10
packages/integrations/node/test/fixtures/locals/src/pages/api.js
vendored
Normal file
10
packages/integrations/node/test/fixtures/locals/src/pages/api.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
export async function post({ locals }) {
|
||||
let out = { ...locals };
|
||||
|
||||
return new Response(JSON.stringify(out), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
4
packages/integrations/node/test/fixtures/locals/src/pages/foo.astro
vendored
Normal file
4
packages/integrations/node/test/fixtures/locals/src/pages/foo.astro
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
const { foo } = Astro.locals;
|
||||
---
|
||||
<h1>{foo}</h1>
|
53
packages/integrations/node/test/locals.test.js
Normal file
53
packages/integrations/node/test/locals.test.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
import nodejs from '../dist/index.js';
|
||||
import { loadFixture, createRequestAndResponse } from './test-utils.js';
|
||||
import { expect } from 'chai';
|
||||
|
||||
describe('API routes', () => {
|
||||
/** @type {import('./test-utils').Fixture} */
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({
|
||||
root: './fixtures/locals/',
|
||||
output: 'server',
|
||||
adapter: nodejs({ mode: 'middleware' }),
|
||||
});
|
||||
await fixture.build();
|
||||
});
|
||||
|
||||
it('Can render locals in page', async () => {
|
||||
const { handler } = await import('./fixtures/locals/dist/server/entry.mjs');
|
||||
let { req, res, text } = createRequestAndResponse({
|
||||
method: 'POST',
|
||||
url: '/foo',
|
||||
});
|
||||
|
||||
let locals = { foo: 'bar' };
|
||||
|
||||
handler(req, res, () => {}, locals);
|
||||
req.send();
|
||||
|
||||
let html = await text();
|
||||
|
||||
expect(html).to.contain('<h1>bar</h1>');
|
||||
});
|
||||
|
||||
it('Can access locals in API', async () => {
|
||||
const { handler } = await import('./fixtures/locals/dist/server/entry.mjs');
|
||||
let { req, res, done } = createRequestAndResponse({
|
||||
method: 'POST',
|
||||
url: '/api',
|
||||
});
|
||||
|
||||
let locals = { foo: 'bar' };
|
||||
|
||||
handler(req, res, () => {}, locals);
|
||||
req.send();
|
||||
|
||||
let [buffer] = await done;
|
||||
|
||||
let json = JSON.parse(buffer.toString('utf-8'));
|
||||
|
||||
expect(json.foo).to.equal('bar');
|
||||
});
|
||||
});
|
|
@ -3252,6 +3252,12 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/ssr-locals:
|
||||
dependencies:
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/ssr-manifest:
|
||||
dependencies:
|
||||
astro:
|
||||
|
@ -4415,7 +4421,7 @@ importers:
|
|||
version: 9.2.2
|
||||
vite:
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1(@types/node@14.18.21)
|
||||
version: 4.3.1(@types/node@18.16.3)(sass@1.52.2)
|
||||
|
||||
packages/integrations/netlify/test/edge-functions/fixtures/dynimport:
|
||||
dependencies:
|
||||
|
@ -4550,6 +4556,15 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/node/test/fixtures/locals:
|
||||
dependencies:
|
||||
'@astrojs/node':
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../../../../astro
|
||||
|
||||
packages/integrations/node/test/fixtures/node-middleware:
|
||||
dependencies:
|
||||
'@astrojs/node':
|
||||
|
@ -4930,7 +4945,7 @@ importers:
|
|||
version: 3.0.0(vite@4.3.1)(vue@3.2.47)
|
||||
'@vue/babel-plugin-jsx':
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
version: 1.1.1(@babel/core@7.21.8)
|
||||
'@vue/compiler-sfc':
|
||||
specifier: ^3.2.39
|
||||
version: 3.2.39
|
||||
|
@ -9317,23 +9332,6 @@ packages:
|
|||
resolution: {integrity: sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==}
|
||||
dev: false
|
||||
|
||||
/@vue/babel-plugin-jsx@1.1.1:
|
||||
resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==}
|
||||
dependencies:
|
||||
'@babel/helper-module-imports': 7.21.4
|
||||
'@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.18.2)
|
||||
'@babel/template': 7.20.7
|
||||
'@babel/traverse': 7.18.2
|
||||
'@babel/types': 7.21.5
|
||||
'@vue/babel-helper-vue-transform-on': 1.0.2
|
||||
camelcase: 6.3.0
|
||||
html-tags: 3.3.1
|
||||
svg-tags: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@vue/babel-plugin-jsx@1.1.1(@babel/core@7.21.8):
|
||||
resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==}
|
||||
dependencies:
|
||||
|
@ -17665,39 +17663,6 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/vite@4.3.1(@types/node@14.18.21):
|
||||
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': '>= 14'
|
||||
less: '*'
|
||||
sass: '*'
|
||||
stylus: '*'
|
||||
sugarss: '*'
|
||||
terser: ^5.4.0
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
less:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
stylus:
|
||||
optional: true
|
||||
sugarss:
|
||||
optional: true
|
||||
terser:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/node': 14.18.21
|
||||
esbuild: 0.17.18
|
||||
postcss: 8.4.23
|
||||
rollup: 3.21.8
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/vite@4.3.1(@types/node@18.16.3)(sass@1.52.2):
|
||||
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
|
Loading…
Reference in a new issue