import { defineConfig } from 'vite'
import baseConfig from './vite.config.js'

export default defineConfig(({ isPreview }) => ({
  ...baseConfig,
  base: !isPreview ? './' : '/relative-base/', // relative base to make dist portable
  build: {
    ...baseConfig.build,
    outDir: 'dist/relative-base',
    watch: null,
    minify: false,
    assetsInlineLimit: 0,
    rolldownOptions: {
      output: {
        entryFileNames: 'entries/[name].js',
        chunkFileNames: 'chunks/[name]-[hash].js',
        assetFileNames: 'other-assets/[name]-[hash][extname]',
      },
    },
  },
  cacheDir: 'node_modules/.vite-relative-base',
}))


import { rerender } from './runtime'

export const parentValue = 'parent'
export { value as childValue } from './child'

if (import.meta.hot) {
  import.meta.hot.accept((newMod) => {
    if (!newMod) return

    rerender({ child: newMod.childValue, parent: newMod.parentValue })
  })
}


<!-- Serde readme rendered on crates.io -->

**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**

---

You may be looking for:

- [An overview of Serde](https://serde.rs)
- [Data formats supported by Serde](https://serde.rs/#data-formats)
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
- [Examples](https://serde.rs/examples.html)
- [API documentation](https://docs.rs/serde)
- [Release notes](https://github.com/serde-rs/serde/releases)

## Serde in action

```rust
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    // Convert the Point to a JSON string.
    let serialized = serde_json::to_string(&point).unwrap();

    // Prints serialized = {"x":1,"y":2}
    println!("serialized = {}", serialized);

    // Convert the JSON string back to a Point.
    let deserialized: Point = serde_json::from_str(&serialized).unwrap();

    // Prints deserialized = Point { x: 1, y: 2 }
    println!("deserialized = {:?}", deserialized);
}
```

## Getting help

Serde is one of the most widely used Rust libraries so any place that Rustaceans
congregate will be able to help you out. For chat, consider trying the
[#rust-questions] or [#rust-beginners] channels of the unofficial community
Discord (invite: <https://discord.gg/rust-lang-community>), the [#rust-usage]
or [#beginners] channels of the official Rust Project Discord (invite:
<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For
asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the
[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust
[Discourse forum][discourse]. It's acceptable to file a support issue in this
repo but they tend not to get as many eyes as any of the above and may get
closed without a response after some time.

[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513
[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281
[#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848
[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612
[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general
[stackoverflow]: https://stackoverflow.com/questions/tagged/rust
[/r/rust]: https://www.reddit.com/r/rust
[discourse]: https://users.rust-lang.org


# <small>nlohmann::basic_json::</small>at

```cpp
// (1)
reference at(size_type idx);
const_reference at(size_type idx) const;

// (2)
reference at(const typename object_t::key_type& key);
const_reference at(const typename object_t::key_type& key) const;

// (3)
template<typename KeyType>
reference at(KeyType&& key);
template<typename KeyType>
const_reference at(KeyType&& key) const;

// (4)
reference at(const json_pointer& ptr);
const_reference at(const json_pointer& ptr) const;
```

1. Returns a reference to the array element at specified location `idx`, with bounds checking.
2. Returns a reference to the object element with specified key `key`, with bounds checking.
3. See 2. This overload is only available if `KeyType` is comparable with `#!cpp typename object_t::key_type` and
   `#!cpp typename object_comparator_t::is_transparent` denotes a type.
4. Returns a reference to the element at specified JSON pointer `ptr`, with bounds checking.

## Template parameters

`KeyType`
:   A type for an object key other than [`json_pointer`](../json_pointer/index.md) that is comparable with
    [`string_t`](string_t.md) using  [`object_comparator_t`](object_comparator_t.md).
    This can also be a string view (C++17).

## Parameters

`idx` (in)
:   index of the element to access

`key` (in)
:   object key of the elements to access

`ptr` (in)
:   JSON pointer to the desired element

## Return value

1. reference to the element at index `idx`
2. reference to the element at key `key`
3. reference to the element at key `key`
4. reference to the element pointed to by `ptr`

## Exception safety

Strong exception safety: if an exception occurs, the original value stays intact.

## Exceptions

1. The function can throw the following exceptions:
    - Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the JSON value is not an array;
      in this case, calling `at` with an index makes no sense. See the example below.
    - Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if the index `idx` is out of
      range of the array; that is, `idx >= size()`. See the example below.
2. The function can throw the following exceptions:
    - Throws [`type_error.304`](../../home/exceptions.md#jsonexceptiontype_error304) if the JSON value is not an object;
      in this case, calling `at` with a key makes no sense. See the example below.
    - Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if the key `key` is not
      stored in the object; that is, `find(key) == end()`. See the example below.
3. See 2.
4. The function can throw the following exceptions:
    - Throws [`parse_error.106`](../../home/exceptions.md#jsonexceptionparse_error106) if an array index in the passed
      JSON pointer `ptr` begins with '0'. See the example below.
    - Throws [`parse_error.109`](../../home/exceptions.md#jsonexceptionparse_error109) if an array index in the passed
      JSON pointer `ptr` is not a number. See the example below.
    - Throws [`out_of_range.401`](../../home/exceptions.md#jsonexceptionout_of_range401) if an array index in the passed
      JSON pointer `ptr` is out of range. See the example below.
    - Throws [`out_of_range.402`](../../home/exceptions.md#jsonexceptionout_of_range402) if the array index '-' is used
      in the passed JSON pointer `ptr`. As `at` provides checked access (and no elements are implicitly inserted), the
      index '-' is always invalid. See the example below.
    - Throws [`out_of_range.403`](../../home/exceptions.md#jsonexceptionout_of_range403) if the JSON pointer describes a
      key of an object which cannot be found. See the example below.
    - Throws [`out_of_range.404`](../../home/exceptions.md#jsonexceptionout_of_range404) if the JSON pointer `ptr` can
      not be resolved. See the example below.
    - Throws [`out_of_range.410`](../../home/exceptions.md#jsonexceptionout_of_range410) if an array index in the passed
      JSON pointer `ptr` exceeds the range of `size_type` (e.g., on 32-bit platforms).

## Complexity

1. Constant.
2. Logarithmic in the size of the container.
3. Logarithmic in the size of the container.
4. Logarithmic in the size of the container.

## Examples

??? example "Example: (1) access specified array element with bounds checking"

    The example below shows how array elements can be read and written using `at()`. It also demonstrates the different
    exceptions that can be thrown.

    ```cpp
    --8<-- "examples/at__size_type.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__size_type.output"
    ```

??? example "Example: (1) access specified array element with bounds checking"

    The example below shows how array elements can be read using `at()`. It also demonstrates the different exceptions
    that can be thrown.

    ```cpp
    --8<-- "examples/at__size_type_const.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__size_type_const.output"
    ```

??? example "Example: (2) access specified object element with bounds checking"

    The example below shows how object elements can be read and written using `at()`. It also demonstrates the different
    exceptions that can be thrown.

    ```cpp
    --8<-- "examples/at__object_t_key_type.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__object_t_key_type.output"
    ```

??? example "Example: (2) access specified object element with bounds checking"

    The example below shows how object elements can be read using `at()`. It also demonstrates the different exceptions
    that can be thrown.

    ```cpp
    --8<-- "examples/at__object_t_key_type_const.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__object_t_key_type_const.output"
    ```

??? example "Example: (3) access specified object element using string_view with bounds checking"

    The example below shows how object elements can be read and written using `at()`. It also demonstrates the different
    exceptions that can be thrown.

    ```cpp
    --8<-- "examples/at__keytype.c++17.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__keytype.c++17.output"
    ```

??? example "Example: (3) access specified object element using string_view with bounds checking"

    The example below shows how object elements can be read using `at()`. It also demonstrates the different exceptions
    that can be thrown.

    ```cpp
    --8<-- "examples/at__keytype_const.c++17.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__keytype_const.c++17.output"
    ```

??? example "Example: (4) access specified element via JSON Pointer"

    The example below shows how object elements can be read and written using `at()`. It also demonstrates the different
    exceptions that can be thrown.

    ```cpp
    --8<-- "examples/at__json_pointer.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__json_pointer.output"
    ```

??? example "Example: (4) access specified element via JSON Pointer"

    The example below shows how object elements can be read using `at()`. It also demonstrates the different exceptions
    that can be thrown.

    ```cpp
    --8<-- "examples/at__json_pointer_const.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/at__json_pointer_const.output"
    ```

## See also

- documentation on [checked access](../../features/element_access/checked_access.md)
- [`operator[]`](operator%5B%5D.md) for unchecked access by reference
- [`value`](value.md) for access with default value

## Version history

1. Added in version 1.0.0.
2. Added in version 1.0.0.
3. Added in version 3.11.0.
4. Added in version 2.0.0.


import path from 'node:path'
import { describe, expect, test } from 'vitest'
import { expandGlobIds } from '../../optimizer/resolve'

const fixtureRoot = path.join(import.meta.dirname, '../fixtures/glob-exports')

function makeConfig(root: string): any {
  return {
    root,
    resolve: { preserveSymlinks: false },
    packageCache: new Map(),
  }
}

describe('expandGlobIds', () => {
  test('skips null-valued exports (private subpath patterns)', () => {
    const result = expandGlobIds('my-pkg/*', makeConfig(fixtureRoot))

    expect(result).toContain('my-pkg')
    expect(result).toContain('my-pkg/utils')
    expect(result).toContain('my-pkg/public')
    expect(result).not.toContain('my-pkg/private')
    expect(result).not.toContain('my-pkg/also-private')
  })
})


# Runtime Assertions

The code contains numerous debug assertions to ensure class invariants are valid or to detect undefined behavior.
Whereas the former class invariants are nothing to be concerned with, the latter checks for undefined behavior are to
detect bugs in client code.

## Switch off runtime assertions

Runtime assertions can be switched off by defining the preprocessor macro `NDEBUG` (see the
[documentation of assert](https://en.cppreference.com/w/cpp/error/assert)) which is the default for release builds.

## Change assertion behavior

The behavior of runtime assertions can be changed by defining macro [`JSON_ASSERT(x)`](../api/macros/json_assert.md)
before including the `json.hpp` header.

## Function with runtime assertions

### Unchecked object access to a const value

Function [`operator[]`](../api/basic_json/operator%5B%5D.md) implements unchecked access for objects. Whereas a missing
key is added in the case of non-const objects, accessing a const object with a missing key is undefined behavior (think
of a dereferenced null pointer) and yields a runtime assertion.

If you are not sure whether an element in an object exists, use checked access with the
[`at` function](../api/basic_json/at.md) or call the [`contains` function](../api/basic_json/contains.md) before.

See also the documentation on [element access](element_access/index.md).

??? example "Example 1: Missing object key"

    The following code will trigger an assertion at runtime:

    ```cpp
    #include <nlohmann/json.hpp>

    using json = nlohmann::json;

    int main()
    {
        const json j = {{"key", "value"}};
        auto v = j["missing"];
    }
    ```

    Output:

    ```
    Assertion failed: (m_value.object->find(key) != m_value.object->end()), function operator[], file json.hpp, line 2144.
    ```

### Constructing from an uninitialized iterator range

Constructing a JSON value from an iterator range (see [constructor](../api/basic_json/basic_json.md)) with an
uninitialized iterator is undefined behavior and yields a runtime assertion.

??? example "Example 2: Uninitialized iterator range"

    The following code will trigger an assertion at runtime:

    ```cpp
    #include <nlohmann/json.hpp>

    using json = nlohmann::json;

    int main()
    {
        json::iterator it1, it2;
        json j(it1, it2);
    }
    ```

    Output:

    ```
    Assertion failed: (m_object != nullptr), function operator++, file iter_impl.hpp, line 368.
    ```

### Operations on uninitialized iterators

Any operation on uninitialized iterators (i.e., iterators that are not associated with any JSON value) is undefined
behavior and yields a runtime assertion.

??? example "Example 3: Uninitialized iterator"

    The following code will trigger an assertion at runtime:

    ```cpp
    #include <nlohmann/json.hpp>

    using json = nlohmann::json;

    int main()
    {
      json::iterator it;
      ++it;
    }
    ```

    Output:

    ```
    Assertion failed: (m_object != nullptr), function operator++, file iter_impl.hpp, line 368.
    ```

## Changes

### Reading from a null `FILE` or `char` pointer

Reading from a null `#!cpp FILE` or `#!cpp char` pointer in C++ is undefined behavior.  Until version 3.12.0, this
library asserted that the pointer was not `nullptr` using a runtime assertion. If assertions were disabled, this would
result in undefined behavior. Since version 3.12.0, this library checks for `nullptr` and throws a
[`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) to prevent the undefined behavior.

??? example "Example 4: Reading from null pointer"

    The following code will trigger an assertion at runtime:

    ```cpp
    #include <iostream>
    #include <nlohmann/json.hpp>

    using json = nlohmann::json;

    int main()
    {
        std::FILE* f = std::fopen("nonexistent_file.json", "r");
        try {
            json j = json::parse(f);
        } catch (std::exception& e) {
            std::cerr << e.what() << std::endl;
        }
    }
    ```

    Output:

    ```
    [json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON
    ```

## See also

- [JSON_ASSERT](../api/macros/json_assert.md) - control behavior of runtime assertions


import path from 'node:path'
import MagicString from 'magic-string'
import type { RollupError } from 'rolldown'
import { parseAstAsync } from 'rolldown/parseAst'
import { stripLiteral } from 'strip-literal'
import type { ESTree } from 'rolldown/utils'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { evalValue, injectQuery, transformStableResult } from '../utils'
import { createBackCompatIdResolver } from '../idResolver'
import type { ResolveIdFn } from '../idResolver'
import { cleanUrl, slash } from '../../shared/utils'
import type { WorkerType } from './worker'
import {
  WORKER_FILE_ID,
  emitWorkerAssetsForBundledDev,
  workerFileToUrl,
} from './worker'
import { fileToUrl, toOutputFilePathInJSForBundledDev } from './asset'
import type { InternalResolveOptions } from './resolve'
import { tryFsResolve } from './resolve'
import { hasViteIgnoreRE } from './importAnalysis'

interface WorkerOptions {
  type?: WorkerType
}

function err(e: string, pos: number) {
  const error = new Error(e) as RollupError
  error.pos = pos
  return error
}

function findClosingParen(input: string, fromIndex: number) {
  let count = 1

  for (let i = fromIndex; i < input.length; i++) {
    if (input[i] === '(') count++
    if (input[i] === ')') count--
    if (count === 0) return i
  }

  return -1
}

function extractWorkerTypeFromAst(
  expression: ESTree.Expression,
  optsStartIndex: number,
): 'classic' | 'module' | undefined {
  if (expression.type !== 'ObjectExpression') {
    return
  }

  let lastSpreadElementIndex = -1
  let typeProperty = null
  let typePropertyIndex = -1

  for (let i = 0; i < expression.properties.length; i++) {
    const property = expression.properties[i]

    if (property.type === 'SpreadElement') {
      lastSpreadElementIndex = i
      continue
    }

    if (
      property.type === 'Property' &&
      ((property.key.type === 'Identifier' && property.key.name === 'type') ||
        (property.key.type === 'Literal' && property.key.value === 'type'))
    ) {
      typeProperty = property
      typePropertyIndex = i
    }
  }

  if (typePropertyIndex === -1 && lastSpreadElementIndex === -1) {
    // No type property or spread element in use. Assume safe usage and default to classic
    return 'classic'
  }

  if (typePropertyIndex < lastSpreadElementIndex) {
    throw err(
      'Expected object spread to be used before the definition of the type property. ' +
        'Vite needs a static value for the type property to correctly infer it.',
      optsStartIndex,
    )
  }

  if (typeProperty?.value.type !== 'Literal') {
    throw err(
      'Expected worker options type property to be a literal value.',
      optsStartIndex,
    )
  }

  // Silently default to classic type like the getWorkerType method
  return typeProperty?.value.value === 'module' ? 'module' : 'classic'
}

async function parseWorkerOptions(
  rawOpts: string,
  optsStartIndex: number,
): Promise<WorkerOptions> {
  let opts: WorkerOptions = {}
  try {
    opts = evalValue<WorkerOptions>(rawOpts)
  } catch {
    const optsNode = (
      (await parseAstAsync(`(${rawOpts})`))
        .body[0] as ESTree.ExpressionStatement
    ).expression

    const type = extractWorkerTypeFromAst(optsNode, optsStartIndex)
    if (type) {
      return { type }
    }

    throw err(
      'Vite is unable to parse the worker options as the value is not static. ' +
        'To ignore this error, please use /* @vite-ignore */ in the worker options.',
      optsStartIndex,
    )
  }

  if (opts == null) {
    return {}
  }

  if (typeof opts !== 'object') {
    throw err(
      `Expected worker options to be an object, got ${typeof opts}`,
      optsStartIndex,
    )
  }

  return opts
}

async function getWorkerType(
  raw: string,
  clean: string,
  i: number,
): Promise<WorkerType> {
  const commaIndex = clean.indexOf(',', i)
  if (commaIndex === -1) {
    return 'classic'
  }
  const endIndex = findClosingParen(clean, i)

  // case: ') ... ,' mean no worker options params
  if (commaIndex > endIndex) {
    return 'classic'
  }

  // need to find in comment code
  let workerOptString = raw.substring(commaIndex + 1, endIndex)
  const hasViteIgnore = hasViteIgnoreRE.test(workerOptString)
  if (hasViteIgnore) {
    return 'ignore'
  }

  // need to find in no comment code
  const cleanWorkerOptString = clean.substring(commaIndex + 1, endIndex)
  const trimmedCleanWorkerOptString = cleanWorkerOptString.trim()
  if (!trimmedCleanWorkerOptString.length) {
    return 'classic'
  }

  // strip trailing comma for evalValue
  if (trimmedCleanWorkerOptString.endsWith(',')) {
    workerOptString = workerOptString.slice(
      0,
      cleanWorkerOptString.lastIndexOf(','),
    )
  }

  const workerOpts = await parseWorkerOptions(workerOptString, commaIndex + 1)
  if (
    workerOpts.type &&
    (workerOpts.type === 'module' || workerOpts.type === 'classic')
  ) {
    return workerOpts.type
  }

  return 'classic'
}

export const workerImportMetaUrlRE: RegExp =
  /\bnew\s+(?:Worker|SharedWorker)\s*\(\s*(new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*(?:,\s*)?\))/dg

export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
  let workerResolver: ResolveIdFn

  const fsResolveOptions: InternalResolveOptions = {
    ...config.resolve,
    root: config.root,
    isProduction: config.isProduction,
    isBuild: config.command === 'build',
    packageCache: config.packageCache,
    asSrc: true,
  }

  return {
    name: 'vite:worker-import-meta-url',

    applyToEnvironment(environment) {
      return environment.config.consumer === 'client'
    },

    transform: {
      filter: { code: workerImportMetaUrlRE },
      async handler(code, id) {
        const isBundled = this.environment.config.isBundled
        let s: MagicString | undefined
        const cleanString = stripLiteral(code)
        const re = new RegExp(workerImportMetaUrlRE)

        let match: RegExpExecArray | null
        while ((match = re.exec(cleanString))) {
          const [[, endIndex], [expStart, expEnd], [urlStart, urlEnd]] =
            match.indices as Array<[number, number]>

          const rawUrl = code.slice(urlStart, urlEnd)

          // potential dynamic template string
          if (rawUrl[0] === '`' && rawUrl.includes('${')) {
            this.error(
              `\`new URL(url, import.meta.url)\` is not supported in dynamic template string.`,
              expStart,
            )
          }

          s ||= new MagicString(code)
          const workerType = await getWorkerType(code, cleanString, endIndex)
          const url = rawUrl.slice(1, -1)
          let file: string | undefined
          if (url[0] === '.') {
            file = path.resolve(path.dirname(id), url)
            file = slash(tryFsResolve(file, fsResolveOptions) ?? file)
          } else {
            workerResolver ??= createBackCompatIdResolver(config, {
              extensions: [],
              tryIndex: false,
              preferRelative: true,
            })
            file = await workerResolver(this.environment, url, id)
            file ??=
              url[0] === '/'
                ? slash(path.join(config.publicDir, url))
                : slash(path.resolve(path.dirname(id), url))
          }

          if (
            isBundled &&
            config.isWorker &&
            config.bundleChain.at(-1) === cleanUrl(file)
          ) {
            s.update(expStart, expEnd, 'self.location.href')
          } else {
            let builtUrl: string
            if (isBundled) {
              const result = await workerFileToUrl(config, file)
              if (this.environment.config.command === 'serve') {
                emitWorkerAssetsForBundledDev(this, config)
                builtUrl = toOutputFilePathInJSForBundledDev(
                  this.environment,
                  result.entryFilename,
                )
              } else {
                builtUrl = result.entryUrlPlaceholder
              }
              for (const file of result.watchedFiles) {
                this.addWatchFile(file)
              }
            } else {
              builtUrl = await fileToUrl(this, cleanUrl(file))
              builtUrl = injectQuery(
                builtUrl,
                `${WORKER_FILE_ID}&type=${workerType}`,
              )
            }
            s.update(
              expStart,
              expEnd,
              // NOTE: add `'' +` to opt-out rolldown's transform: https://github.com/rolldown/rolldown/issues/2745
              `new URL(/* @vite-ignore */ ${JSON.stringify(builtUrl)}, '' + import.meta.url)`,
            )
          }
        }

        if (s) {
          return transformStableResult(s, id, config)
        }

        return null
      },
    },
  }
}


//     __ _____ _____ _____
//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
// |  |  |__   |  |  | | | |  version 3.12.0
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT

#include "doctest_compatibility.h"

#include <nlohmann/json.hpp>
using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS
    using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
#endif

TEST_CASE("JSON Merge Patch")
{
    SECTION("examples from RFC 7396")
    {
        SECTION("Section 1")
        {
            json document = R"({
                "a": "b",
                "c": {
                    "d": "e",
                    "f": "g"
                }
            })"_json;

            json const patch = R"({
                "a": "z",
                "c": {
                    "f": null
                }
            })"_json;

            json expected = R"({
                "a": "z",
                "c": {
                    "d": "e"
                }
            })"_json;

            document.merge_patch(patch);
            CHECK(document == expected);
        }

        SECTION("Section 3")
        {
            json document = R"({
                "title": "Goodbye!",
                "author": {
                    "givenName": "John",
                    "familyName": "Doe"
                },
                "tags": [
                    "example",
                    "sample"
                ],
                "content": "This will be unchanged"
            })"_json;

            json const patch = R"({
                "title": "Hello!",
                "phoneNumber": "+01-123-456-7890",
                "author": {
                    "familyName": null
                },
                "tags": [
                    "example"
                ]
            })"_json;

            json expected = R"({
                "title": "Hello!",
                "author": {
                    "givenName": "John"
                },
                "tags": [
                    "example"
                ],
                "content": "This will be unchanged",
                "phoneNumber": "+01-123-456-7890"
            })"_json;

            document.merge_patch(patch);
            CHECK(document == expected);
        }

        SECTION("Appendix A")
        {
            SECTION("Example 1")
            {
                json original = R"({"a":"b"})"_json;
                json const patch = R"({"a":"c"})"_json;
                json result = R"({"a":"c"})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 2")
            {
                json original = R"({"a":"b"})"_json;
                json const patch = R"({"b":"c"})"_json;
                json result = R"({"a":"b", "b":"c"})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 3")
            {
                json original = R"({"a":"b"})"_json;
                json const patch = R"({"a":null})"_json;
                json result = R"({})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 4")
            {
                json original = R"({"a":"b","b":"c"})"_json;
                json const patch = R"({"a":null})"_json;
                json result = R"({"b":"c"})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 5")
            {
                json original = R"({"a":["b"]})"_json;
                json const patch = R"({"a":"c"})"_json;
                json result = R"({"a":"c"})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 6")
            {
                json original = R"({"a":"c"})"_json;
                json const patch = R"({"a":["b"]})"_json;
                json result = R"({"a":["b"]})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 7")
            {
                json original = R"({"a":{"b": "c"}})"_json;
                json const patch = R"({"a":{"b":"d","c":null}})"_json;
                json result = R"({"a": {"b": "d"}})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 8")
            {
                json original = R"({"a":[{"b":"c"}]})"_json;
                json const patch = R"({"a":[1]})"_json;
                json result = R"({"a":[1]})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 9")
            {
                json original = R"(["a","b"])"_json;
                json const patch = R"(["c","d"])"_json;
                json result = R"(["c","d"])"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 10")
            {
                json original = R"({"a":"b"})"_json;
                json const patch = R"(["c"])"_json;
                json result = R"(["c"])"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 11")
            {
                json original = R"({"a":"foo"})"_json;
                json const patch = R"(null)"_json;
                json result = R"(null)"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 12")
            {
                json original = R"({"a":"foo"})"_json;
                json const patch = R"("bar")"_json;
                json result = R"("bar")"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 13")
            {
                json original = R"({"e":null})"_json;
                json const patch = R"({"a":1})"_json;
                json result = R"({"e":null,"a":1})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 14")
            {
                json original = R"([1,2])"_json;
                json const patch = R"({"a":"b","c":null})"_json;
                json result = R"({"a":"b"})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }

            SECTION("Example 15")
            {
                json original = R"({})"_json;
                json const patch = R"({"a":{"bb":{"ccc":null}}})"_json;
                json result = R"({"a":{"bb":{}}})"_json;

                original.merge_patch(patch);
                CHECK(original == result);
            }
        }
    }
}


import fs from 'node:fs'
import path from 'node:path'
import legacy from '@vitejs/plugin-legacy'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [legacy()],

  build: {
    outDir: 'dist/chunk-importmap',
    chunkImportMap: true,
  },

  // for tests, remove `<script type="module">` tags and remove `nomodule`
  // attrs so that we run the legacy bundle instead.
  __test__() {
    const indexPath = path.resolve(
      import.meta.dirname,
      './dist/chunk-importmap/index.html',
    )
    let index = fs.readFileSync(indexPath, 'utf-8')
    index = index
      .replace(/<script type="module".*?<\/script>/g, '')
      .replace(/<script nomodule/g, '<script')
    fs.writeFileSync(indexPath, index)
  },
})


# <small>nlohmann::basic_json::</small>~basic_json

```cpp
~basic_json() noexcept;
```

Destroys the JSON value and frees all allocated memory.

## Exception safety

No-throw guarantee: this member function never throws exceptions.

## Complexity

Linear.

<!-- NOLINT Examples -->

## Version history

- Added in version 1.0.0.


import path from 'node:path'
import fs from 'node:fs'
import type { Connect } from '#dep-types/connect'
import { createDebugger, joinUrlSegments } from '../../utils'
import { cleanUrl } from '../../../shared/utils'
import type { DevEnvironment } from '../environment'

const debug = createDebugger('vite:html-fallback')

export function htmlFallbackMiddleware(
  root: string,
  spaFallback: boolean,
  clientEnvironment?: DevEnvironment,
): Connect.NextHandleFunction {
  const memoryFiles = clientEnvironment?.bundledDev?.memoryFiles

  function checkFileExists(relativePath: string) {
    return (
      memoryFiles?.has(
        relativePath.slice(1), // remove first /
      ) ?? fs.existsSync(path.join(root, relativePath))
    )
  }

  // Keep the named function. The name is visible in debug logs via `DEBUG=connect:dispatcher ...`
  return function viteHtmlFallbackMiddleware(req, _res, next) {
    if (
      // Only accept GET or HEAD
      (req.method !== 'GET' && req.method !== 'HEAD') ||
      // Exclude default favicon requests
      req.url === '/favicon.ico' ||
      // Require Accept: text/html or */*
      !(
        req.headers.accept === undefined || // equivalent to `Accept: */*`
        req.headers.accept === '' || // equivalent to `Accept: */*`
        req.headers.accept.includes('text/html') ||
        req.headers.accept.includes('*/*')
      )
    ) {
      return next()
    }

    const url = cleanUrl(req.url!)
    let pathname
    try {
      pathname = decodeURIComponent(url)
    } catch {
      // ignore malformed URI
      return next()
    }

    // .html files are not handled by serveStaticMiddleware
    // so we need to check if the file exists
    if (pathname.endsWith('.html')) {
      if (checkFileExists(pathname)) {
        debug?.(`Rewriting ${req.method} ${req.url} to ${url}`)
        req.url = url
        return next()
      }
    }
    // trailing slash should check for fallback index.html
    else if (pathname.endsWith('/')) {
      if (checkFileExists(joinUrlSegments(pathname, 'index.html'))) {
        const newUrl = url + 'index.html'
        debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`)
        req.url = newUrl
        return next()
      }
    }
    // non-trailing slash should check for fallback .html
    else {
      if (checkFileExists(pathname + '.html')) {
        const newUrl = url + '.html'
        debug?.(`Rewriting ${req.method} ${req.url} to ${newUrl}`)
        req.url = newUrl
        return next()
      }
    }

    if (spaFallback) {
      debug?.(`Rewriting ${req.method} ${req.url} to /index.html`)
      req.url = '/index.html'
    }

    next()
  }
}


import React from 'react'

export default function Root() {
  const [count, setCount] = React.useState(0)

  const [hydrated, setHydrated] = React.useState(false)
  React.useEffect(() => {
    setHydrated(true)
  }, [])

  return (

hydrated: {String(hydrated)}

Count: {count}

      <button onClick={() => setCount((v) => v - 1)}>-1</button>
      <button onClick={() => setCount((v) => v + 1)}>+1</button>

  )
}


//     __ _____ _____ _____
//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
// |  |  |__   |  |  | | | |  version 3.12.0
// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT

#include "doctest_compatibility.h"

#define JSON_TESTS_PRIVATE
#include <nlohmann/json.hpp>
using nlohmann::json;

template<typename Iter>
using can_post_increment_temporary = decltype((std::declval<Iter>()++)++);

template<typename Iter>
using can_post_decrement_temporary = decltype((std::declval<Iter>()--)--);

TEST_CASE("iterator class")
{
    SECTION("construction")
    {
        SECTION("constructor")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator const it(&j);
            }

            SECTION("object")
            {
                json j(json::value_t::object);
                json::iterator const it(&j);
            }

            SECTION("array")
            {
                json j(json::value_t::array);
                json::iterator const it(&j);
            }
        }

        SECTION("copy assignment")
        {
            json j(json::value_t::null);
            json::iterator const it(&j);
            json::iterator it2(&j);
            it2 = it;
        }
    }

    SECTION("initialization")
    {
        SECTION("set_begin")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator it(&j);
                it.set_begin();
                CHECK((it == j.begin()));
            }

            SECTION("object")
            {
                json j(json::value_t::object);
                json::iterator it(&j);
                it.set_begin();
                CHECK((it == j.begin()));
            }

            SECTION("array")
            {
                json j(json::value_t::array);
                json::iterator it(&j);
                it.set_begin();
                CHECK((it == j.begin()));
            }
        }

        SECTION("set_end")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator it(&j);
                it.set_end();
                CHECK((it == j.end()));
            }

            SECTION("object")
            {
                json j(json::value_t::object);
                json::iterator it(&j);
                it.set_end();
                CHECK((it == j.end()));
            }

            SECTION("array")
            {
                json j(json::value_t::array);
                json::iterator it(&j);
                it.set_end();
                CHECK((it == j.end()));
            }
        }
    }

    SECTION("element access")
    {
        SECTION("operator*")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator const it = j.begin();
                CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
            }

            SECTION("number")
            {
                json j(17);
                json::iterator it = j.begin();
                CHECK(*it == json(17));
                it = j.end();
                CHECK_THROWS_WITH_AS(*it, "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
            }

            SECTION("object")
            {
                json j({{"foo", "bar"}});
                json::iterator const it = j.begin();
                CHECK(*it == json("bar"));
            }

            SECTION("array")
            {
                json j({1, 2, 3, 4});
                json::iterator const it = j.begin();
                CHECK(*it == json(1));
            }
        }

        SECTION("operator->")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator const it = j.begin();
                CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
            }

            SECTION("number")
            {
                json j(17);
                json::iterator it = j.begin();
                CHECK(std::string(it->type_name()) == "number");
                it = j.end();
                CHECK_THROWS_WITH_AS(std::string(it->type_name()), "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
            }

            SECTION("object")
            {
                json j({{"foo", "bar"}});
                json::iterator const it = j.begin();
                CHECK(std::string(it->type_name()) == "string");
            }

            SECTION("array")
            {
                json j({1, 2, 3, 4});
                json::iterator const it = j.begin();
                CHECK(std::string(it->type_name()) == "number");
            }
        }
    }

    SECTION("increment/decrement")
    {
        SECTION("post-increment")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator it = j.begin();
                CHECK((it.m_it.primitive_iterator.m_it == 1));
                it++;
                CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
            }

            SECTION("number")
            {
                json j(17);
                json::iterator it = j.begin();
                CHECK((it.m_it.primitive_iterator.m_it == 0));
                it++;
                CHECK((it.m_it.primitive_iterator.m_it == 1));
                it++;
                CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
            }

            SECTION("object")
            {
                json j({{"foo", "bar"}});
                json::iterator it = j.begin();
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
                it++;
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
            }

            SECTION("array")
            {
                json j({1, 2, 3, 4});
                json::iterator it = j.begin();
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
                it++;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                it++;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                it++;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                it++;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
            }
        }

        SECTION("pre-increment")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator it = j.begin();
                CHECK((it.m_it.primitive_iterator.m_it == 1));
                ++it;
                CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
            }

            SECTION("number")
            {
                json j(17);
                json::iterator it = j.begin();
                CHECK((it.m_it.primitive_iterator.m_it == 0));
                ++it;
                CHECK((it.m_it.primitive_iterator.m_it == 1));
                ++it;
                CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
            }

            SECTION("object")
            {
                json j({{"foo", "bar"}});
                json::iterator it = j.begin();
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
                ++it;
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
            }

            SECTION("array")
            {
                json j({1, 2, 3, 4});
                json::iterator it = j.begin();
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
                ++it;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                ++it;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                ++it;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                ++it;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
            }
        }

        SECTION("post-decrement")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator const it = j.end();
                CHECK((it.m_it.primitive_iterator.m_it == 1));
            }

            SECTION("number")
            {
                json j(17);
                json::iterator it = j.end();
                CHECK((it.m_it.primitive_iterator.m_it == 1));
                it--;
                CHECK((it.m_it.primitive_iterator.m_it == 0));
                it--;
                CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
            }

            SECTION("object")
            {
                json j({{"foo", "bar"}});
                json::iterator it = j.end();
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
                it--;
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
            }

            SECTION("array")
            {
                json j({1, 2, 3, 4});
                json::iterator it = j.end();
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
                it--;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                it--;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                it--;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                it--;
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
            }
        }

        SECTION("pre-decrement")
        {
            SECTION("null")
            {
                json j(json::value_t::null);
                json::iterator const it = j.end();
                CHECK((it.m_it.primitive_iterator.m_it == 1));
            }

            SECTION("number")
            {
                json j(17);
                json::iterator it = j.end();
                CHECK((it.m_it.primitive_iterator.m_it == 1));
                --it;
                CHECK((it.m_it.primitive_iterator.m_it == 0));
                --it;
                CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
            }

            SECTION("object")
            {
                json j({{"foo", "bar"}});
                json::iterator it = j.end();
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
                --it;
                CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
            }

            SECTION("array")
            {
                json j({1, 2, 3, 4});
                json::iterator it = j.end();
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
                --it;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                --it;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                --it;
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
                --it;
                CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
                CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
            }
        }
    }
    SECTION("equality-preserving")
    {
        SECTION("post-increment")
        {
            SECTION("primitive_iterator_t")
            {
                using Iter = nlohmann::detail::primitive_iterator_t;
                CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
            }
            SECTION("iter_impl")
            {
                using Iter = nlohmann::detail::iter_impl<json>;
                CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
            }
            SECTION("json_reverse_iterator")
            {
                using Base = nlohmann::detail::iter_impl<json>;
                using Iter = nlohmann::detail::json_reverse_iterator<Base>;
                CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value);
            }
        }
        SECTION("post-decrement")
        {
            SECTION("primitive_iterator_t")
            {
                using Iter = nlohmann::detail::primitive_iterator_t;
                CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value);
            }
            SECTION("iter_impl")
            {
                using Iter = nlohmann::detail::iter_impl<json>;
                CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value );
            }
            SECTION("json_reverse_iterator")
            {
                using Base = nlohmann::detail::iter_impl<json>;
                using Iter = nlohmann::detail::json_reverse_iterator<Base>;
                CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value );
            }
        }
    }
    // prevent "accidental mutation of a temporary object"
    SECTION("cert-dcl21-cpp")
    {
        using nlohmann::detail::is_detected;
        SECTION("post-increment")
        {
            SECTION("primitive_iterator_t")
            {
                using Iter = nlohmann::detail::primitive_iterator_t;
                CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
            }
            SECTION("iter_impl")
            {
                using Iter = nlohmann::detail::iter_impl<json>;
                CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
            }
            SECTION("json_reverse_iterator")
            {
                using Base = nlohmann::detail::iter_impl<json>;
                using Iter = nlohmann::detail::json_reverse_iterator<Base>;
                CHECK_FALSE(is_detected<can_post_increment_temporary, Iter&>::value);
            }
        }
        SECTION("post-decrement")
        {
            SECTION("primitive_iterator_t")
            {
                using Iter = nlohmann::detail::primitive_iterator_t;
                CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
            }
            SECTION("iter_impl")
            {
                using Iter = nlohmann::detail::iter_impl<json>;
                CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
            }
            SECTION("json_reverse_iterator")
            {
                using Base = nlohmann::detail::iter_impl<json>;
                using Iter = nlohmann::detail::json_reverse_iterator<Base>;
                CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
            }

        }
    }
}


Import assertion

From source code

From dependency


;(function () {
  var freeExports =
    typeof exports === 'object' && exports && !exports.nodeType && exports

  var freeModule =
    freeExports &&
    typeof module === 'object' &&
    module &&
    !module.nodeType &&
    module

  function cloneDeep(value) {
    if (value == null || typeof value !== 'object') {
      return value
    }

    if (Array.isArray(value)) {
      return value.map(cloneDeep)
    }

    const cloned = {}
    for (const key in value) {
      if (Object.hasOwn(value, key)) {
        cloned[key] = cloneDeep(value[key])
      }
    }
    return cloned
  }

  const lodash = {}
  lodash.cloneDeep = cloneDeep

  if (freeModule) {
    ;(freeModule.exports = lodash).lodash = lodash
    freeExports.lodash = lodash
  }
}).call(this)


# Serialization

Serialization is the process of turning a JSON value back into JSON text. It is the counterpart to
[parsing](parsing/index.md). The central function is [`dump`](../api/basic_json/dump.md), which returns the JSON text as
a string.

```cpp
json j = {{"pi", 3.141}, {"happy", true}};

std::string s = j.dump();   // {"happy":true,"pi":3.141}
```

To write a value directly to a stream (for example, a file or `#!cpp std::cout`), the
[`operator<<`](../api/operator_ltlt.md) is provided:

```cpp
std::cout << j << std::endl;
```

!!! note "String, not raw value"

    `dump` always returns a **JSON text**. Serializing a JSON string therefore includes the surrounding quotes and
    escapes special characters. To obtain the *contained* string value without quotes, use
    [`get<std::string>()`](conversions.md) instead of `dump`. See the [converting values](conversions.md) page.

## Pretty-printing

By default, `dump` produces the most compact representation without any superfluous whitespace. Passing a non-negative
`indent` argument pretty-prints the output with the given number of spaces per level:

??? example

    ```cpp
    --8<-- "examples/dump.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/dump.output"
    ```

The indentation character can be changed with the second argument (e.g., a tab `#!cpp '\t'`). An `indent` of `0` inserts
newlines but no leading spaces, and the default of `#!cpp -1` selects the compact single-line form.

## Non-ASCII characters

Strings are stored and serialized as UTF-8 (see [types](types/index.md#strings)). By default, `dump` copies valid
non-ASCII characters as-is. Setting the third argument `ensure_ascii` to `#!cpp true` escapes all non-ASCII characters
with `\uXXXX` sequences, so that the output contains only ASCII characters:

```cpp
json j = "苹果";
j.dump();               // "苹果"
j.dump(-1, ' ', true);  // "苹果"
```

## Handling invalid UTF-8

If a string contains invalid UTF-8 sequences (for example, because it holds data in another encoding such as Latin-1),
serialization fails by default. The fourth argument of `dump` selects an
[`error_handler`](../api/basic_json/error_handler_t.md):

- `strict` (default) — throw a [`type_error.316`](../home/exceptions.md#jsonexceptiontype_error316) exception.
- `replace` — replace invalid bytes with the Unicode replacement character U+FFFD (`�`).
- `ignore` — silently drop invalid bytes.

??? example

    ```cpp
    --8<-- "examples/error_handler_t.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/error_handler_t.output"
    ```

!!! tip "Avoiding invalid UTF-8"

    The best fix is to ensure that all strings are UTF-8 encoded before storing them. See the
    [FAQ on non-ASCII characters](../home/faq.md#parse-errors-reading-non-ascii-characters) for how to convert wide or
    Latin-1 strings.

## Numbers, NaN, and binary values

- **Numbers** are serialized with enough precision to round-trip; see [number serialization](types/number_handling.md#number-serialization).
- **NaN and infinity** cannot be represented in JSON and are serialized as `#!json null`; see
  [NaN handling](types/number_handling.md#nan-handling). The [binary formats](binary_formats/index.md) can preserve
  them.
- **Binary values** have no JSON representation and are serialized as a helper object for debugging only; see
  [binary values](binary_values.md#serialization).

## Using `std::format`, `std::print`, and `fmt`

Since version 3.12.0, JSON values can be formatted directly with C++20's
[`std::format`](https://en.cppreference.com/w/cpp/utility/format/format) whenever the standard library provides the
`<format>` header (controlled by [`JSON_HAS_STD_FORMAT`](../api/macros/json_has_std_format.md)). This is enabled by the
[`std::formatter<basic_json>`](../api/basic_json/std_formatter.md) specialization, which also makes JSON values work with
`std::format_to` and with C++23's `std::print`/`std::println`:

```cpp
std::print("{}", j);      // compact, like j.dump()
std::print("{:2}", j);    // pretty-printed with indent 2 (like j.dump(2))
std::println("{:#}", j);  // pretty-printed with the default indent
```

The format spec mirrors the `dump` parameters: `#!cpp "{:#}"` pretty-prints, a width such as `#!cpp "{:2}"` sets the
indent, and a fill-and-align prefix such as `#!cpp "{:.>#}"` sets the indent character.

For the [{fmt}](https://github.com/fmtlib/fmt) library, the library ships a
[`format_as`](../api/basic_json/format_as.md) helper. Note its behavior depends on the `fmt` version; see the
[FAQ entry](../home/faq.md#using-json-values-with-stdformat-or-fmt) for the details and a recipe for a full
`fmt::formatter` specialization.

## Serializing to other formats

Besides JSON text, a value can also be serialized to the more compact [binary formats](binary_formats/index.md)
(BJData, BSON, CBOR, MessagePack, UBJSON).

## See also

- [`dump`](../api/basic_json/dump.md) - serialize to a JSON-formatted string
- [`operator<<`](../api/operator_ltlt.md) - serialize to a stream
- [`to_string`](../api/basic_json/to_string.md) - user-defined-conversion helper
- [`std::formatter<basic_json>`](../api/basic_json/std_formatter.md) - use JSON values with `std::format` and `std::print`
- [`format_as`](../api/basic_json/format_as.md) - use JSON values with the {fmt} library
- [Parsing](parsing/index.md) - the reverse operation


Promise.all([import('./deps-all-accepted'), import('./deps-some-accepted')])
  .then(([all, some]) => {
    log('loaded:all:' + all.a + all.b + all.c + all.default)
    log('loaded:some:' + some.a + some.b + some.c + some.default)
    log('>>> ready <<<')
  })
  .catch((err) => {
    log(err)
  })


# <small>nlohmann::json_sax::</small>binary

```cpp
virtual bool binary(binary_t& val) = 0;
```

A binary value was read.

## Parameters

`val` (in)
:   binary value

## Return value

Whether parsing should proceed.

## Notes

It is safe to move the passed binary value.

## Examples

??? example

    The example below shows how the SAX interface is used.

    ```cpp
    --8<-- "examples/sax_parse__binary.cpp"
    ```

    Output:

    ```json
    --8<-- "examples/sax_parse__binary.output"
    ```

## Version history

- Added in version 3.8.0.


import { virtual } from 'virtual:file'
import { virtual as virtualDep } from 'virtual:file-dep'
import { foo as depFoo, nestedFoo } from './hmrDep'
import './hotData'
import './importing-updated'
import './invalidation-circular-deps'
import './file-delete-restore'
import './optional-chaining/parent'
import './intermediate-file-delete'
import './circular'
import './prune'
import logo from './logo.svg'
import logoNoInline from './logo-no-inline.svg'
import { msg as softInvalidationMsg } from './soft-invalidation'

export const foo = 1
text('.app', foo)
text('.dep', depFoo)
text('.nested', nestedFoo)
text('.virtual', virtual)
text('.virtual-dep', virtualDep)
text('.soft-invalidation', softInvalidationMsg)
setImgSrc('#logo', logo)
setImgSrc('#logo-no-inline', logoNoInline)

text('.virtual-dep', 0)

const btn = document.querySelector('.virtual-update') as HTMLButtonElement
btn.onclick = () => {
  if (import.meta.hot) {
    import.meta.hot.send('virtual:increment')
  }
}

const btnDep = document.querySelector(
  '.virtual-update-dep',
) as HTMLButtonElement
btnDep.onclick = () => {
  if (import.meta.hot) {
    import.meta.hot.send('virtual:increment', '-dep')
  }
}

if (import.meta.hot) {
  import.meta.hot.accept(({ foo }) => {
    console.log('(self-accepting 1) foo is now:', foo)
  })

  import.meta.hot.accept(({ foo }) => {
    console.log('(self-accepting 2) foo is now:', foo)
  })

  const handleDep = (type, newFoo, newNestedFoo) => {
    console.log(`(${type}) foo is now: ${newFoo}`)
    console.log(`(${type}) nested foo is now: ${newNestedFoo}`)
    text('.dep', newFoo)
    text('.nested', newNestedFoo)
  }

  import.meta.hot.accept('./logo.svg', (newUrl) => {
    setImgSrc('#logo', newUrl.default)
    console.log('Logo updated', newUrl.default)
  })

  import.meta.hot.accept('./logo-no-inline.svg', (newUrl) => {
    setImgSrc('#logo-no-inline', newUrl.default)
    console.log('Logo-no-inline updated', newUrl.default)
  })

  import.meta.hot.accept('./hmrDep', ({ foo, nestedFoo }) => {
    handleDep('single dep', foo, nestedFoo)
  })

  import.meta.hot.accept('virtual:file-dep', ({ virtual }) => {
    text('.virtual-dep', virtual)
  })

  import.meta.hot.accept(['./hmrDep'], ([{ foo, nestedFoo }]) => {
    handleDep('multi deps', foo, nestedFoo)
  })

  import.meta.hot.dispose(() => {
    console.log(`foo was:`, foo)
  })

  import.meta.hot.on('vite:afterUpdate', (event) => {
    console.log(`>>> vite:afterUpdate -- ${event.type}`)
  })

  import.meta.hot.on('vite:beforeUpdate', (event) => {
    console.log(`>>> vite:beforeUpdate -- ${event.type}`)

    const cssUpdate = event.updates.find(
      (update) =>
        update.type === 'css-update' && update.path.includes('global.css'),
    )
    if (cssUpdate) {
      text(
        '.css-prev',
        (document.querySelector('.global-css') as HTMLLinkElement).href,
      )

      // Wait until the tag has been swapped out, which includes the time taken
      // to download and parse the new stylesheet. Assert the swapped link.
      const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          mutation.addedNodes.forEach((node) => {
            if (
              node.nodeType === Node.ELEMENT_NODE &&
              (node as Element).tagName === 'LINK'
            ) {
              text('.link-tag-added', 'yes')
            }
          })
          mutation.removedNodes.forEach((node) => {
            if (
              node.nodeType === Node.ELEMENT_NODE &&
              (node as Element).tagName === 'LINK'
            ) {
              text('.link-tag-removed', 'yes')
              text(
                '.css-post',
                (document.querySelector('.global-css') as HTMLLinkElement).href,
              )
            }
          })
        })
      })

      observer.observe(document.querySelector('#style-tags-wrapper'), {
        childList: true,
      })
    }
  })

  import.meta.hot.on('vite:error', (event) => {
    console.log(`>>> vite:error -- ${event.err.message}`)
  })

  import.meta.hot.on('vite:invalidate', ({ path }) => {
    console.log(`>>> vite:invalidate -- ${path}`)
  })

  import.meta.hot.on('custom:foo', ({ msg }) => {
    text('.custom', msg)
  })

  import.meta.hot.on('custom:remove', removeCb)

  // send custom event to server to calculate 1 + 2
  import.meta.hot.send('custom:remote-add', { a: 1, b: 2 })
  import.meta.hot.on('custom:remote-add-result', ({ result }) => {
    text('.custom-communication', result)
  })
}

function text(el, text) {
  document.querySelector(el).textContent = text
}

function setImgSrc(el, src) {
  ;(document.querySelector(el) as HTMLImageElement).src = src
}

function removeCb({ msg }) {
  text('.toRemove', msg)
  import.meta.hot.off('custom:remove', removeCb)
}


#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    json j;
    j["address"]["street"] = "Fake Street";
    j["address"]["housenumber"] = "12";

    try
    {
        int housenumber = j["address"]["housenumber"];
    }
    catch (const json::exception& e)
    {
        std::cout << e.what() << '\n';
    }
}


import fs from 'node:fs'
import fsp from 'node:fs/promises'
import path from 'node:path'
import { performance } from 'node:perf_hooks'
import { scan } from 'rolldown/experimental'
import type { TransformOptions as OxcTransformOptions } from 'rolldown/utils'
import { transformSync } from 'rolldown/utils'
import type { PartialResolvedId, Plugin } from 'rolldown'
import colors from 'picocolors'
import { glob } from 'tinyglobby'
import {
  CSS_LANGS_RE,
  JS_TYPES_RE,
  KNOWN_ASSET_TYPES,
  SPECIAL_QUERY_RE,
} from '../constants'
import {
  arraify,
  asyncFlatten,
  createDebugger,
  dataUrlRE,
  deepClone,
  externalRE,
  isInNodeModules,
  isObject,
  isOptimizable,
  moduleListContains,
  multilineCommentsRE,
  normalizePath,
  singlelineCommentsRE,
  virtualModulePrefix,
  virtualModuleRE,
} from '../utils'
import type { EnvironmentPluginContainer } from '../server/pluginContainer'
import {
  ERR_CLOSED_SERVER,
  createEnvironmentPluginContainer,
} from '../server/pluginContainer'
import { BaseEnvironment } from '../baseEnvironment'
import type { DevEnvironment } from '../server/environment'
import { transformGlobImport } from '../plugins/importMetaGlob'
import { cleanUrl } from '../../shared/utils'
import { getRollupJsxPresets } from '../plugins/oxc'

export class ScanEnvironment extends BaseEnvironment {
  mode = 'scan' as const

  get pluginContainer(): EnvironmentPluginContainer {
    if (!this._pluginContainer)
      throw new Error(
        `${this.name} environment.pluginContainer called before initialized`,
      )
    return this._pluginContainer
  }
  /**
   * @internal
   */
  _pluginContainer: EnvironmentPluginContainer | undefined

  async init(): Promise<void> {
    if (this._initiated) {
      return
    }
    this._initiated = true
    this._pluginContainer = await createEnvironmentPluginContainer(
      this,
      this.plugins,
      undefined,
      false,
    )
  }
}

// Restrict access to the module graph and the server while scanning
export function devToScanEnvironment(
  environment: DevEnvironment,
): ScanEnvironment {
  return {
    mode: 'scan',
    get name() {
      return environment.name
    },
    getTopLevelConfig() {
      return environment.getTopLevelConfig()
    },
    get config() {
      return environment.config
    },
    get logger() {
      return environment.logger
    },
    get pluginContainer() {
      return environment.pluginContainer
    },
    get plugins() {
      return environment.plugins
    },
  } as unknown as ScanEnvironment
}

const debug = createDebugger('vite:deps')

const htmlTypesRE = /\.(?:html|vue|svelte|astro|imba)$/

// A simple regex to detect import sources. This is only used on
// <script lang="ts"> blocks in vue (setup only) or svelte files, since
// seemingly unused imports are dropped by esbuild when transpiling TS which
// prevents it from crawling further.
// We can't use es-module-lexer because it can't handle TS, and don't want to
// use Acorn because it's slow. Luckily this doesn't have to be bullet proof
// since even missed imports can be caught at runtime, and false positives will
// simply be ignored.
export const importsRE: RegExp =
  /(?<!\/\/.*)(?<=^|;|\*\/)\s*import(?!\s+type)(?:[\w*{}\n\r\t, ]+from)?\s*("[^"]+"|'[^']+')\s*(?=$|;|\/\/|\/\*)/gm

export function scanImports(environment: ScanEnvironment): {
  cancel: () => Promise<void>
  result: Promise<{
    deps: Record<string, string>
    missing: Record<string, string>
  }>
} {
  const start = performance.now()
  const { config } = environment

  const scanContext = { cancelled: false }
  async function cancel() {
    scanContext.cancelled = true
  }

  async function scan() {
    const entries = await computeEntries(environment)
    if (!entries.length) {
      if (
        !config.optimizeDeps.entries &&
        !config.optimizeDeps.include &&
        !config.input
      ) {
        environment.logger.warn(
          colors.yellow(
            '(!) Could not auto-determine entry point from rolldownOptions or html files ' +
              'and there are no explicit optimizeDeps.include patterns. ' +
              'Skipping dependency pre-bundling.',
          ),
        )
      }
      return
    }
    if (scanContext.cancelled) return

    debug?.(
      `Crawling dependencies using entries: ${entries
        .map((entry) => `\n  ${colors.dim(entry)}`)
        .join('')}`,
    )
    const deps: Record<string, string> = {}
    const missing: Record<string, string> = {}

    const context = await prepareRolldownScanner(
      environment,
      entries,
      deps,
      missing,
    )
    if (scanContext.cancelled) return

    try {
      await context.build()
      return {
        // Ensure a fixed order so hashes are stable and improve logs
        deps: orderedDependencies(deps),
        missing,
      }
    } catch (e) {
      // The scanner runs in the background and may still be crawling when the
      // server is closed. In that case resolutions reject with
      // `ERR_CLOSED_SERVER` and the scan build fails.
      if (
        e.errors?.some(
          (error: { pluginCode?: string }) =>
            error.pluginCode === ERR_CLOSED_SERVER,
        )
      ) {
        return
      }
      const prependMessage = colors.red(`\
  Failed to scan for dependencies from entries:
  ${entries.join('\n')}

  `)
      e.message = prependMessage + e.message
      throw e
    } finally {
      if (debug) {
        const duration = (performance.now() - start).toFixed(2)
        const depsStr =
          Object.keys(orderedDependencies(deps))
            .sort()
            .map((id) => `\n  ${colors.cyan(id)} -> ${colors.dim(deps[id])}`)
            .join('') || colors.dim('no dependencies found')
        debug(`Scan completed in ${duration}ms: ${depsStr}`)
      }
    }
  }
  const result = scan()

  return {
    cancel,
    result: result.then((res) => res ?? { deps: {}, missing: {} }),
  }
}

async function computeEntries(environment: ScanEnvironment) {
  let entries: string[] = []

  const explicitEntryPatterns = environment.config.optimizeDeps.entries
  const input =
    environment.config.input ?? environment.config.build.rolldownOptions.input

  if (explicitEntryPatterns) {
    entries = await globEntries(explicitEntryPatterns, environment)
  } else if (input) {
    const resolvePath = async (p: string) => {
      const id = (
        await environment.pluginContainer.resolveId(p, undefined, {
          isEntry: true,
          scan: true,
        })
      )?.id
      if (id === undefined) {
        throw new Error(
          `failed to resolve rolldownOptions.input value: ${JSON.stringify(p)}.`,
        )
      }
      return id
    }
    if (typeof input === 'string') {
      entries = [await resolvePath(input)]
    } else if (Array.isArray(input)) {
      entries = await Promise.all(input.map(resolvePath))
    } else if (isObject(input)) {
      entries = await Promise.all(Object.values(input).map(resolvePath))
    } else {
      throw new Error('invalid rolldownOptions.input value.')
    }
  } else {
    entries = await globEntries('**/*.html', environment)
  }

  // Non-supported entry file types and virtual files should not be scanned for
  // dependencies.
  entries = entries.filter(
    (entry) =>
      isScannable(entry, environment.config.optimizeDeps.extensions) &&
      fs.existsSync(entry),
  )

  return entries
}

async function prepareRolldownScanner(
  environment: ScanEnvironment,
  entries: string[],
  deps: Record<string, string>,
  missing: Record<string, string>,
): Promise<{ build: () => Promise<void> }> {
  const { plugins: pluginsFromConfig = [], ...rolldownOptions } =
    environment.config.optimizeDeps.rolldownOptions ?? {}

  const transformOptions = deepClone(rolldownOptions.transform) ?? {}
  if (transformOptions.jsx === undefined) {
    transformOptions.jsx = {}
  } else if (
    transformOptions.jsx === 'react' ||
    transformOptions.jsx === 'react-jsx'
  ) {
    transformOptions.jsx = getRollupJsxPresets(transformOptions.jsx)
  }
  if (typeof transformOptions.jsx === 'object') {
    transformOptions.jsx.development ??= !environment.config.isProduction
  }
  const transformSyncJsxOptions: OxcTransformOptions['jsx'] =
    transformOptions.jsx === false ? undefined : transformOptions.jsx

  const plugins = await asyncFlatten(arraify(pluginsFromConfig))
  plugins.push(
    ...rolldownScanPlugin(
      environment,
      deps,
      missing,
      entries,
      transformSyncJsxOptions,
    ),
  )

  async function build() {
    await scan({
      ...rolldownOptions,
      transform: transformOptions,
      input: entries,
      logLevel: 'silent',
      plugins,
    })
  }

  return { build }
}

function orderedDependencies(deps: Record<string, string>) {
  const depsList = Object.entries(deps)
  // Ensure the same browserHash for the same set of dependencies
  depsList.sort((a, b) => a[0].localeCompare(b[0]))
  return Object.fromEntries(depsList)
}

async function globEntries(
  patterns: string | string[],
  environment: ScanEnvironment,
) {
  const nodeModulesPatterns: string[] = []
  const regularPatterns: string[] = []

  for (const pattern of arraify(patterns)) {
    if (pattern.includes('node_modules')) {
      nodeModulesPatterns.push(pattern)
    } else {
      regularPatterns.push(pattern)
    }
  }

  const sharedOptions = {
    absolute: true,
    cwd: environment.config.root,
    ignore: [
      `**/${environment.config.build.outDir}/**`,
      // if there aren't explicit entries, also ignore other common folders
      ...(environment.config.optimizeDeps.entries
        ? []
        : [`**/__tests__/**`, `**/coverage/**`]),
    ],
  }

  const results = await Promise.all([
    glob(nodeModulesPatterns, sharedOptions),
    glob(regularPatterns, {
      ...sharedOptions,
      ignore: [...sharedOptions.ignore, '**/node_modules/**'],
    }),
  ])

  return results.flat()
}

type Loader = 'js' | 'ts' | 'jsx' | 'tsx'

export const scriptRE: RegExp =
  /(<script(?:\s+[a-z_:][-\w:]*(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^"'<>=\s]+))?)*\s*>)(.*?)<\/script>/gis
export const commentRE: RegExp = /<!--.*?-->/gs
const srcRE = /\bsrc\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s'">]+))/i
const typeRE = /\btype\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s'">]+))/i
const langRE = /\blang\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s'">]+))/i
const svelteScriptModuleRE =
  /\bcontext\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s'">]+))/i
const svelteModuleRE = /\smodule\b/i

function rolldownScanPlugin(
  environment: ScanEnvironment,
  depImports: Record<string, string>,
  missing: Record<string, string>,
  entries: string[],
  jsxOptions: OxcTransformOptions['jsx'],
): Plugin[] {
  const seen = new Map<string, string | undefined>()
  async function resolveId(
    id: string,
    importer?: string,
    options?: Parameters<EnvironmentPluginContainer['resolveId']>[2],
  ): Promise<PartialResolvedId | null> {
    return environment.pluginContainer.resolveId(
      id,
      importer && normalizePath(importer),
      { scan: true, ...options },
    )
  }
  const resolve = async (
    id: string,
    importer?: string,
    options?: Parameters<typeof resolveId>[2],
  ) => {
    const key = JSON.stringify([
      id,
      importer && path.dirname(importer),
      options,
    ])
    if (seen.has(key)) {
      return seen.get(key)
    }
    const resolved = await resolveId(id, importer, options)
    const res = resolved?.id
    seen.set(key, res)
    return res
  }

  const optimizeDepsOptions = environment.config.optimizeDeps
  const include = optimizeDepsOptions.include
  const exclude = [
    ...(optimizeDepsOptions.exclude ?? []),
    '@vite/client',
    '@vite/env',
  ]

  const externalUnlessEntry = ({ path }: { path: string }) => ({
    id: path,
    external: !entries.includes(path),
  })

  const doTransformGlobImport = async (
    contents: string,
    id: string,
    loader: Loader,
  ) => {
    let transpiledContents: string
    // transpile because `transformGlobImport` only expects js
    if (loader !== 'js') {
      const result = transformSync(id, contents, {
        ...(jsxOptions !== undefined ? { jsx: jsxOptions } : {}),
        lang: loader,
        tsconfig: false,
      })
      if (result.errors.length > 0) {
        throw new AggregateError(result.errors, 'oxc transform error')
      }
      transpiledContents = result.code
    } else {
      transpiledContents = contents
    }

    const result = await transformGlobImport(
      transpiledContents,
      id,
      environment.config.root,
      resolve,
    )

    return result?.s.toString() || transpiledContents
  }

  const scripts: Record<
    string,
    {
      contents: string
      loader: Loader
    }
  > = {}

  const htmlTypeOnLoadCallback = async (id: string): Promise<string> => {
    let raw = await fsp.readFile(id, 'utf-8')
    // Avoid matching the content of the comment
    raw = raw.replace(commentRE, '<!---->')
    const isHtml = id.endsWith('.html')
    let js = ''
    let scriptId = 0
    const matches = raw.matchAll(scriptRE)
    for (const [, openTag, content] of matches) {
      const typeMatch = typeRE.exec(openTag)
      const type = typeMatch && (typeMatch[1] || typeMatch[2] || typeMatch[3])
      const langMatch = langRE.exec(openTag)
      const lang = langMatch && (langMatch[1] || langMatch[2] || langMatch[3])
      // skip non type module script
      if (isHtml && type !== 'module') {
        continue
      }
      // skip type="application/ld+json" and other non-JS types
      if (
        type &&
        !(
          type.includes('javascript') ||
          type.includes('ecmascript') ||
          type === 'module'
        )
      ) {
        continue
      }
      let loader: Loader = 'js'
      if (lang === 'ts' || lang === 'tsx' || lang === 'jsx') {
        loader = lang
      } else if (id.endsWith('.astro')) {
        loader = 'ts'
      }
      const srcMatch = srcRE.exec(openTag)
      if (srcMatch) {
        const src = srcMatch[1] || srcMatch[2] || srcMatch[3]
        js += `import ${JSON.stringify(src)}\n`
      } else if (content.trim()) {
        // The reason why virtual modules are needed:
        // 1. There can be module scripts (`<script context="module">` in Svelte and `<script>` in Vue)
        // or local scripts (`<script>` in Svelte and `<script setup>` in Vue)
        // 2. There can be multiple module scripts in html
        // We need to handle these separately in case variable names are reused between them

        // append imports in TS to prevent esbuild from removing them
        // since they may be used in the template
        const contents =
          content + (loader.startsWith('ts') ? extractImportPaths(content) : '')

        const key = `${id}?id=${scriptId++}`
        if (contents.includes('import.meta.glob')) {
          scripts[key] = {
            loader: 'js', // since it is transpiled
            contents: await doTransformGlobImport(contents, id, loader),
          }
        } else {
          scripts[key] = {
            loader,
            contents,
          }
        }

        const virtualModulePath = JSON.stringify(virtualModulePrefix + key)

        let addedImport = false

        // For Svelte files, exports in <script context="module"> or <script module> means module exports,
        // exports in <script> means component props. To avoid having two same export name from the
        // star exports, we need to ignore exports in <script>
        if (id.endsWith('.svelte')) {
          let isModule = svelteModuleRE.test(openTag) // test for svelte5 <script module> syntax
          if (!isModule) {
            // fallback, test for svelte4 <script context="module"> syntax
            const contextMatch = svelteScriptModuleRE.exec(openTag)
            const context =
              contextMatch &&
              (contextMatch[1] || contextMatch[2] || contextMatch[3])
            isModule = context === 'module'
          }
          if (!isModule) {
            addedImport = true
            js += `import ${virtualModulePath}\n`
          }
        }

        if (!addedImport) {
          js += `export * from ${virtualModulePath}\n`
        }
      }
    }

    // This will trigger incorrectly if `export default` is contained
    // anywhere in a string. Svelte and Astro files can't have
    // `export default` as code so we know if it's encountered it's a
    // false positive (e.g. contained in a string)
    if (!id.endsWith('.vue') || !js.includes('export default')) {
      js += '\nexport default {}'
    }

    return js
  }

  const ASSET_TYPE_RE = new RegExp(`\\.(${KNOWN_ASSET_TYPES.join('|')})$`)

  return [
    {
      name: 'vite:dep-scan:resolve-external-url',
      resolveId: {
        // external urls
        filter: { id: externalRE },
        handler: (id) => ({ id, external: true }),
      },
    },
    {
      name: 'vite:dep-scan:resolve-data-url',
      resolveId: {
        // data urls
        filter: { id: dataUrlRE },
        handler: (id) => ({ id, external: true }),
      },
    },
    {
      // local scripts (`<script>` in Svelte and `<script setup>` in Vue)
      name: 'vite:dep-scan:local-scripts',
      resolveId: {
        filter: { id: virtualModuleRE },
        handler: (id) => ({ id }),
      },
      load: {
        filter: { id: virtualModuleRE },
        handler(id) {
          const script = scripts[id.replace(virtualModulePrefix, '')]
          return {
            code: script.contents,
            moduleType: script.loader,
          }
        },
      },
    },

    {
      name: 'vite:dep-scan:resolve',
      async resolveId(id, importer) {
        // Make sure virtual module importer can be resolve
        importer =
          importer && virtualModuleRE.test(importer)
            ? importer.replace(virtualModulePrefix, '')
            : importer

        // html types: extract script contents -----------------------------------
        if (htmlTypesRE.test(id)) {
          const resolved = await resolve(id, importer)
          if (!resolved) return
          // It is possible for the scanner to scan html types in node_modules.
          // If we can optimize this html type, skip it so it's handled by the
          // bare import resolve, and recorded as optimization dep.
          if (
            isInNodeModules(resolved) &&
            isOptimizable(resolved, optimizeDepsOptions)
          )
            return
          if (shouldExternalizeDep(resolved, id)) {
            return externalUnlessEntry({ path: id })
          }
          return resolved
        }

        // bare imports: record and externalize ----------------------------------
        // avoid matching windows volume
        if (/^[\w@][^:]/.test(id)) {
          if (moduleListContains(exclude, id)) {
            return externalUnlessEntry({ path: id })
          }
          if (depImports[id]) {
            return externalUnlessEntry({ path: id })
          }
          const resolved = await resolve(id, importer)
          if (resolved) {
            if (shouldExternalizeDep(resolved, id)) {
              return externalUnlessEntry({ path: id })
            }
            if (isInNodeModules(resolved) || include?.includes(id)) {
              // dependency or forced included, externalize and stop crawling
              if (isOptimizable(resolved, optimizeDepsOptions)) {
                depImports[id] = resolved
              }
              return externalUnlessEntry({ path: id })
            } else if (isScannable(resolved, optimizeDepsOptions.extensions)) {
              // linked package, keep crawling
              return path.resolve(resolved)
            } else {
              return externalUnlessEntry({ path: id })
            }
          } else {
            missing[id] = normalizePath(importer!)
          }
        }

        // Externalized file types -----------------------------------------------
        // these are done on raw ids using esbuild's native regex filter so it
        // should be faster than doing it in the catch-all via js
        // they are done after the bare import resolve because a package name
        // may end with these extensions

        // css
        if (CSS_LANGS_RE.test(id)) {
          return externalUnlessEntry({ path: id })
        }

        // json & wasm
        if (/\.(?:json|json5|wasm)$/.test(id)) {
          return externalUnlessEntry({ path: id })
        }

        // known asset types
        if (ASSET_TYPE_RE.test(id)) {
          return externalUnlessEntry({ path: id })
        }

        // known vite query types: ?worker, ?raw
        if (SPECIAL_QUERY_RE.test(id)) {
          return {
            id,
            external: true,
          }
        }

        // catch all -------------------------------------------------------------

        // use vite resolver to support urls and omitted extensions
        const resolved = await resolve(id, importer)
        if (resolved) {
          if (
            shouldExternalizeDep(resolved, id) ||
            !isScannable(resolved, optimizeDepsOptions.extensions)
          ) {
            return externalUnlessEntry({ path: id })
          }
          return path.resolve(cleanUrl(resolved))
        }

        // resolve failed... probably unsupported type
        return externalUnlessEntry({ path: id })
      },
    },
    {
      name: 'vite:dep-scan:load:html',
      load: {
        // extract scripts inside HTML-like files and treat it as a js module
        filter: { id: htmlTypesRE },
        async handler(id) {
          return {
            code: await htmlTypeOnLoadCallback(id),
            moduleType: 'js',
          }
        },
      },
    },
    // for jsx/tsx, we need to access the content and check for
    // presence of import.meta.glob, since it results in import relationships
    // but isn't crawled by esbuild.
    ...(environment.config.esbuild && environment.config.esbuild.jsxInject
      ? [
          {
            name: 'vite:dep-scan:transform:jsx-inject',
            transform: {
              filter: {
                id: /\.[jt]sx$/,
              },
              handler(code) {
                const esbuildConfig = environment.config.esbuild
                if (esbuildConfig && esbuildConfig.jsxInject) {
                  code = esbuildConfig.jsxInject + `\n` + code
                }
                return code
              },
            },
          } satisfies Plugin,
        ]
      : []),
    {
      name: 'vite:dep-scan:transform:js-glob',
      transform: {
        filter: {
          code: 'import.meta.glob',
        },
        async handler(code, id) {
          if (JS_TYPES_RE.test(id)) {
            let ext = path.extname(id).slice(1)
            if (ext === 'mjs') ext = 'js'
            const loader = ext as 'js' | 'ts' | 'jsx' | 'tsx'
            return {
              moduleType: 'js',
              code: await doTransformGlobImport(code, id, loader),
            }
          }
        },
      },
    },
  ]
}

/**
 * when using TS + (Vue + `<script setup>`) or Svelte, imports may seem
 * unused to esbuild and dropped in the build output, which prevents
 * esbuild from crawling further.
 * the solution is to add `import 'x'` for every source to force
 * esbuild to keep crawling due to potential side effects.
 */
function extractImportPaths(code: string) {
  // empty singleline & multiline comments to avoid matching comments
  code = code
    .replace(multilineCommentsRE, '/* */')
    .replace(singlelineCommentsRE, '')

  let js = ''
  let m
  importsRE.lastIndex = 0
  while ((m = importsRE.exec(code)) != null) {
    js += `\nimport ${m[1]}`
  }
  return js
}

function shouldExternalizeDep(resolvedId: string, rawId: string): boolean {
  // not a valid file path
  if (!path.isAbsolute(resolvedId)) {
    return true
  }
  // virtual id
  if (resolvedId === rawId || resolvedId.includes('\0')) {
    return true
  }
  return false
}

function isScannable(id: string, extensions: string[] | undefined): boolean {
  return (
    JS_TYPES_RE.test(id) ||
    htmlTypesRE.test(id) ||
    extensions?.includes(path.extname(id)) ||
    false
  )
}


# Environment API

:::info Release Candidate
The Environment API is generally in the release candidate phase. We'll maintain stability in the APIs between major releases to allow the ecosystem to experiment and build upon them. However, note that [some specific APIs](/changes/#considering) are still considered experimental.

We plan to stabilize these new APIs (with potential breaking changes) in a future major release once downstream projects have had time to experiment with the new features and validate them.

Resources:

- [Feedback discussion](https://github.com/vitejs/vite/discussions/16358) where we are gathering feedback about the new APIs.
- [Environment API PR](https://github.com/vitejs/vite/pull/16471) where the new APIs were implemented and reviewed.

Please share your feedback with us.
:::

## Formalizing Environments

Vite 6 formalizes the concept of Environments. Until Vite 5, there were two implicit Environments (`client`, and optionally `ssr`). The new Environment API allows users and framework authors to create as many environments as needed to map the way their apps work in production. This new capability required a big internal refactoring, but a lot of effort has been placed on backward compatibility. The initial goal of Vite 6 is to move the ecosystem to the new major as smoothly as possible, delaying the adoption of the APIs until enough users have migrated and frameworks and plugin authors have validated the new design.

## Closing the Gap Between Build and Dev

For a simple SPA/MPA, no new APIs around environments are exposed to the config. Internally, Vite will apply the options to a `client` environment, but it's not necessary to know of this concept when configuring Vite. The config and behavior from Vite 5 should work seamlessly here.

When we move to a typical server-side rendered (SSR) app, we'll have two environments:

- `client`: runs the app in the browser.
- `ssr`: runs the app in node (or other server runtimes) which renders pages before sending them to the browser.

In dev, Vite executes the server code in the same Node process as the Vite dev server, giving a close approximation to the production environment. However, it is also possible for servers to run in other JS runtimes, like [Cloudflare's workerd](https://github.com/cloudflare/workerd) which have different constraints. Modern apps may also run in more than two environments, e.g. a browser, a node server, and an edge server. Vite 5 didn't allow to properly represent these environments.

Vite 6 allows users to configure their app during build and dev to map all of its environments. During dev, a single Vite dev server can now be used to run code in multiple different environments concurrently. The app source code is still transformed by Vite dev server. On top of the shared HTTP server, middlewares, resolved config, and plugins pipeline, the Vite dev server now has a set of independent dev environments. Each of them is configured to match the production environment as closely as possible, and is connected to a dev runtime where the code is executed (for workerd, the server code can now run in miniflare locally). In the client, the browser imports and executes the code. In other environments, a module runner fetches and evaluates the transformed code.

![Vite Environments](../images/vite-environments.svg)

## Environments Configuration

For an SPA/MPA, the configuration will look similar to Vite 5. Internally these options are used to configure the `client` environment.

```js
export default defineConfig({
  build: {
    sourcemap: false,
  },
  optimizeDeps: {
    include: ['lib'],
  },
})
```

This is important because we'd like to keep Vite approachable and avoid exposing new concepts until they are needed.

If the app is composed of several environments, then these environments can be configured explicitly with the `environments` config option.

```js
export default {
  build: {
    sourcemap: false,
  },
  optimizeDeps: {
    include: ['lib'],
  },
  environments: {
    server: {},
    edge: {
      resolve: {
        noExternal: true,
      },
    },
  },
}
```

When not explicitly documented, environment inherits the configured top-level config options (for example, the new `server` and `edge` environments will inherit the `build.sourcemap: false` option). A small number of top-level options, like `optimizeDeps`, only apply to the `client` environment, as they don't work well when applied as a default to server environments. Those options have <NonInheritBadge /> badge in [the reference](/config/). The `client` environment can also be configured explicitly through `environments.client`, but we recommend to do it with the top-level options so the client config remains unchanged when adding new environments.

The `EnvironmentOptions` interface exposes all the per-environment options. There are environment options that apply to both `build` and `dev`, like `resolve`. And there are `DevEnvironmentOptions` and `BuildEnvironmentOptions` for dev and build specific options (like `dev.warmup` or `build.outDir`). Some options like `optimizeDeps` only applies to dev, but is kept as top level instead of nested in `dev` for backward compatibility.

```ts
interface EnvironmentOptions {
  define?: Record<string, any>
  resolve?: EnvironmentResolveOptions
  optimizeDeps: DepOptimizationOptions
  consumer?: 'client' | 'server'
  dev: DevOptions
  build: BuildOptions
}
```

The `UserConfig` interface extends from the `EnvironmentOptions` interface, allowing to configure the client and defaults for other environments, configured through the `environments` option. The `client` and a server environment named `ssr` are always present during dev. This allows backward compatibility with `server.ssrLoadModule(url)` and `server.moduleGraph`. During build, the `client` environment is always present, and the `ssr` environment is only present if it is explicitly configured (using `environments.ssr` or for backward compatibility `build.ssr`). An app doesn't need to use the `ssr` name for its SSR environment, it could name it `server` for example.

```ts
interface UserConfig extends EnvironmentOptions {
  environments: Record<string, EnvironmentOptions>
  // other options
}
```

Note that the `ssr` top-level property is going to be deprecated once the Environment API is stable. This option has the same role as `environments`, but for the default `ssr` environment and only allowed configuring of a small set of options.

## Custom Environment Instances

Low level configuration APIs are available so runtime providers can provide environments with proper defaults for their runtimes. These environments can also spawn other processes or threads to run the modules during dev in a closer runtime to the production environment.

For example, the [Cloudflare Vite plugin](https://developers.cloudflare.com/workers/vite-plugin/) uses the Environment API to run code in the Cloudflare Workers runtime (`workerd`) during development.

```js
import { customEnvironment } from 'vite-environment-provider'

export default {
  build: {
    outDir: '/dist/client',
  },
  environments: {
    ssr: customEnvironment({
      build: {
        outDir: '/dist/ssr',
      },
    }),
  },
}
```

## Backward Compatibility

The current Vite server API is not yet deprecated and is backward compatible with Vite 5.

The `server.moduleGraph` returns a mixed view of the client and ssr module graphs. Backward compatible mixed module nodes will be returned from all its methods. The same scheme is used for the module nodes passed to `handleHotUpdate`.

We don't recommend switching to Environment API yet. We are aiming for a good portion of the user base to adopt Vite 6 before so plugins don't need to maintain two versions. Checkout the future breaking changes section for information on future deprecations and upgrade path:

- [`this.environment` in Hooks](/changes/this-environment-in-hooks)
- [HMR `hotUpdate` Plugin Hook](/changes/hotupdate-hook)
- [Move to Per-environment APIs](/changes/per-environment-apis)
- [SSR Using `ModuleRunner` API](/changes/ssr-using-modulerunner)
- [Shared Plugins During Build](/changes/shared-plugins-during-build)

## Target Users

This guide provides the basic concepts about environments for end users.

Plugin authors have a more consistent API available to interact with the current environment configuration. If you're building on top of Vite, the [Environment API Plugins Guide](./api-environment-plugins.md) guide describes the way extended plugin APIs available to support multiple custom environments.

Frameworks could decide to expose environments at different levels. If you're a framework author, continue reading the [Environment API Frameworks Guide](./api-environment-frameworks) to learn about the Environment API programmatic side.

For Runtime providers, the [Environment API Runtimes Guide](./api-environment-runtimes.md) explains how to offer custom environments to be consumed by frameworks and users.