From 80e44a8fbb2677396c7ef557460e54979dc04f59 Mon Sep 17 00:00:00 2001 From: Roman Imankulov Date: Thu, 2 Jun 2022 08:15:38 +0100 Subject: [PATCH 01/72] docs: update Heroku deployment instructions (#7910) --- docs/guide/static-deploy.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/guide/static-deploy.md b/docs/guide/static-deploy.md index 7b732cb990cbf6..97ebae14372340 100644 --- a/docs/guide/static-deploy.md +++ b/docs/guide/static-deploy.md @@ -266,12 +266,17 @@ You can also deploy to a [custom domain](http://surge.sh/help/adding-a-custom-do # creates a new app with a specified name $ heroku apps:create example + ``` + +6. Set buildpacks. We use `heroku/nodejs` to build the project and `heroku-buildpack-static` to serve it. - # set buildpack for static sites - $ heroku buildpacks:set https://github.com/heroku/heroku-buildpack-static.git + ```bash + # set buildpacks + $ heroku buildpacks:set heroku/nodejs + $ heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static.git ``` -6. Deploy your site: +7. Deploy your site: ```bash # publish site From e9925948fd4e199625bbb25ee931bed1d50e9618 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 3 Jun 2022 22:20:03 +0800 Subject: [PATCH 02/72] feat: expose `version` (#8456) --- packages/vite/src/node/publicUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vite/src/node/publicUtils.ts b/packages/vite/src/node/publicUtils.ts index e24db763814dec..31c7135965a3d8 100644 --- a/packages/vite/src/node/publicUtils.ts +++ b/packages/vite/src/node/publicUtils.ts @@ -3,6 +3,7 @@ * This file will be bundled to ESM and CJS and redirected by ../index.cjs * Please control the side-effects by checking the ./dist/node-cjs/publicUtils.cjs bundle */ +export { VERSION as version } from './constants' export { splitVendorChunkPlugin, splitVendorChunk From d97e4022c4253c42e44483b9c88a7c2b76a713a8 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 3 Jun 2022 22:22:50 +0800 Subject: [PATCH 03/72] chore: resolve ssr options (#8455) --- packages/vite/src/node/config.ts | 28 ++++----------------- packages/vite/src/node/index.ts | 6 +++++ packages/vite/src/node/ssr/index.ts | 39 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 packages/vite/src/node/ssr/index.ts diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index d80f5a60583abc..a9e6ba33f1d0ba 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -41,6 +41,8 @@ import type { PluginContainer } from './server/pluginContainer' import { createPluginContainer } from './server/pluginContainer' import type { PackageCache } from './packages' import { loadEnv, resolveEnvPrefix } from './env' +import type { ResolvedSSROptions, SSROptions } from './ssr' +import { resolveSSROptions } from './ssr' const debug = createDebugger('vite:config') @@ -228,29 +230,6 @@ export interface ExperimentalOptions { importGlobRestoreExtension?: boolean } -export type SSRTarget = 'node' | 'webworker' - -export type SSRFormat = 'esm' | 'cjs' - -export interface SSROptions { - external?: string[] - noExternal?: string | RegExp | (string | RegExp)[] | true - /** - * Define the target for the ssr build. The browser field in package.json - * is ignored for node but used if webworker is the target - * Default: 'node' - */ - target?: SSRTarget - /** - * Define the format for the ssr build. Since Vite v3 the SSR build generates ESM by default. - * `'cjs'` can be selected to generate a CJS build, but it isn't recommended. This option is - * left marked as experimental to give users more time to update to ESM. CJS builds requires - * complex externalization heuristics that aren't present in the ESM format. - * @experimental - */ - format?: SSRFormat -} - export interface ResolveWorkerOptions { format: 'es' | 'iife' plugins: Plugin[] @@ -285,6 +264,7 @@ export type ResolvedConfig = Readonly< server: ResolvedServerOptions build: ResolvedBuildOptions preview: ResolvedPreviewOptions + ssr: ResolvedSSROptions | undefined assetsInclude: (file: string) => boolean logger: Logger createResolver: (options?: Partial) => ResolveFn @@ -491,6 +471,7 @@ export async function resolveConfig( : '' const server = resolveServerOptions(resolvedRoot, config.server, logger) + const ssr = resolveSSROptions(config.ssr) const optimizeDeps = config.optimizeDeps || {} @@ -508,6 +489,7 @@ export async function resolveConfig( cacheDir, command, mode, + ssr, isWorker: false, mainConfig: null, isProduction, diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index ff8c0ebdf6abab..2eb69befb4ee2a 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -39,6 +39,12 @@ export type { DepsOptimizer, ExportsData } from './optimizer' +export type { + ResolvedSSROptions, + SSROptions, + SSRFormat, + SSRTarget +} from './ssr' export type { Plugin } from './plugin' export type { PackageCache, PackageData } from './packages' export type { diff --git a/packages/vite/src/node/ssr/index.ts b/packages/vite/src/node/ssr/index.ts new file mode 100644 index 00000000000000..84f050ff8e41d4 --- /dev/null +++ b/packages/vite/src/node/ssr/index.ts @@ -0,0 +1,39 @@ +export type SSRTarget = 'node' | 'webworker' +export type SSRFormat = 'esm' | 'cjs' + +export interface SSROptions { + external?: string[] + noExternal?: string | RegExp | (string | RegExp)[] | true + /** + * Define the target for the ssr build. The browser field in package.json + * is ignored for node but used if webworker is the target + * Default: 'node' + */ + target?: SSRTarget + /** + * Define the format for the ssr build. Since Vite v3 the SSR build generates ESM by default. + * `'cjs'` can be selected to generate a CJS build, but it isn't recommended. This option is + * left marked as experimental to give users more time to update to ESM. CJS builds requires + * complex externalization heuristics that aren't present in the ESM format. + * @experimental + */ + format?: SSRFormat +} + +export interface ResolvedSSROptions extends SSROptions { + target: SSRTarget + format: SSRFormat +} + +export function resolveSSROptions( + ssr: SSROptions | undefined +): ResolvedSSROptions | undefined { + if (ssr === undefined) { + return undefined + } + return { + format: 'esm', + target: 'node', + ...ssr + } +} From 64fc61cf76cc62b1cafc2c3dab738c22cb7f2d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sun, 5 Jun 2022 15:04:04 +0900 Subject: [PATCH 04/72] perf: disable postcss sourcemap when unused (#8451) --- packages/vite/src/node/plugins/css.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 1fa30f6a272ddd..89bbfd6c8c46f4 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -837,15 +837,19 @@ async function compileCSS( ...postcssOptions, to: id, from: id, - map: { - inline: false, - annotation: false, - // postcss may return virtual files - // we cannot obtain content of them, so this needs to be enabled - sourcesContent: true - // when "prev: preprocessorMap", the result map may include duplicate filename in `postcssResult.map.sources` - // prev: preprocessorMap, - } + ...(devSourcemap + ? { + map: { + inline: false, + annotation: false, + // postcss may return virtual files + // we cannot obtain content of them, so this needs to be enabled + sourcesContent: true + // when "prev: preprocessorMap", the result map may include duplicate filename in `postcssResult.map.sources` + // prev: preprocessorMap, + } + } + : {}) }) // record CSS dependencies from @imports From 129b4997859e3e17bcfd40d422c4dfaecccc15cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sun, 5 Jun 2022 15:04:32 +0900 Subject: [PATCH 05/72] chore: generate vite sourcemap when not production (#8453) --- packages/vite/rollup.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/rollup.config.ts b/packages/vite/rollup.config.ts index 6759ede01d14c2..7232fa2484fff5 100644 --- a/packages/vite/rollup.config.ts +++ b/packages/vite/rollup.config.ts @@ -183,7 +183,7 @@ function createNodeConfig(isProduction: boolean) { ], plugins: createNodePlugins( isProduction, - false, + !isProduction, // in production we use api-extractor for dts generation // in development we need to rely on the rollup ts plugin isProduction ? false : path.resolve(__dirname, 'dist/node') From 1061bbdaf81c2808ed8a86946cf0e07a0d8e5b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Sun, 5 Jun 2022 15:28:10 +0900 Subject: [PATCH 06/72] fix(optimizer): external require-import conversion (fixes #2492, #3409) (#8459) --- .../src/node/optimizer/esbuildDepPlugin.ts | 28 ++++++++++++++++++- .../__tests__/optimize-deps.spec.ts | 6 +++- .../optimize-deps/dep-cjs-with-assets/foo.css | 3 ++ .../dep-cjs-with-assets/index.js | 3 ++ .../dep-cjs-with-assets/package.json | 6 ++++ .../optimize-deps/dep-linked-include/test.css | 2 +- playground/optimize-deps/index.html | 8 ++++++ playground/optimize-deps/package.json | 1 + pnpm-lock.yaml | 11 ++++++++ 9 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 playground/optimize-deps/dep-cjs-with-assets/foo.css create mode 100644 playground/optimize-deps/dep-cjs-with-assets/index.js create mode 100644 playground/optimize-deps/dep-cjs-with-assets/package.json diff --git a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts index 0c32af75219438..ee2a6e18cf04c6 100644 --- a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts +++ b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts @@ -13,6 +13,10 @@ import { import { browserExternalId } from '../plugins/resolve' import type { ExportsData } from '.' +const externalWithConversionNamespace = + 'vite:dep-pre-bundle:external-conversion' +const convertedExternalPrefix = 'vite-dep-pre-bundle-external:' + const externalTypes = [ 'css', // supported pre-processor types @@ -80,20 +84,42 @@ export function esbuildDepPlugin( name: 'vite:dep-pre-bundle', setup(build) { // externalize assets and commonly known non-js file types + // See #8459 for more details about this require-import conversion build.onResolve( { filter: new RegExp(`\\.(` + allExternalTypes.join('|') + `)(\\?.*)?$`) }, async ({ path: id, importer, kind }) => { + // if the prefix exist, it is already converted to `import`, so set `external: true` + if (id.startsWith(convertedExternalPrefix)) { + return { + path: id.slice(convertedExternalPrefix.length), + external: true + } + } + const resolved = await resolve(id, importer, kind) if (resolved) { + // here it is not set to `external: true` to convert `require` to `import` return { path: resolved, - external: true + namespace: externalWithConversionNamespace } } } ) + build.onLoad( + { filter: /./, namespace: externalWithConversionNamespace }, + (args) => { + // import itself with prefix (this is the actual part of require-import conversion) + return { + contents: + `export { default } from "${convertedExternalPrefix}${args.path}";` + + `export * from "${convertedExternalPrefix}${args.path}";`, + loader: 'js' + } + } + ) function resolveEntry(id: string) { const flatId = flattenId(id) diff --git a/playground/optimize-deps/__tests__/optimize-deps.spec.ts b/playground/optimize-deps/__tests__/optimize-deps.spec.ts index a32274dca25e0c..929455300ba555 100644 --- a/playground/optimize-deps/__tests__/optimize-deps.spec.ts +++ b/playground/optimize-deps/__tests__/optimize-deps.spec.ts @@ -77,7 +77,11 @@ test('dep with dynamic import', async () => { }) test('dep with css import', async () => { - expect(await getColor('h1')).toBe('red') + expect(await getColor('.dep-linked-include')).toBe('red') +}) + +test('CJS dep with css import', async () => { + expect(await getColor('.cjs-with-assets')).toBe('blue') }) test('dep w/ non-js files handled via plugin', async () => { diff --git a/playground/optimize-deps/dep-cjs-with-assets/foo.css b/playground/optimize-deps/dep-cjs-with-assets/foo.css new file mode 100644 index 00000000000000..8347f9fb0c358e --- /dev/null +++ b/playground/optimize-deps/dep-cjs-with-assets/foo.css @@ -0,0 +1,3 @@ +.cjs-with-assets { + color: blue; +} diff --git a/playground/optimize-deps/dep-cjs-with-assets/index.js b/playground/optimize-deps/dep-cjs-with-assets/index.js new file mode 100644 index 00000000000000..26b296af650d88 --- /dev/null +++ b/playground/optimize-deps/dep-cjs-with-assets/index.js @@ -0,0 +1,3 @@ +require('./foo.css') + +exports.a = 11 diff --git a/playground/optimize-deps/dep-cjs-with-assets/package.json b/playground/optimize-deps/dep-cjs-with-assets/package.json new file mode 100644 index 00000000000000..2e4f6e68c7510c --- /dev/null +++ b/playground/optimize-deps/dep-cjs-with-assets/package.json @@ -0,0 +1,6 @@ +{ + "name": "dep-cjs-with-assets", + "private": true, + "version": "0.0.0", + "main": "index.js" +} diff --git a/playground/optimize-deps/dep-linked-include/test.css b/playground/optimize-deps/dep-linked-include/test.css index 60f1eab97137f7..20ae3263941d1e 100644 --- a/playground/optimize-deps/dep-linked-include/test.css +++ b/playground/optimize-deps/dep-linked-include/test.css @@ -1,3 +1,3 @@ -body { +.dep-linked-include { color: red; } diff --git a/playground/optimize-deps/index.html b/playground/optimize-deps/index.html index 3cd619f9ce9236..c70ab5b2f09322 100644 --- a/playground/optimize-deps/index.html +++ b/playground/optimize-deps/index.html @@ -35,6 +35,12 @@

Detecting linked src package and optimizing its deps (lodash-es)

Optimizing force included dep even when it's linked

+

Dep with CSS

+
This should be red
+ +

CJS Dep with CSS

+
This should be blue
+

import * as ...

@@ -91,6 +97,8 @@

Reused variable names

text('.import-star', `[success] ${keys.join(', ')}`) } + import 'dep-cjs-with-assets' + import { env } from 'dep-node-env' text('.node-env', env) diff --git a/playground/optimize-deps/package.json b/playground/optimize-deps/package.json index 055d23bc9ce597..d323ca77af0a29 100644 --- a/playground/optimize-deps/package.json +++ b/playground/optimize-deps/package.json @@ -13,6 +13,7 @@ "clipboard": "^2.0.11", "dep-cjs-compiled-from-cjs": "file:./dep-cjs-compiled-from-cjs", "dep-cjs-compiled-from-esm": "file:./dep-cjs-compiled-from-esm", + "dep-cjs-with-assets": "file:./dep-cjs-with-assets", "dep-esbuild-plugin-transform": "file:./dep-esbuild-plugin-transform", "dep-linked": "link:./dep-linked", "dep-linked-include": "link:./dep-linked-include", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index acef1fe7331aef..aa07fd3c5ae874 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -576,6 +576,7 @@ importers: clipboard: ^2.0.11 dep-cjs-compiled-from-cjs: file:./dep-cjs-compiled-from-cjs dep-cjs-compiled-from-esm: file:./dep-cjs-compiled-from-esm + dep-cjs-with-assets: file:./dep-cjs-with-assets dep-esbuild-plugin-transform: file:./dep-esbuild-plugin-transform dep-linked: link:./dep-linked dep-linked-include: link:./dep-linked-include @@ -596,6 +597,7 @@ importers: clipboard: 2.0.11 dep-cjs-compiled-from-cjs: file:playground/optimize-deps/dep-cjs-compiled-from-cjs dep-cjs-compiled-from-esm: file:playground/optimize-deps/dep-cjs-compiled-from-esm + dep-cjs-with-assets: file:playground/optimize-deps/dep-cjs-with-assets dep-esbuild-plugin-transform: file:playground/optimize-deps/dep-esbuild-plugin-transform dep-linked: link:dep-linked dep-linked-include: link:dep-linked-include @@ -620,6 +622,9 @@ importers: playground/optimize-deps/dep-cjs-compiled-from-esm: specifiers: {} + playground/optimize-deps/dep-cjs-with-assets: + specifiers: {} + playground/optimize-deps/dep-esbuild-plugin-transform: specifiers: {} @@ -8810,6 +8815,12 @@ packages: version: 0.0.0 dev: false + file:playground/optimize-deps/dep-cjs-with-assets: + resolution: {directory: playground/optimize-deps/dep-cjs-with-assets, type: directory} + name: dep-cjs-with-assets + version: 0.0.0 + dev: false + file:playground/optimize-deps/dep-esbuild-plugin-transform: resolution: {directory: playground/optimize-deps/dep-esbuild-plugin-transform, type: directory} name: dep-esbuild-plugin-transform From e2e44ff32b7b2bcbcae793cdcda263d1ad495fc0 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Sun, 5 Jun 2022 18:55:45 +0800 Subject: [PATCH 07/72] feat: handle named imports of builtin modules (#8338) --- .../src/node/optimizer/esbuildDepPlugin.ts | 36 ++++++++-- .../vite/src/node/plugins/importAnalysis.ts | 69 +++++++++++++------ packages/vite/src/node/plugins/resolve.ts | 16 +++-- playground/optimize-deps/.env | 1 - .../__tests__/optimize-deps.spec.ts | 41 ++++++++++- .../dep-with-builtin-module-cjs/index.js | 18 +++++ .../dep-with-builtin-module-cjs/package.json | 6 ++ .../dep-with-builtin-module-esm/index.js | 21 ++++++ .../dep-with-builtin-module-esm/package.json | 7 ++ playground/optimize-deps/index.html | 31 +++++++++ playground/optimize-deps/package.json | 2 + playground/optimize-deps/vite.config.js | 13 ++++ pnpm-lock.yaml | 22 ++++++ 13 files changed, 244 insertions(+), 39 deletions(-) delete mode 100644 playground/optimize-deps/.env create mode 100644 playground/optimize-deps/dep-with-builtin-module-cjs/index.js create mode 100644 playground/optimize-deps/dep-with-builtin-module-cjs/package.json create mode 100644 playground/optimize-deps/dep-with-builtin-module-esm/index.js create mode 100644 playground/optimize-deps/dep-with-builtin-module-esm/package.json diff --git a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts index ee2a6e18cf04c6..fbfb658e9f7505 100644 --- a/packages/vite/src/node/optimizer/esbuildDepPlugin.ts +++ b/packages/vite/src/node/optimizer/esbuildDepPlugin.ts @@ -219,15 +219,37 @@ export function esbuildDepPlugin( build.onLoad( { filter: /.*/, namespace: 'browser-external' }, - ({ path: id }) => { + ({ path }) => { return { - contents: - `export default new Proxy({}, { - get() { - throw new Error('Module "${id}" has been externalized for ` + - `browser compatibility and cannot be accessed in client code.') + // Return in CJS to intercept named imports. Use `Object.create` to + // create the Proxy in the prototype to workaround esbuild issue. Why? + // + // In short, esbuild cjs->esm flow: + // 1. Create empty object using `Object.create(Object.getPrototypeOf(module.exports))`. + // 2. Assign props of `module.exports` to the object. + // 3. Return object for ESM use. + // + // If we do `module.exports = new Proxy({}, {})`, step 1 returns empty object, + // step 2 does nothing as there's no props for `module.exports`. The final object + // is just an empty object. + // + // Creating the Proxy in the prototype satisfies step 1 immediately, which means + // the returned object is a Proxy that we can intercept. + // + // Note: Skip keys that are accessed by esbuild and browser devtools. + contents: `\ +module.exports = Object.create(new Proxy({}, { + get(_, key) { + if ( + key !== '__esModule' && + key !== '__proto__' && + key !== 'constructor' && + key !== 'splice' + ) { + throw new Error(\`Module "${path}" has been externalized for browser compatibility. Cannot access "${path}.\${key}" in client code.\`) + } } -})` +}))` } } ) diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index ba221b4b1d5283..0c279da0601727 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -58,6 +58,7 @@ import { delayDepsOptimizerUntil } from './optimizedDeps' import { isCSSRequest, isDirectCSSRequest } from './css' +import { browserExternalId } from './resolve' const isDebug = !!process.env.DEBUG const debug = createDebugger('vite:import-analysis') @@ -322,11 +323,9 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { s: start, e: end, ss: expStart, - se: expEnd, d: dynamicIndex, // #2083 User may use escape path, // so use imports[index].n to get the unescaped string - // @ts-ignore n: specifier } = imports[index] @@ -434,29 +433,20 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { } } else if (needsInterop) { debug(`${url} needs interop`) - if (isDynamicImport) { - // rewrite `import('package')` to expose the default directly - str().overwrite( - expStart, - expEnd, - `import('${url}').then(m => m.default && m.default.__esModule ? m.default : ({ ...m.default, default: m.default }))`, - { contentOnly: true } - ) - } else { - const exp = source.slice(expStart, expEnd) - const rewritten = transformCjsImport(exp, url, rawUrl, index) - if (rewritten) { - str().overwrite(expStart, expEnd, rewritten, { - contentOnly: true - }) - } else { - // #1439 export * from '...' - str().overwrite(start, end, url, { contentOnly: true }) - } - } + interopNamedImports(str(), imports[index], url, index) rewriteDone = true } } + // If source code imports builtin modules via named imports, the stub proxy export + // would fail as it's `export default` only. Apply interop for builtin modules to + // correctly throw the error message. + else if ( + url.includes(browserExternalId) && + source.slice(expStart, start).includes('{') + ) { + interopNamedImports(str(), imports[index], url, index) + rewriteDone = true + } if (!rewriteDone) { str().overwrite(start, end, isDynamicImport ? `'${url}'` : url, { contentOnly: true @@ -639,6 +629,41 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { } } +function interopNamedImports( + str: MagicString, + importSpecifier: ImportSpecifier, + rewrittenUrl: string, + importIndex: number +) { + const source = str.original + const { + s: start, + e: end, + ss: expStart, + se: expEnd, + d: dynamicIndex + } = importSpecifier + if (dynamicIndex > -1) { + // rewrite `import('package')` to expose the default directly + str.overwrite( + expStart, + expEnd, + `import('${rewrittenUrl}').then(m => m.default && m.default.__esModule ? m.default : ({ ...m.default, default: m.default }))`, + { contentOnly: true } + ) + } else { + const exp = source.slice(expStart, expEnd) + const rawUrl = source.slice(start, end) + const rewritten = transformCjsImport(exp, rewrittenUrl, rawUrl, importIndex) + if (rewritten) { + str.overwrite(expStart, expEnd, rewritten, { contentOnly: true }) + } else { + // #1439 export * from '...' + str.overwrite(start, end, rewrittenUrl, { contentOnly: true }) + } + } +} + type ImportNameSpecifier = { importedName: string; localName: string } /** diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 33a5ad31efe5b4..7ccc3a7eb5cb7a 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -339,15 +339,17 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { load(id) { if (id.startsWith(browserExternalId)) { - return isProduction - ? `export default {}` - : `export default new Proxy({}, { - get() { - throw new Error('Module "${id.slice( - browserExternalId.length + 1 - )}" has been externalized for browser compatibility and cannot be accessed in client code.') + if (isProduction) { + return `export default {}` + } else { + id = id.slice(browserExternalId.length + 1) + return `\ +export default new Proxy({}, { + get(_, key) { + throw new Error(\`Module "${id}" has been externalized for browser compatibility. Cannot access "${id}.\${key}" in client code.\`) } })` + } } } } diff --git a/playground/optimize-deps/.env b/playground/optimize-deps/.env deleted file mode 100644 index 995fca4af2ee24..00000000000000 --- a/playground/optimize-deps/.env +++ /dev/null @@ -1 +0,0 @@ -NODE_ENV=production \ No newline at end of file diff --git a/playground/optimize-deps/__tests__/optimize-deps.spec.ts b/playground/optimize-deps/__tests__/optimize-deps.spec.ts index 929455300ba555..bf4fee61e4e74c 100644 --- a/playground/optimize-deps/__tests__/optimize-deps.spec.ts +++ b/playground/optimize-deps/__tests__/optimize-deps.spec.ts @@ -1,4 +1,11 @@ -import { getColor, page } from '~utils' +import { + browserErrors, + browserLogs, + getColor, + isBuild, + isServe, + page +} from '~utils' test('default + named imports from cjs dep (react)', async () => { expect(await page.textContent('.cjs button')).toBe('count is 0') @@ -63,7 +70,7 @@ test('import * from optimized dep', async () => { }) test('import from dep with process.env.NODE_ENV', async () => { - expect(await page.textContent('.node-env')).toMatch(`prod`) + expect(await page.textContent('.node-env')).toMatch(isBuild ? 'prod' : 'dev') }) test('import from dep with .notjs files', async () => { @@ -113,3 +120,33 @@ test('import aliased package with colon', async () => { test('variable names are reused in different scripts', async () => { expect(await page.textContent('.reused-variable-names')).toBe('reused') }) + +test.runIf(isServe)('error on builtin modules usage', () => { + expect(browserLogs).toEqual( + expect.arrayContaining([ + // from dep-with-builtin-module-esm top-level try-catch + expect.stringContaining( + 'dep-with-builtin-module-esm Error: Module "fs" has been externalized for browser compatibility. Cannot access "fs.readFileSync" in client code.' + ), + expect.stringContaining( + 'dep-with-builtin-module-esm Error: Module "path" has been externalized for browser compatibility. Cannot access "path.join" in client code.' + ), + // from dep-with-builtin-module-cjs top-level try-catch + expect.stringContaining( + 'dep-with-builtin-module-cjs Error: Module "path" has been externalized for browser compatibility. Cannot access "path.join" in client code.' + ) + ]) + ) + + expect(browserErrors.map((error) => error.message)).toEqual( + expect.arrayContaining([ + // from user source code + 'Module "buffer" has been externalized for browser compatibility. Cannot access "buffer.Buffer" in client code.', + 'Module "child_process" has been externalized for browser compatibility. Cannot access "child_process.execSync" in client code.', + // from dep-with-builtin-module-esm read() + 'Module "fs" has been externalized for browser compatibility. Cannot access "fs.readFileSync" in client code.', + // from dep-with-builtin-module-esm read() + 'Module "fs" has been externalized for browser compatibility. Cannot access "fs.readFileSync" in client code.' + ]) + ) +}) diff --git a/playground/optimize-deps/dep-with-builtin-module-cjs/index.js b/playground/optimize-deps/dep-with-builtin-module-cjs/index.js new file mode 100644 index 00000000000000..920a0da0d97dda --- /dev/null +++ b/playground/optimize-deps/dep-with-builtin-module-cjs/index.js @@ -0,0 +1,18 @@ +const fs = require('fs') +const path = require('path') + +// NOTE: require destructure would error immediately because of how esbuild +// compiles it. There's no way around it as it's direct property access, which +// triggers the Proxy get trap. + +// access from default import +try { + path.join() +} catch (e) { + console.log('dep-with-builtin-module-cjs', e) +} + +// access from function +module.exports.read = () => { + return fs.readFileSync('test') +} diff --git a/playground/optimize-deps/dep-with-builtin-module-cjs/package.json b/playground/optimize-deps/dep-with-builtin-module-cjs/package.json new file mode 100644 index 00000000000000..8b39306140e804 --- /dev/null +++ b/playground/optimize-deps/dep-with-builtin-module-cjs/package.json @@ -0,0 +1,6 @@ +{ + "name": "dep-with-builtin-module-cjs", + "private": true, + "version": "0.0.0", + "main": "index.js" +} diff --git a/playground/optimize-deps/dep-with-builtin-module-esm/index.js b/playground/optimize-deps/dep-with-builtin-module-esm/index.js new file mode 100644 index 00000000000000..e3734720051aca --- /dev/null +++ b/playground/optimize-deps/dep-with-builtin-module-esm/index.js @@ -0,0 +1,21 @@ +import { readFileSync } from 'fs' +import path from 'path' + +// access from named import +try { + readFileSync() +} catch (e) { + console.log('dep-with-builtin-module-esm', e) +} + +// access from default import +try { + path.join() +} catch (e) { + console.log('dep-with-builtin-module-esm', e) +} + +// access from function +export function read() { + return readFileSync('test') +} diff --git a/playground/optimize-deps/dep-with-builtin-module-esm/package.json b/playground/optimize-deps/dep-with-builtin-module-esm/package.json new file mode 100644 index 00000000000000..e01897e5a51850 --- /dev/null +++ b/playground/optimize-deps/dep-with-builtin-module-esm/package.json @@ -0,0 +1,7 @@ +{ + "name": "dep-with-builtin-module-esm", + "private": true, + "version": "0.0.0", + "main": "index.js", + "type": "module" +} diff --git a/playground/optimize-deps/index.html b/playground/optimize-deps/index.html index c70ab5b2f09322..39d76fd83d0609 100644 --- a/playground/optimize-deps/index.html +++ b/playground/optimize-deps/index.html @@ -138,3 +138,34 @@

Reused variable names

const reusedName = 'reused' text('.reused-variable-names', reusedName) + + + + + + + + diff --git a/playground/optimize-deps/package.json b/playground/optimize-deps/package.json index d323ca77af0a29..7509b8284b9bc1 100644 --- a/playground/optimize-deps/package.json +++ b/playground/optimize-deps/package.json @@ -19,6 +19,8 @@ "dep-linked-include": "link:./dep-linked-include", "dep-node-env": "file:./dep-node-env", "dep-not-js": "file:./dep-not-js", + "dep-with-builtin-module-cjs": "file:./dep-with-builtin-module-cjs", + "dep-with-builtin-module-esm": "file:./dep-with-builtin-module-esm", "dep-with-dynamic-import": "file:./dep-with-dynamic-import", "lodash-es": "^4.17.21", "nested-exclude": "file:./nested-exclude", diff --git a/playground/optimize-deps/vite.config.js b/playground/optimize-deps/vite.config.js index fb3bbfc4a33eb5..d5da62f3331fc2 100644 --- a/playground/optimize-deps/vite.config.js +++ b/playground/optimize-deps/vite.config.js @@ -62,6 +62,19 @@ module.exports = { return { code } } } + }, + // TODO: Remove this one support for prebundling in build lands. + // It is expected that named importing in build doesn't work + // as it incurs a lot of overhead in build. + { + name: 'polyfill-named-fs-build', + apply: 'build', + enforce: 'pre', + load(id) { + if (id === '__vite-browser-external:fs') { + return `export default {}; export function readFileSync() {}` + } + } } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa07fd3c5ae874..5e2530f0dafc6b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -582,6 +582,8 @@ importers: dep-linked-include: link:./dep-linked-include dep-node-env: file:./dep-node-env dep-not-js: file:./dep-not-js + dep-with-builtin-module-cjs: file:./dep-with-builtin-module-cjs + dep-with-builtin-module-esm: file:./dep-with-builtin-module-esm dep-with-dynamic-import: file:./dep-with-dynamic-import lodash-es: ^4.17.21 nested-exclude: file:./nested-exclude @@ -603,6 +605,8 @@ importers: dep-linked-include: link:dep-linked-include dep-node-env: file:playground/optimize-deps/dep-node-env dep-not-js: file:playground/optimize-deps/dep-not-js + dep-with-builtin-module-cjs: file:playground/optimize-deps/dep-with-builtin-module-cjs + dep-with-builtin-module-esm: file:playground/optimize-deps/dep-with-builtin-module-esm dep-with-dynamic-import: file:playground/optimize-deps/dep-with-dynamic-import lodash-es: 4.17.21 nested-exclude: file:playground/optimize-deps/nested-exclude @@ -646,6 +650,12 @@ importers: playground/optimize-deps/dep-not-js: specifiers: {} + playground/optimize-deps/dep-with-builtin-module-cjs: + specifiers: {} + + playground/optimize-deps/dep-with-builtin-module-esm: + specifiers: {} + playground/optimize-deps/dep-with-dynamic-import: specifiers: {} @@ -8839,6 +8849,18 @@ packages: version: 1.0.0 dev: false + file:playground/optimize-deps/dep-with-builtin-module-cjs: + resolution: {directory: playground/optimize-deps/dep-with-builtin-module-cjs, type: directory} + name: dep-with-builtin-module-cjs + version: 0.0.0 + dev: false + + file:playground/optimize-deps/dep-with-builtin-module-esm: + resolution: {directory: playground/optimize-deps/dep-with-builtin-module-esm, type: directory} + name: dep-with-builtin-module-esm + version: 0.0.0 + dev: false + file:playground/optimize-deps/dep-with-dynamic-import: resolution: {directory: playground/optimize-deps/dep-with-dynamic-import, type: directory} name: dep-with-dynamic-import From 908c9e4cdd2cceb0f01495e38066ffe33c21ddb8 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Sun, 5 Jun 2022 18:58:48 +0800 Subject: [PATCH 08/72] feat: preserve process env vars in lib build (#8090) --- packages/vite/src/node/plugins/define.ts | 44 ++++++++++++------------ playground/lib/__tests__/lib.spec.ts | 28 +++++++-------- playground/lib/index.dist.html | 9 +++++ playground/lib/src/main.js | 3 ++ 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index ca0f446cc1f58e..6edb1bd8858a11 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -10,15 +10,23 @@ const isNonJsRequest = (request: string): boolean => nonJsRe.test(request) export function definePlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' - - const processNodeEnv: Record = { - 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || config.mode), - 'global.process.env.NODE_ENV': JSON.stringify( - process.env.NODE_ENV || config.mode - ), - 'globalThis.process.env.NODE_ENV': JSON.stringify( - process.env.NODE_ENV || config.mode - ) + const isBuildLib = isBuild && config.build.lib + + // ignore replace process.env in lib build + const processEnv: Record = {} + const processNodeEnv: Record = {} + if (!isBuildLib) { + const nodeEnv = process.env.NODE_ENV || config.mode + Object.assign(processEnv, { + 'process.env.': `({}).`, + 'global.process.env.': `({}).`, + 'globalThis.process.env.': `({}).` + }) + Object.assign(processNodeEnv, { + 'process.env.NODE_ENV': JSON.stringify(nodeEnv), + 'global.process.env.NODE_ENV': JSON.stringify(nodeEnv), + 'globalThis.process.env.NODE_ENV': JSON.stringify(nodeEnv) + }) } const userDefine: Record = {} @@ -27,7 +35,8 @@ export function definePlugin(config: ResolvedConfig): Plugin { userDefine[key] = typeof val === 'string' ? val : JSON.stringify(val) } - // during dev, import.meta properties are handled by importAnalysis plugin + // during dev, import.meta properties are handled by importAnalysis plugin. + // ignore replace import.meta.env in lib build const importMetaKeys: Record = {} if (isBuild) { const env: Record = { @@ -47,22 +56,13 @@ export function definePlugin(config: ResolvedConfig): Plugin { function generatePattern( ssr: boolean ): [Record, RegExp | null] { - const processEnv: Record = {} - const isNeedProcessEnv = !ssr || config.ssr?.target === 'webworker' - - if (isNeedProcessEnv) { - Object.assign(processEnv, { - 'process.env.': `({}).`, - 'global.process.env.': `({}).`, - 'globalThis.process.env.': `({}).` - }) - } + const replaceProcessEnv = !ssr || config.ssr?.target === 'webworker' const replacements: Record = { - ...(isNeedProcessEnv ? processNodeEnv : {}), + ...(replaceProcessEnv ? processNodeEnv : {}), ...userDefine, ...importMetaKeys, - ...processEnv + ...(replaceProcessEnv ? processEnv : {}) } const replacementsKeys = Object.keys(replacements) diff --git a/playground/lib/__tests__/lib.spec.ts b/playground/lib/__tests__/lib.spec.ts index 32c6edba1bdeb9..9046097f7e8375 100644 --- a/playground/lib/__tests__/lib.spec.ts +++ b/playground/lib/__tests__/lib.spec.ts @@ -1,11 +1,9 @@ -import path from 'path' -import fs from 'fs' import { isBuild, isServe, page, + readFile, serverLogs, - testDir, untilUpdated } from '~utils' @@ -16,20 +14,14 @@ describe.runIf(isBuild)('build', () => { test('umd', async () => { expect(await page.textContent('.umd')).toBe('It works') - const code = fs.readFileSync( - path.join(testDir, 'dist/my-lib-custom-filename.umd.js'), - 'utf-8' - ) + const code = readFile('dist/my-lib-custom-filename.umd.js') // esbuild helpers are injected inside of the UMD wrapper expect(code).toMatch(/^\(function\(/) }) test('iife', async () => { expect(await page.textContent('.iife')).toBe('It works') - const code = fs.readFileSync( - path.join(testDir, 'dist/my-lib-custom-filename.iife.js'), - 'utf-8' - ) + const code = readFile('dist/my-lib-custom-filename.iife.js') // esbuild helpers are injected inside of the IIFE wrapper expect(code).toMatch(/^const MyLib=function\(\){"use strict";/) }) @@ -39,10 +31,7 @@ describe.runIf(isBuild)('build', () => { () => page.textContent('.dynamic-import-message'), 'hello vite' ) - const code = fs.readFileSync( - path.join(testDir, 'dist/lib/dynamic-import-message.es.mjs'), - 'utf-8' - ) + const code = readFile('dist/lib/dynamic-import-message.es.mjs') expect(code).not.toMatch('__vitePreload') // Test that library chunks are hashed @@ -55,6 +44,15 @@ describe.runIf(isBuild)('build', () => { expect(log).not.toMatch('All "@import" rules must come first') }) }) + + test('preserve process.env', () => { + const es = readFile('dist/my-lib-custom-filename.mjs') + const iife = readFile('dist/my-lib-custom-filename.iife.js') + const umd = readFile('dist/my-lib-custom-filename.umd.js') + expect(es).toMatch('process.env.NODE_ENV') + expect(iife).toMatch('process.env.NODE_ENV') + expect(umd).toMatch('process.env.NODE_ENV') + }) }) test.runIf(isServe)('dev', async () => { diff --git a/playground/lib/index.dist.html b/playground/lib/index.dist.html index 02362a9c111e5e..99f08c73396fea 100644 --- a/playground/lib/index.dist.html +++ b/playground/lib/index.dist.html @@ -4,6 +4,15 @@
+ + -

This is child content

+

Vite + Lit

diff --git a/packages/create-vite/template-lit-ts/public/vite.svg b/packages/create-vite/template-lit-ts/public/vite.svg new file mode 100644 index 00000000000000..e7b8dfb1b2a60b --- /dev/null +++ b/packages/create-vite/template-lit-ts/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-lit-ts/src/assets/lit.svg b/packages/create-vite/template-lit-ts/src/assets/lit.svg new file mode 100644 index 00000000000000..4a9c1fe662ea4e --- /dev/null +++ b/packages/create-vite/template-lit-ts/src/assets/lit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-lit-ts/src/favicon.svg b/packages/create-vite/template-lit-ts/src/favicon.svg deleted file mode 100644 index de4aeddc12bdfe..00000000000000 --- a/packages/create-vite/template-lit-ts/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/create-vite/template-lit-ts/src/index.css b/packages/create-vite/template-lit-ts/src/index.css new file mode 100644 index 00000000000000..d39ac2e34eebe8 --- /dev/null +++ b/packages/create-vite/template-lit-ts/src/index.css @@ -0,0 +1,40 @@ +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } +} diff --git a/packages/create-vite/template-lit-ts/src/my-element.ts b/packages/create-vite/template-lit-ts/src/my-element.ts index c7fd4c6d6982f4..2808d30ae6ef66 100644 --- a/packages/create-vite/template-lit-ts/src/my-element.ts +++ b/packages/create-vite/template-lit-ts/src/my-element.ts @@ -1,5 +1,7 @@ import { html, css, LitElement } from 'lit' import { customElement, property } from 'lit/decorators.js' +import viteLogo from '/vite.svg' +import litLogo from './assets/lit.svg' /** * An example element. @@ -9,20 +11,11 @@ import { customElement, property } from 'lit/decorators.js' */ @customElement('my-element') export class MyElement extends LitElement { - static styles = css` - :host { - display: block; - border: solid 1px gray; - padding: 16px; - max-width: 800px; - } - ` - /** - * The name to say "Hello" to. + * Copy for the read the docs hint. */ @property() - name = 'World' + docsHint = 'Click on the Vite and Lit logos to learn more' /** * The number of times the button has been clicked. @@ -32,11 +25,21 @@ export class MyElement extends LitElement { render() { return html` -

Hello, ${this.name}!

- +
+ + +
+
+ +
+

${this.docsHint}

` } @@ -44,9 +47,71 @@ export class MyElement extends LitElement { this.count++ } - foo(): string { - return 'foo' - } + static styles = css` + :host { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; + } + + .logo { + height: 6em; + padding: 1.5em; + } + .logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); + } + + .card { + padding: 2em; + } + + .read-the-docs { + color: #888; + } + + h1 { + font-size: 3.2em; + } + + a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; + } + a:hover { + color: #535bf2; + } + + button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; + } + button:hover { + border-color: #646cff; + } + button:focus, + button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; + } + + @media (prefers-color-scheme: light) { + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } + } + ` } declare global { diff --git a/packages/create-vite/template-lit/index.html b/packages/create-vite/template-lit/index.html index 2c9742f1c3bcff..e8be0205b1d8cf 100644 --- a/packages/create-vite/template-lit/index.html +++ b/packages/create-vite/template-lit/index.html @@ -2,14 +2,15 @@ - + - Vite + Lit App + Vite + Lit + -

This is child content

+

Vite + Lit

diff --git a/packages/create-vite/template-lit/public/vite.svg b/packages/create-vite/template-lit/public/vite.svg new file mode 100644 index 00000000000000..e7b8dfb1b2a60b --- /dev/null +++ b/packages/create-vite/template-lit/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-lit/src/assets/lit.svg b/packages/create-vite/template-lit/src/assets/lit.svg new file mode 100644 index 00000000000000..4a9c1fe662ea4e --- /dev/null +++ b/packages/create-vite/template-lit/src/assets/lit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-lit/src/favicon.svg b/packages/create-vite/template-lit/src/favicon.svg deleted file mode 100644 index de4aeddc12bdfe..00000000000000 --- a/packages/create-vite/template-lit/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/create-vite/template-lit/src/index.css b/packages/create-vite/template-lit/src/index.css new file mode 100644 index 00000000000000..b52d4c639b5e5f --- /dev/null +++ b/packages/create-vite/template-lit/src/index.css @@ -0,0 +1,31 @@ +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } +} diff --git a/packages/create-vite/template-lit/src/my-element.js b/packages/create-vite/template-lit/src/my-element.js index 83b11fa869c26c..6ca0dab47b3a3f 100644 --- a/packages/create-vite/template-lit/src/my-element.js +++ b/packages/create-vite/template-lit/src/my-element.js @@ -1,4 +1,6 @@ import { html, css, LitElement } from 'lit' +import viteLogo from '/vite.svg' +import litLogo from './assets/lit.svg' /** * An example element. @@ -7,23 +9,12 @@ import { html, css, LitElement } from 'lit' * @csspart button - The button */ export class MyElement extends LitElement { - static get styles() { - return css` - :host { - display: block; - border: solid 1px gray; - padding: 16px; - max-width: 800px; - } - ` - } - static get properties() { return { /** - * The name to say "Hello" to. + * Copy for the read the docs hint. */ - name: { type: String }, + docsHint: { type: String }, /** * The number of times the button has been clicked. @@ -34,23 +25,101 @@ export class MyElement extends LitElement { constructor() { super() - this.name = 'World' + this.docsHint = 'Click on the Vite and Lit logos to learn more' this.count = 0 } render() { return html` -

Hello, ${this.name}!

- +
+ + +
+
+ +
+

${this.docsHint}

` } _onClick() { this.count++ } + + static get styles() { + return css` + :host { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; + } + + .logo { + height: 6em; + padding: 1.5em; + } + .logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); + } + + .card { + padding: 2em; + } + + .read-the-docs { + color: #888; + } + + a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; + } + a:hover { + color: #535bf2; + } + + h1 { + font-size: 3.2em; + } + + button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; + } + button:hover { + border-color: #646cff; + } + button:focus, + button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; + } + + @media (prefers-color-scheme: light) { + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } + } + ` + } } window.customElements.define('my-element', MyElement) diff --git a/packages/create-vite/template-preact-ts/index.html b/packages/create-vite/template-preact-ts/index.html index 5dd45a1e2ab404..ed0f5bbd72520b 100644 --- a/packages/create-vite/template-preact-ts/index.html +++ b/packages/create-vite/template-preact-ts/index.html @@ -2,9 +2,9 @@ - + - Vite App + Vite + Preact + TS
diff --git a/packages/create-vite/template-preact-ts/public/vite.svg b/packages/create-vite/template-preact-ts/public/vite.svg new file mode 100644 index 00000000000000..e7b8dfb1b2a60b --- /dev/null +++ b/packages/create-vite/template-preact-ts/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-preact-ts/src/app.css b/packages/create-vite/template-preact-ts/src/app.css new file mode 100644 index 00000000000000..9e9f9c9c6884c9 --- /dev/null +++ b/packages/create-vite/template-preact-ts/src/app.css @@ -0,0 +1,22 @@ +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/packages/create-vite/template-preact-ts/src/app.tsx b/packages/create-vite/template-preact-ts/src/app.tsx index 64fe3eda94c933..db652c2630f10b 100644 --- a/packages/create-vite/template-preact-ts/src/app.tsx +++ b/packages/create-vite/template-preact-ts/src/app.tsx @@ -1,19 +1,32 @@ -import { Logo } from './logo' +import { useState } from 'preact/hooks' +import viteLogo from '/vite.svg' +import preactLogo from './assets/preact.svg' +import './app.css' export function App() { + const [count, setCount] = useState(0) + return ( <> - -

Hello Vite + Preact!

-

- - Learn Preact +

+

Vite + Preact

+
+ +

+ Edit src/app.tsx and save to test HMR +

+
+

+ Click on the Vite and Preact logos to learn more

) diff --git a/packages/create-vite/template-preact-ts/src/assets/preact.svg b/packages/create-vite/template-preact-ts/src/assets/preact.svg new file mode 100644 index 00000000000000..908f17def0b5a4 --- /dev/null +++ b/packages/create-vite/template-preact-ts/src/assets/preact.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-preact-ts/src/favicon.svg b/packages/create-vite/template-preact-ts/src/favicon.svg deleted file mode 100644 index de4aeddc12bdfe..00000000000000 --- a/packages/create-vite/template-preact-ts/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/create-vite/template-preact-ts/src/index.css b/packages/create-vite/template-preact-ts/src/index.css index 3d36f1648343ec..dbc2fdd562ab3b 100644 --- a/packages/create-vite/template-preact-ts/src/index.css +++ b/packages/create-vite/template-preact-ts/src/index.css @@ -1,30 +1,69 @@ -html, -body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - background: #fafafa; - font-family: 'Helvetica Neue', arial, sans-serif; +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; font-weight: 400; - color: #444; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; } -* { - box-sizing: border-box; +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; } -#app { - height: 100%; - text-align: center; - background-color: #673ab8; - color: #fff; - font-size: 1.5em; - padding-top: 100px; +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; } -.link { - color: #fff; +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } } diff --git a/packages/create-vite/template-preact-ts/src/logo.tsx b/packages/create-vite/template-preact-ts/src/logo.tsx deleted file mode 100644 index dee6f347a90a54..00000000000000 --- a/packages/create-vite/template-preact-ts/src/logo.tsx +++ /dev/null @@ -1,47 +0,0 @@ -export const Logo = () => ( - -) diff --git a/packages/create-vite/template-preact/index.html b/packages/create-vite/template-preact/index.html index c06e9fce67a28f..9f89c1bcc0ddef 100644 --- a/packages/create-vite/template-preact/index.html +++ b/packages/create-vite/template-preact/index.html @@ -2,9 +2,9 @@ - + - Vite App + Vite + Preact
diff --git a/packages/create-vite/template-preact/public/vite.svg b/packages/create-vite/template-preact/public/vite.svg new file mode 100644 index 00000000000000..e7b8dfb1b2a60b --- /dev/null +++ b/packages/create-vite/template-preact/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-preact/src/app.css b/packages/create-vite/template-preact/src/app.css new file mode 100644 index 00000000000000..9e9f9c9c6884c9 --- /dev/null +++ b/packages/create-vite/template-preact/src/app.css @@ -0,0 +1,22 @@ +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/packages/create-vite/template-preact/src/app.jsx b/packages/create-vite/template-preact/src/app.jsx index 64fe3eda94c933..c2ce201061e5bd 100644 --- a/packages/create-vite/template-preact/src/app.jsx +++ b/packages/create-vite/template-preact/src/app.jsx @@ -1,19 +1,32 @@ -import { Logo } from './logo' +import { useState } from 'preact/hooks' +import viteLogo from '/vite.svg' +import preactLogo from './assets/preact.svg' +import './app.css' export function App() { + const [count, setCount] = useState(0) + return ( <> - -

Hello Vite + Preact!

-

- - Learn Preact +

+

Vite + Preact

+
+ +

+ Edit src/app.jsx and save to test HMR +

+
+

+ Click on the Vite and Preact logos to learn more

) diff --git a/packages/create-vite/template-preact/src/assets/preact.svg b/packages/create-vite/template-preact/src/assets/preact.svg new file mode 100644 index 00000000000000..908f17def0b5a4 --- /dev/null +++ b/packages/create-vite/template-preact/src/assets/preact.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-preact/src/favicon.svg b/packages/create-vite/template-preact/src/favicon.svg deleted file mode 100644 index de4aeddc12bdfe..00000000000000 --- a/packages/create-vite/template-preact/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/create-vite/template-preact/src/index.css b/packages/create-vite/template-preact/src/index.css index 3d36f1648343ec..dbc2fdd562ab3b 100644 --- a/packages/create-vite/template-preact/src/index.css +++ b/packages/create-vite/template-preact/src/index.css @@ -1,30 +1,69 @@ -html, -body { - height: 100%; - width: 100%; - padding: 0; - margin: 0; - background: #fafafa; - font-family: 'Helvetica Neue', arial, sans-serif; +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; font-weight: 400; - color: #444; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; } -* { - box-sizing: border-box; +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; } -#app { - height: 100%; - text-align: center; - background-color: #673ab8; - color: #fff; - font-size: 1.5em; - padding-top: 100px; +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; } -.link { - color: #fff; +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } } diff --git a/packages/create-vite/template-preact/src/logo.jsx b/packages/create-vite/template-preact/src/logo.jsx deleted file mode 100644 index dee6f347a90a54..00000000000000 --- a/packages/create-vite/template-preact/src/logo.jsx +++ /dev/null @@ -1,47 +0,0 @@ -export const Logo = () => ( - -) diff --git a/packages/create-vite/template-react-ts/index.html b/packages/create-vite/template-react-ts/index.html index 38f386110323c3..e0d1c840806ee7 100644 --- a/packages/create-vite/template-react-ts/index.html +++ b/packages/create-vite/template-react-ts/index.html @@ -2,9 +2,9 @@ - + - Vite App + Vite + React + TS
diff --git a/packages/create-vite/template-react-ts/public/vite.svg b/packages/create-vite/template-react-ts/public/vite.svg new file mode 100644 index 00000000000000..e7b8dfb1b2a60b --- /dev/null +++ b/packages/create-vite/template-react-ts/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-react-ts/src/App.css b/packages/create-vite/template-react-ts/src/App.css index 8da3fde63d9e7d..2e82675c3c44a9 100644 --- a/packages/create-vite/template-react-ts/src/App.css +++ b/packages/create-vite/template-react-ts/src/App.css @@ -1,34 +1,19 @@ -.App { +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; text-align: center; } -.App-logo { - height: 40vmin; - pointer-events: none; +.logo { + height: 6em; + padding: 1.5em; } - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); } -@keyframes App-logo-spin { +@keyframes logo-spin { from { transform: rotate(0deg); } @@ -37,6 +22,16 @@ } } -button { - font-size: calc(10px + 2vmin); +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; } diff --git a/packages/create-vite/template-react-ts/src/App.tsx b/packages/create-vite/template-react-ts/src/App.tsx index 3d9bd71e51303e..8cfb82d3fbf3c2 100644 --- a/packages/create-vite/template-react-ts/src/App.tsx +++ b/packages/create-vite/template-react-ts/src/App.tsx @@ -1,5 +1,6 @@ import { useState } from 'react' -import logo from './logo.svg' +import viteLogo from '/vite.svg' +import reactLogo from './assets/react.svg' import './App.css' function App() { @@ -7,37 +8,26 @@ function App() { return (
-
- logo -

Hello Vite + React!

+ +

Vite + React

+
+

- + Edit src/App.tsx and save to test HMR

-

- Edit App.tsx and save to test HMR updates. -

-

- - Learn React - - {' | '} - - Vite Docs - -

-
+
+

+ Click on the Vite and React logos to learn more +

) } diff --git a/packages/create-vite/template-react-ts/src/assets/react.svg b/packages/create-vite/template-react-ts/src/assets/react.svg new file mode 100644 index 00000000000000..6c87de9bb33584 --- /dev/null +++ b/packages/create-vite/template-react-ts/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-react-ts/src/favicon.svg b/packages/create-vite/template-react-ts/src/favicon.svg deleted file mode 100644 index de4aeddc12bdfe..00000000000000 --- a/packages/create-vite/template-react-ts/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/create-vite/template-react-ts/src/index.css b/packages/create-vite/template-react-ts/src/index.css index ec2585e8c0bb81..dbc2fdd562ab3b 100644 --- a/packages/create-vite/template-react-ts/src/index.css +++ b/packages/create-vite/template-react-ts/src/index.css @@ -1,13 +1,69 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; } -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } } diff --git a/packages/create-vite/template-react-ts/src/logo.svg b/packages/create-vite/template-react-ts/src/logo.svg deleted file mode 100644 index 6b60c1042f58d9..00000000000000 --- a/packages/create-vite/template-react-ts/src/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/create-vite/template-react/index.html b/packages/create-vite/template-react/index.html index b46ab83364e374..79c470191164e9 100644 --- a/packages/create-vite/template-react/index.html +++ b/packages/create-vite/template-react/index.html @@ -2,9 +2,9 @@ - + - Vite App + Vite + React
diff --git a/packages/create-vite/template-react/public/vite.svg b/packages/create-vite/template-react/public/vite.svg new file mode 100644 index 00000000000000..e7b8dfb1b2a60b --- /dev/null +++ b/packages/create-vite/template-react/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-react/src/App.css b/packages/create-vite/template-react/src/App.css index 8da3fde63d9e7d..2e82675c3c44a9 100644 --- a/packages/create-vite/template-react/src/App.css +++ b/packages/create-vite/template-react/src/App.css @@ -1,34 +1,19 @@ -.App { +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; text-align: center; } -.App-logo { - height: 40vmin; - pointer-events: none; +.logo { + height: 6em; + padding: 1.5em; } - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); } -@keyframes App-logo-spin { +@keyframes logo-spin { from { transform: rotate(0deg); } @@ -37,6 +22,16 @@ } } -button { - font-size: calc(10px + 2vmin); +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; } diff --git a/packages/create-vite/template-react/src/App.jsx b/packages/create-vite/template-react/src/App.jsx index 7d4eb10ff833d1..78ced9c794224d 100644 --- a/packages/create-vite/template-react/src/App.jsx +++ b/packages/create-vite/template-react/src/App.jsx @@ -1,5 +1,6 @@ import { useState } from 'react' -import logo from './logo.svg' +import viteLogo from '/vite.svg' +import reactLogo from './assets/react.svg' import './App.css' function App() { @@ -7,37 +8,26 @@ function App() { return (
-
- logo -

Hello Vite + React!

+ +

Vite + React

+
+

- + Edit src/App.jsx and save to test HMR

-

- Edit App.jsx and save to test HMR updates. -

-

- - Learn React - - {' | '} - - Vite Docs - -

-
+
+

+ Click on the Vite and React logos to learn more +

) } diff --git a/packages/create-vite/template-react/src/assets/react.svg b/packages/create-vite/template-react/src/assets/react.svg new file mode 100644 index 00000000000000..6c87de9bb33584 --- /dev/null +++ b/packages/create-vite/template-react/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/create-vite/template-react/src/favicon.svg b/packages/create-vite/template-react/src/favicon.svg deleted file mode 100644 index de4aeddc12bdfe..00000000000000 --- a/packages/create-vite/template-react/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/create-vite/template-react/src/index.css b/packages/create-vite/template-react/src/index.css index ec2585e8c0bb81..dbc2fdd562ab3b 100644 --- a/packages/create-vite/template-react/src/index.css +++ b/packages/create-vite/template-react/src/index.css @@ -1,13 +1,69 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; } -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } } diff --git a/packages/create-vite/template-react/src/logo.svg b/packages/create-vite/template-react/src/logo.svg deleted file mode 100644 index 6b60c1042f58d9..00000000000000 --- a/packages/create-vite/template-react/src/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/create-vite/template-svelte-ts/index.html b/packages/create-vite/template-svelte-ts/index.html index d2f6839bab176c..b5b125269662aa 100644 --- a/packages/create-vite/template-svelte-ts/index.html +++ b/packages/create-vite/template-svelte-ts/index.html @@ -2,9 +2,9 @@ - + - Svelte + TS + Vite App + Vite + Svelte + TS
diff --git a/packages/create-vite/template-svelte-ts/public/favicon.ico b/packages/create-vite/template-svelte-ts/public/favicon.ico deleted file mode 100644 index d75d248ef0b15096a95054643a4d97f5d9b60846..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmaKqSxA*Z7>4KMS_;~x;8i!JU{-`tpyx!I(n2NFMU)w2L{WiMS3#Lcp@vrpA*5Yp zSy6|`AkYfDD(e{`n8yX0pLf20X1@3RmKkGw`Vte3=0)aUq%ldx zm^49K+Hw0b#^`KboP)QXJOwbuVUFxlAs{RfqJ+twGylWfOp{Hc$s#253LlN1nsFVc zKa>40?h5(7PTC6ltDx)(Y&Ze2xggCq(kK? zTA`;gAfKD!+uFjpxc_A3+Ma(L28W=z4Gvs@r*ECk`;c45=S#;=oA|abt`f&j5&uJO z3Dn+&^gZ%h4JidsaTR{{!_Y8PUx(-%PosPy2gi@qIvBMMYz;e3L1{f~mrd9RdB>pZ zD}4R|sk_C`;=cT&r)c=8u>7h9)u32*SbL`xiq3(pq5C^5-sSOw;<|fv@nfXfl&U`2 z81K5ExDp;bf#DISW%IY%k&2-noShOoz-;kb(u?5RFX-ro?87j3GZdCXrFc8bTx}jd zz_n@djWnxc*TbbCjEq80FPyG}1zQwvjq7R6ZSWuQ@_#A*LN5n<3$BI?X}q%iD!B-s zdSFcNp!EgpJr6CAK?klug4>=)Tv z+F#{yt>6EK)3NU=L&y_W3UNaC?Tg=6YE0)^V;(0Mb0$WJ7>7@Lg0~+3x9d)!Pd