Repository navigation
feat(vrowzer): finish vrowzer.build() with .env files, tsconfig and CommonJS dependencies - #78
Merged
Merged
Conversation
…p-level input Stage 1 ported the fix of upstream #23135, which does not mutate the user's `build.lib` when the top-level `input` gives its entry, but not its test. The test fails without the fix.
`resolveConfig()` loads the `.env` files of `envDir` again, so `import.meta.env` gets the variables with the client prefix (`VITE_` by default), in builds and in previews. - `env.ts` takes the form of Vite 8.3.1, with `NOTE(kazupon)`: the files are parsed with dotenv's `parse()`, because the browser has no `parseEnv()` of `node:util`, and the variables of Vite Task (`getEnvs()`) are left out. - `dotenv-expand` goes to `^13.0.0` with upstream's patch, which lets a variable use the ones of the other `.env` files. The lockfile is updated by hand, because pnpm 12.1.0 drops unrelated entries when it updates it. - `config.ts` restores the deprecation warning of `envFile` and the check of `envPrefix`, and `html.ts` the prefixes of the `%ENV%` replacement. - The Web Worker of the previews now writes the project files before it resolves the config, so the previews read the `.env` files given to `ready()`. Later changes of them do not restart the previews; the next build reads them. Only the files of the project are read: `process.env` is the polyfill's empty object, so nothing of the host is exposed. Tests: - ported from upstream: `loadEnv()` with its fixtures, and `resolveEnvPrefix()` - `resolveConfig()` exposes only the prefixed variables, takes `envPrefix` and `envDir: false`, and rejects an empty prefix - `setupWorker()` writes the files before it resolves the config
The config gets the `tsconfig` option of Vite 8.3 again: the path of the TypeScript configuration, resolved from the root. Builds pass it to rolldown, and to the native transform and resolve plugins, as upstream does. `build.ts` no longer reads it without the type. Without the option, rolldown and the native plugins find the `tsconfig.json` of each module themselves, so its JSX settings, `experimentalDecorators` and `paths` (with `resolve.tsconfigPaths`) applied to builds already. The option selects another file, e.g. `tsconfig.app.json`, with what it extends. The warning that `resolve.tsconfigPaths` has no effect is now for the previews only, which still resolve with the JavaScript resolver and do not read tsconfig. Builds resolve with the native resolver, which supports it. Tests: - upstream's test that the top-level `tsconfig` applies to the rolldown options, commented out in stage 1 - builds in Node apply the `tsconfig.json` of the project, and the file of the `tsconfig` option (the test fails without the option) - the warning of `resolve.tsconfigPaths`, for the previews only
Builds bundled the CommonJS packages that the manifest rebuilds into ES
modules for the previews, e.g. react, in their development form: the
manifest had only the ES modules, bundled with `process.env.NODE_ENV`
set to `"development"`.
With the `build` option, the manifest now also has the original files of
those packages, and builds bundle them for production, as Vite does:
- The original files, with the original `package.json`, are in
`.vrowzer-cjs/` inside the package, so that they stay CommonJS.
- The rewritten `package.json` gives the `development` condition of the
previews the ES module as before, and the other conditions the
original files. Its targets stay inside the package: the native
resolver of builds rejects a target outside it ("Invalid exports
target"), which the ES modules of the previews have.
- Without the option, the manifest does not change. The option is part
of the cache key of the automatic manifest, and the `--build` flag of
`scripts/generate-manifest.ts` sets it.
Tests:
- vite-plugin: the exports for builds, and the manifests with and
without the option
- vite-dev-server: a build in Node resolves this layout, and bundles only
the production branch of a CommonJS package
The warnings of `build()` were only messages. - The warnings of rolldown keep their code, plugin, module, location and code frame. Vite's `onRollupLog()` passes only the message of a warning to the logger, so a new plugin of the builder wraps `build.rolldownOptions.onLog`. It calls the `onLog` of the config first, then Vite's handler, and adds the details to the warning that Vite logged. The warnings that Vite ignores, the error of an unresolved import and the user's `onLog` stay as they are. - The errors that Vite logs without failing the build, e.g. a CSS `@import` that is not found, are returned with the warnings. The collecting logger records them for `hasErrorLogged()`. - The warning of the chunks larger than `build.chunkSizeWarningLimit` is back, with the message of rolldown's reporter, for the minified builds of apps. The reporter checks the sizes when it writes the outputs, which the builder does not do. Tests: the logger, the plugin and the size check, and a build in Node that keeps the code, the module and the location of an `EVAL` warning (the test fails without the plugin).
A new plugin of the builder reports, in the modules of the project,
what builds do not support yet, instead of leaving broken outputs:
- warnings, with the module and the location:
- `import.meta.glob()`, which the output keeps. It includes the
template strings with variables of `new URL(..., import.meta.url)`,
which `vite:asset-import-meta-url` turns into it.
- dynamic imports with variables in their relative paths, whose files
the build does not include. `/* @vite-ignore */` suppresses it, as
in Vite.
- `new Worker(new URL(...))`, whose file the build emits as an asset
without bundling or transforming it
- an error for the `?worker` and `?sharedworker` imports, which failed
with "default is not exported" before
It runs after the other plugins, so that it sees JavaScript. Strings and
comments are left out, and the dependencies are not checked.
Tests: the plugin, and builds in Node that report the warnings with the
module and the line, and the error of `?worker`.
… and CSS Modules The fixture `integration/build/` gets a third project, with: - `.env`, `.env.development`, `.env.production` and `.env.local`, with variables with and without the client prefix, and an expanded one - a `tsconfig.json` with `verbatimModuleSyntax`, which keeps a type-only import with a side effect. The previews do not read tsconfig, so they still run without the side effect. - CSS Modules with `composes` - a CommonJS dependency in the layout of the manifest of `@vrowzer/vite-plugin` with the build option, with branches for production and development `build.integration-test.ts` checks, in the browser: - the variables of the `.env` files in the preview (development) and in the build (production). The variables without the prefix are not exposed, and no env file is in the outputs. - tsconfig applies to the build. The build Worker reads it from the snapshot. - the build bundles the production branch of the CommonJS dependency, and the preview takes its ES module for development - CSS Modules in the preview and in the build: a scoped class, and `composes` - the warnings keep their code, module and location, and report `import.meta.glob()`
- vrowzer README:
- the `.env` files that builds and previews read, the client prefix,
and when the previews read them
- tsconfig, which builds apply and the previews do not read yet
- CSS Modules
- the CommonJS dependencies built for production, and that a
development build cannot resolve them yet
- the details of `warnings`, the errors logged without failing the
build, and the warning about large chunks
- what the build warns about: `import.meta.glob()`, variables in the
relative paths of dynamic imports and `new URL()`, and the Workers
of the project, with `?worker` failing the build
- browsers: the build is tested in Chromium. In WebKit, which does not
support COEP `credentialless`, the page is not cross-origin
isolated, and Vrowzer does not start. Firefox is not tested.
- vite-plugin README: the manifest of `build: true` has the original
files of the CommonJS packages.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #36. Stacked on #77 (stage 2, HTML app builds).
This PR is the last stage of #36.
vrowzer.build()now reads the.envfiles and tsconfig of the project, builds CommonJS dependencies for production, supports CSS Modules, and reports what it does not support.What it does
.envfiles:import.meta.envexposes the variables with the client prefix (VITE_by default) of.env,.env.local,.env.[mode]and.env.[mode].local, as in Vite.ready()starts them.tsconfig.jsonof the project, or the file of the newtsconfigoption (Vite 8.3), e.g. JSX settings,experimentalDecorators,verbatimModuleSyntax, andpathswithresolve.tsconfigPaths.build: true, the manifest of@vrowzer/vite-pluginalso has the original files of the CommonJS packages that it bundles into ES modules for the previews, e.g. react. Builds bundle them for production, as Vite does. The previews keep the ES modules.composes).import.meta.glob(), dynamic imports with variables in their relative paths, andnew Worker(new URL(...))are warnings.?workerimports fail with a clear error instead of"default" is not exported.How it works
.envfiles:env.tstakes the form of Vite 8.3.1. WithNOTE(kazupon): it parses with dotenv'sparse(), because the browser has noparseEnv()ofnode:util, and leaves out Vite Task'sgetEnvs().config.tscallsloadEnv()again. ItsenvFilewarning andenvPrefixcheck are back, and so is the%ENV%prefix ofhtml.ts.dotenv-expandgoes to^13.0.0with upstream's patch, which lets a variable use the ones of the other.envfiles. Upstream's test fails without it.resolveConfig()does not load config files, so the project'svite.config.*is not read.config.tsconfigto rolldown and to the native transform and resolve plugins, as upstream does.tsconfig.jsonof each module.resolve.tsconfigPathshas no effect is now for the previews only..vrowzer-cjs/inside each package, with the originalpackage.json, so that they stay CommonJS: the rewrittenpackage.jsonistype: "module".exportsgive thedevelopmentcondition the ES module, and the other conditions./.vrowzer-cjs/....Invalid "exports" target).buildis part of the cache key, andscripts/generate-manifest.ts --buildsets it.build.rolldownOptions.onLog. It calls the config'sonLog, then Vite's handler, and adds the details to the warning that Vite logged, so Vite's handling of the logs does not change.Differences from the plan
typeand the resolver above.Not supported, or not checked
NODE_ENV=development, e.g. in a.envfile) cannot resolve the CommonJS packages of the manifest: thedevelopmentcondition still points outside the package (../.vrowzer-esm/), which the native resolver rejects..envfiles afterready()reach the next build, but not the running previews (upstream restarts its server).crossOriginIsolatedisfalse, soSharedArrayBufferis missing and Vrowzer itself does not start. The likely cause is that WebKit does not support COEPcredentialless. This is outside Add vrowzer.build() for browser-side production builds #36.import.meta.glob, variable dynamic imports and the Workers of the project stay out of Add vrowzer.build() for browser-side production builds #36's scope. They are reported, not built.Measurements
macOS arm64, Chromium:
.envfiles)build: truefor the react e2e project gets the original files of react (169,358 bytes) and react-dom (7,317,229 bytes). Minified with Oxc, as the automatic manifest does, that is about 3.1 MB. The spike's estimate (549 KiB) counted only the production entries for browsers. Trimming the files to what the production conditions reach is left for another issue.Tests
All on macOS (arm64):
vp run build, the type checks, oxlint, knip and the format check pass.Unit tests: 2183 passed, 3 skipped (39 more than stage 2).
loadEnv()with its fixtures, andresolveEnvPrefix()tsconfiginputdoes not mutate the user config, missed in stage 1.envfiles inresolveConfig(), and the order ofsetupWorker()tsconfigoption andextendsIntegration tests:
build.integration-test.tsgets a project with.envfiles, atsconfig.json, CSS Modules and a CommonJS dependency in the layout of the manifest. In the browser, it checks:.envfiles in the preview (development) and the build (production), without the unprefixed ones and without the env files in the outputsimport.meta.glob()e2e, with the Vite caches cleared first: