Skip to content

Configuration file

As all projects have different needs, we have an optional configuration file cloudpack.config.json that allows you to customize how Cloudpack works for your project.

How to set up

  1. Create a file at the root of the application package called cloudpack.config.json.
  2. Include the property "$schema": "https://unpkg.com/@ms-cloudpack/cli/schema/AppConfig.json" so that you get intellisense for config properties in the code editor.
  3. Define the optional properties that your project needs.

Cloudpack configs support comments. To prevent VS Code from showing errors on comments, you'll need to add the following to .vscode/settings.json:

json
"files.associations": {
  "cloudpack.*.json": "jsonc"
},

Examples

You can see a complete example of a small app and its config in Cloudpack's onedrive-mock app.

Cloudpack is designed to provide sensible defaults, so config settings should only be added as needed based on details of your app's setup. The following is just a sample of what an imaginary app's config might look like, not intended to be copy-pasted.

json
{
  "$schema": "https://unpkg.com/@ms-cloudpack/cli/schema/AppConfig.json",
  "server": {
    "port": 5050
  },
  "routes": [
    {
      "match": "/",
      "serverEntry": "./public/index.html",
      "entry": "./src/index.tsx"
    },
    {
      "match": "/custom",
      "serverEntry": "./scripts/custom.html.mjs"
    },
    {
      "match": "/about",
      "entry": "./src/about.tsx"
    }
  ],
  "features": {
    "disableSourceMaps": false,
    "enqueueDependencies": false
  },
  "define": {
    "FEATURE_FLAGS.enableNewUI": true,
    "API_CONFIG.endpoints": [
      "https://api.example.com/v1",
      "https://api.example.com/v2"
    ]
  },
  "remoteCache": {
    "storageAccount": "cloudpackcache",
    "container": "onedrive-mock"
  },
  "helpMessage": "Need help? Go to http://aka.ms/cloudpack-help and ask in our support channel!",
  "packageSettings": [
    {
      "match": "foo",
      "exports": { ".": "./mainFile.js" }
    },
    {
      "match": "bar",
      "inlinedDependencies": ["baz"]
    },
    {
      "match": ["@foo/*", "other-pkg"],
      "bundler": "rollup"
    },
    {
      "match": ["react", "react-dom", "react-is"],
      "link": {
        "duplicatedDependencyBehavior": "force-host-version"
      }
    }
  ]
}

To enable HTTPS:

json
{
  "$schema": "https://unpkg.com/@ms-cloudpack/cli/schema/AppConfig.json",
  "server": {
    "domain": "www.mywebsite.com",
    "port": 443,
    "https": {
      "cert": "/path/to/cert.pem",
      "key": "/path/to/key.pem"
    }
  }
}

Environment variable expansion

Cloudpack config files support environment variable expansion, allowing you to reference environment variables at Cloudpack startup time. The format is as follows:

{env:var_name}

Where var_name is the name of an environment variable that has been set. These symbols are expanded when the Cloudpack config file is loaded into memory.

Note that environment variable names are case sensitive.

For example:

json
{
  "$schema": "schema",
  "server": {
    "requestHeaders": {
      "X-AVETT": "Do you know something? {env:Avett} I really really do."
    }
  }
}

Assuming an environment variable named Avett is set to the string value I love the Avett Brothers!, then at run-time, the X-AVETT request header value will effectively be: Do you know something? I love the Avett Brothers! I really really do.

How and when you choose to set your environment variables is entirely up to you.

Available properties

The following top-level config properties are available. All properties are optional. (See the AppConfig source for the most up-to-date list.)

PropertyTypeDescription
extendsstring | string[]Extend the configuration from another file.
bundlerCapabilitiesRegistryRecord<string, string>Custom bundler capabilities.
defaultBundler'ori'|'rollup'|'rspack'|'webpack'Advanced used only: Override the bundler that's used by default (see details). Changing this will decrease performance, so in most cases, you should use targeted PackageSettings.bundler instead.
defineRecord<string, string | number | boolean | (string | number | boolean)[]>Global constants to be defined at compile time.
dependsOn[string, string[]][]Commands to execute prior to Cloudpack bundling. Each entry has a command and an array of arguments: ['command', ['arg1', 'arg2']].
featuresFeaturesEnable additional Cloudpack features.
helpMessagestringHelp message to display when Cloudpack starts up.
packageSettingsPackageSettings[]Settings to customize how packages are bundled.
patchFilesGlobPatternstringCustom glob pattern to match patch-package patch files, relative to the project root (default patches/*.patch).
remoteCacheRemoteCacheConfigAzure Blob Storage configuration for remote package cache (required for cloudpack sync).
routesRoute[]Register routes with the dev server to host various pages.
serverServerConfigConfiguration for the application server.
telemetryTelemetryConfigConfiguration for telemetry.

Default bundler

Cloudpack will try to use ori where possible, falling back to rollup for CommonJS packages or webpack in certain other cases. As of writing, it's the fastest bundler option Cloudpack offers for most cases: at least 30% faster than rspack. See the design docs for more on Cloudpack's bundler strategy.

If you only need to change the bundler for certain packages, use PackageSettings.bundler. defaultBundler is only intended for the case where ori doesn't work with your repo/build for some reason and you absolutely must use a different default bundler. Just be aware that changing defaultBundler will significantly decrease build performance, especially if you choose webpack. (If you're not comfortable with ori due to the private source, we recommend rspack.) Also note that changing defaultBundler only applies to cases where Cloudpack would usually choose ori, not cases like CJS where a different bundler is needed.

Extending configurations

Cloudpack supports config extension, promoting consistency and reuse.

The extends property can be either a single string or an array of strings. Both package import specifiers and relative paths are supported.

Configs are merged as follows:

  • The current app's config takes precedence over the extended config(s).
  • If extends is an array, properties from later configs take precedence over earlier ones.
  • Objects are deeply merged.
  • Primitive values are overwritten.
  • Arrays are overwritten, EXCEPT for packageSettings, which are concatenated.

In a monorepo with multiple apps, it's recommended to put most packageSettings in a shared config (unless there's some specific reason not to). This prevents duplication in case another app needs the same settings later.

Shared config packages

If you prefer to put the shared config(s) in a package rather than referencing them with relative paths, you can do this as follows.

  1. Create a package, e.g. my-shared-config, with a package.json and one or more cloudpack config files.

  2. The package can export either a single config which is referenced simply by the package name, or one or more configs which are referenced by paths within the package. Set this my-shared-config/package.json as follows:

    • Single config: Set "main" to point to your config file, e.g. "main": "cloudpack.base.json"

    • Multiple configs: It's recommended to use an exports map with a key for each config, e.g.:

      json
      {
        // ... other package.json properties omitted ...
        "exports": {
          // These keys can be anything you want (you could use the literal config file name)
          "./base": "./cloudpack.base.json",
          "./extra": "./cloudpack.extra.json"
        }
      }
  3. In the consuming app, ensure the shared config package is listed in devDependencies.

  4. In the consuming app's cloudpack.config.json, use the extends property:

    json
    {
      // Pick one of these patterns as appropriate...
      // If you exported one config:
      "extends": "my-shared-config",
      // If you exported multiple configs:
      "extends": "my-shared-config/base",
      // If you'd like to extend multiple configs:
      "extends": ["my-shared-config/base", "my-shared-config/extra"],
    
      // Extra properties will be merged in
      "helpMessage": "app help"
    }

Types

ServerConfig

Options for configuring how the dev server works. All properties are optional. (See the ServerConfig source for the most up-to-date list.)

PropertyTypeDefaultDescription
defaultPathstring''The default path under the domain to use when opening the browser.
domainstring | string[]'localhost'Domain name of the server. If multiple domains are specified, the first one will be used as the primary domain used when opening the browser.
httpsHttpsConfig | trueHTTPS configuration for the server. If not provided, the server will use HTTP. File paths are accepted for ca, cert, key, and pfx. Everything else is passed directly to https.createServer().
openboolean | stringtrueWhether to automatically open the browser when the server starts, or a specific URL to open. (You can also use the --open or --no-open CLI flags.)
portnumber | number[]The ports to be used by the server. If provided, an error will be thrown if none are available. If not provided, the server will attempt to find an available port.
requestHeadersRecord<string, string>Additional header key/value pairs to be added to every response.
showOverlay'always' | 'errors-only' | 'never''always'Whether to show the Cloudpack overlay (status badge and dialog) in the app UI. It's not recommended to change this unless the overlay is causing issues (and if it's only needed in a specific context, use the --show-overlay <when> CLI option).

To emulate a public path setting, use a static route like { "match": "*", "staticPath": "./public" }.

TelemetryConfig

Options for configuring telemetry. Telemetry is only collected if a key is provided, and it's only sent to the specified Application Insights instance. For teams within Microsoft, the Cloudpack team provides a shared instrumentation key to track usage on our internal dashboards.

(See the TelemetryConfig source for the most up-to-date list.)

PropertyTypeDescription
instrumentationKey (required)stringApplication Insights instrumentation key.

Features

Feature flags can be set to true to enable additional Cloudpack features. All features are optional. (See the allFeatures source for the most up-to-date list.)

PropertyTypeDescription
autoUpdateEntriesbooleanAutomatically updates the generated config when an unknown import path is used during start (default: true).
disableSourceMapsbooleanDisables the generation of source-maps during build.
enableCloudHostedbooleanEnables cloud-hosted application.
enableModuleWorkersbooleanEnables support of import maps for workers. To use this feature, the package with the worker must be bundled with webpack (default: true).
enableParcelWatcherbooleanEnables the use of @parcel/watcher for file watching (default: true).
enableRemoteCacheDownloadsbooleanEnables downloading bundles from remote cache instead of bundling.
enableSSRbooleanEnables server-side rendering (SSR) for the application. This is experimental and may not work in all cases.
enableWatcherInForkbooleanEnables the file watcher to be spawned in a forked process (default: true).
enqueueDependenciesbooleanEnables the preemptive enqueueing of dependencies during build.
evaluateDynamicImportsbooleanCheck for dynamic (async) imports with non-literal paths in bundle output during init.
optimizeDependenciesbooleanExcludes unused dependencies in the generated config during an init run. This helps trim the dependency graph, reduce the import map, and speed up performance.
relativeImportMapPathsbooleanEnables relative resource paths to be used in import map paths when useSingleWebServer is true (default: true).
removeUnusedExportsbooleanCreates null entries for unused exports in generated config so that they are not included when bundling.
resolveWebExtensions (deprecated)booleanRemoved in favor of resolve-web-extensions bundler capability. Enables React Native type resolution of .web.ts extensions.
syncBundlesbooleanEnables the syncing of bundles.
syncInternalPackagesbooleanEnables the syncing of internal packages.
useSingleWebServerbooleanUse a single server for both bundles and app assets (default: true).
verifyExportsbooleanEnables the verification of exports during init (default: true).

PackageSettings

An object used to provide settings for how we bundle packages. match is the only required property. (See the PackageSettings source for the most up-to-date list.)

When merging package settings, later settings take precedence over earlier ones. In most cases, object keys are merged, and arrays are concatenated. Exports maps are also concatenated. See the mergePackageSettings source for details.

PropertyTypeDescription
match (required)PackageSettingsMatch | PackageSettingsMatch[]Where to apply the settings.
includedDependenciesstring[]Include these dependencies when computing the import map. This is primarily used when dev dependencies are needed at runtime. '$devDependencies' will include all dev deps.
excludedDependenciesstring[]Ignore these dependencies when resolving all dependencies and running init. '$peerDependencies' will exclude all peer deps.
inlinedDependenciesstring[]Inline these dependencies in the library's bundle. This is useful for libraries which are small and don't need to be loaded separately, have issues being resolved by the browser, or provide scss files.
exportsExports mapUse this exports map instead of the original entry points from package.json. (Any Cloudpack-generated exports will be merged.) This is useful if a library's exports map is missing or broken, or to skip bundling entries which aren't needed at runtime.
bundlerstringForces the package to be bundled using a specific bundler. As of writing, the options are ori, rollup, rspack, webpack.
bundlerOptionsRecord<string, unknown>Any bundler-specific options to be merged with the calculated bundler options (requires bundler to be specified). Using this is generally not recommended since it locks the package to a specific bundler.
inputPathsstring[]Paths used for file monitoring and input hashing. More details about input paths
ignoreMissingExportsboolean | Record<string, string[]>Ignore issues with verifyExports: If true, don't check this package's exports. If an object, it's a mapping from import path (e.g. . or ./lib/foo) to export names to ignore.
ignoredBundlerWarningsstring[]Ignore these warning messages from the bundler (partial string matches). This is for non-actionable messages from external dependencies which can't easily be fixed, to avoid confusing users.
linkLinkOptionsControl how the package and its deps are handled in the resolve map by cloudpack link.
bundlerCapabilitiesBundlerCapabilitiesOptionsSee bundler capabilities.
unsafeCjsExportNames{ [exportsKey: string]: string[] } | 'types'For a CJS package only: provide hardcoded export names or generate from types, instead of running the code (see details).

PackageSettings.inputPaths

ts
interface PackageSettings {
  inputPaths?: string[]
}

Paths used for file monitoring and input hashing. Supports glob matching and ! for exclusions. Use ... to include the default values (see sourceFilesGlobs in linked file). node_modules is always ignored even without '...'.

For input hashing, both positive and negative globs are considered.

For file watching, behavior depends on the watcher backend:

  • Parcel watcher (default): only negative globs are respected for ignoring files (all non-ignored files under the package will be watched)
  • Chokidar watcher (with features.enableParcelWatcher: false): both positive and negative globs are supported

PackageSettings.match

ts
type PackageSettingsMatch = string | { name: string; version?: string }

interface PackageSettings {
  match: PackageSettingsMatch | PackageSettingsMatch[]
  // and other properties
}

Where to apply the settings. A string is a shorthand for name. Use an array for multiple matches.

PropertyTypeDescription
name (required)stringPackage name. It can end with a * wildcard.

Use a leading ! to negate the match: for example, "match": ["@scope/*", "!@scope/foo"].
versionstringAny valid semantic version or range (default *). Not supported with a negated (!) name.

PackageSettings.unsafeCjsExportNames

ts
interface PackageSettings {
  unsafeCjsExportNames?: { [exportsKey: string]: string[] } | 'types'
}

For a CJS package only: when generating ESM stubs for the package, this setting can be used to either provide hardcoded names or attempt to detect names from types, instead of by running the code.

An object is used to provide hardcoded export names. This is an escape hatch and should be used with caution, as it can lead to unexpected behavior. It's mainly intended to be used if the standard stub generation fails for some reason, or maybe is excessively slow for one package (please also let the team know if either of these happen).

  • Each key is a relative output file path (with forward slashes and leading ./) and without the extension (unless it's non-JS). Note that this is the actual file output path within the package, not an exports map key.
  • The value is a list of export names.
  • Any keys not included will have a default export, but no named exports (so {} means that all entries should have only a default export).

If set to 'types', Cloudpack will attempt to generate stubs based on TypeScript declaration files included with the package. This currently only works if there's a corresponding .d.ts file for each file being bundled. It will include named exports for all types in the declaration file and relative imported files.

LinkOptions

Package settings to control how the package and its deps are handled in the resolve map by cloudpack link.

PropertyTypeDescription
duplicatedDependencyBehaviorspecific strings (see below)Controls the behavior of duplicated dependencies in the resolve map when running cloudpack link.

duplicatedDependencyBehavior: Controls the behavior of duplicated dependencies in the resolve map when running cloudpack link. Options:

  • 'allow-duplication' (default): allow multiple versions of the same package to exist in the resolve map to satisfy semver.
  • 'force-host-version': the package will be deduplicated to the version of the host package, ignoring semver requirements.
  • 'force-remote-version': the package will be deduplicated to the version of the remote package, ignoring semver requirements.

RemoteCacheConfig

Azure Blob Storage configuration required for cloudpack sync to upload and download packages from the remote cache. (See the RemoteCacheConfig source for the most up-to-date list.)

PropertyTypeDescription
storageAccount (required)stringStorage account name
container (required)stringContainer name in the storage account
tenantIdstringThe Microsoft Entra tenant (directory) ID. This will ensure that only users from this tenant can access the remote cache.

Route

See Routing configuration.

Define

The define property allows you to define global constants for your application. How these constants are handled depends on the bundling mode:

  • In library mode (development): The values are added as global variables at runtime rather than being replaced during compilation. This increases bundle cache hit ratio since the bundles don't contain the specific values.
  • In production mode: Values are replaced at compile time, similar to webpack's DefinePlugin.

Values in the define object can be strings, numbers, booleans, or arrays of these primitive types. The key can use dot notation to create nested properties.

For example:

json
{
  "define": {
    "FEATURE_FLAGS.enableNewUI": true,
    "API_CONFIG.endpoints": [
      "https://api.example.com/v1",
      "https://api.example.com/v2"
    ]
  }
}

Usage in code

js
// Your code
if (FEATURE_FLAGS.enableNewUI) {
  // do something
}
API_CONFIG.endpoints.forEach((endpoint) => fetch(endpoint))

How it works in library mode (development)

Variables are available at runtime but not replaced during compilation. The bundles don't contain the specific values.

How it works in production mode

The code is transformed during compilation:

js
// After compilation in production mode
if (true) {
  // do something
}
;['https://api.example.com/v1', 'https://api.example.com/v2'].forEach(
  (endpoint) => fetch(endpoint),
)