Resources

The resources section of tps.json controls how static assets — JavaScript, CSS, fonts, images — are bundled, written to the output folder, embedded into the compiled assembly, and referenced from the generated index.html. It is what lets a self-contained Transpose library ship its own scripts and styles so that a consuming project gets them automatically.

This page covers what the section does, every key it accepts, how files are combined, and a worked example for a component library.

What resources does

A resources entry describes one group. For each group the compiler:

  1. Resolves the listed files (expanding a glob if there is one).
  2. Writes the result into the output folder, under the group's output sub-folder.
  3. Embeds it as a resource inside the compiled assembly, so a referencing project can extract it.
  4. Links it from the generated index.html — a <script> for JavaScript, a <link rel="stylesheet"> for CSS — unless the group opts out with load.
flowchart LR F["files[]<br/>app.js, util.js, …"] --> C["resolve<br/>(+ concatenate, for a bundle)"] C --> E["write to<br/>output/&lt;output&gt;/&lt;name&gt;"] C --> M["embed into<br/>the assembly"] C --> H["link from<br/>index.html"]

Bundle groups vs. copy-through groups

The group's name decides which of two shapes it takes:

  • Bundle groupname ends in .js or .css. Every file the group lists is concatenated, in order, into a single output file called name.
  • Copy-through group — any other name (including no name at all). Each listed file is copied under its own file name. Use this for fonts, images, and other assets that must stay as separate files.
{
  "resources": [
    // Bundle: three stylesheets concatenated into one assets/css/app.css.
    { "name": "app.css",
      "files": [ "assets/css/base.css", "assets/css/layout.css", "assets/css/theme.css" ],
      "output": "assets/css" },

    // Copy-through: each font file copied under its own name into assets/fonts/.
    { "name": "fonts", "files": [ "assets/fonts/*" ], "output": "assets/fonts" }
  ]
}

Resource keys

Each object in the resources array accepts these keys, and only these:

Key Type Default Description
name string The output file name of a bundle group (e.g. app.css), or a label for a copy-through group. Also the key a referencing project uses to find the embedded resource. Supports the module#file.js and file.js.dontload forms below.
files string[] The files the group is built from, in order. Paths are relative to the project directory. Supports one glob per entry — see Globs.
output string output root Sub-folder of the Transpose output folder the file is written to. Omit to write into the output root.
load bool true Whether the resource is referenced from the generated index.html. false still writes and embeds the file, but leaves loading it to the application.
Two spellings of "don't load"

"load": false on the group and the legacy .dontload suffix on its name ("name": "lazy-module.js.dontload") mean the same thing, and either one alone suppresses the link. The suffix is dropped from the output file name. The flag is recorded in the resource manifest embedded in a package DLL, so a project referencing the library extracts the file without auto-loading it either.

A name may also carry a module# grouping prefix ("name": "acme#acme.css"); everything before the # is a label, and the output file name is the part after it.

Keys that Transpose does not read

If you are porting an h5.json resources section, these keys are no longer recognised and are ignored:

extract, inject, header (and its {version} / {author} / {copyright} / {date} / {year} tokens), silent, removeBom, assembly, remark.

There is also no default-settings entry: in h5, an entry without a name supplied defaults for every other entry. In Transpose a name-less entry is just a copy-through group. Repeat the output and load values on each group instead.

Globs

A group can pull in a whole folder with a glob. The wildcard goes in the file name part of the pattern; the directory part must be a literal path.

{ "name": "fonts", "files": [ "assets/fonts/*" ], "output": "assets/fonts" }

Constraints:

  • Matching is not recursive — only files directly in the named directory are picked up. Add one group per sub-folder if you need more.
  • The wildcard must be in the file name; assets/*/icons/*.svg does not work.
  • A directory that does not exist contributes nothing, silently.
  • MSBuild tokens are not expanded in files paths. $(OutDir) is substituted only in the top-level output setting.

The project's own compiled JavaScript

Transpose always embeds the project's own bundle and its reflection metadata, in both a formatted and a pre-minified variant. Adding a resources section does not turn that off.

This differs from h5

In h5, adding any resources section suppressed the automatic output, so a library had to re-declare its own .js, .min.js, .meta.js and .meta.min.js by hand. Transpose embeds them for you, and only suppresses the default embed of the specific bundle a group re-declares. A library no longer needs the four boilerplate entries, and no longer needs to list its scripts twice to satisfy both build configurations — the pre-minified variant is always shipped, so a consuming project extracts the .min.js in Release and the plain .js in Debug without minifying library code itself.

The one reason to re-declare your own bundle is to change its load flag — for example to ship a module the application fetches on demand:

{
  "resources": [
    { "name": "app.js.dontload", "files": [ "app.js" ] }
  ]
}

A file in files whose leaf name matches one of the project's own outputs (app.js, app.min.js, app.meta.js, app.meta.min.js) resolves to the in-memory bundle rather than to a file on disk, so this works even though nothing has been written yet when the group is processed.

Minified vs. non-minified

Resource JavaScript is taken as authored and never re-minified by Transpose. That has one consequence worth knowing: a resource named *.min.js is linked only from index.min.html, and a plain *.js resource only from index.html. So a third-party script you want available in both configurations needs an entry under each name.

CSS resources are linked from both pages, so a stylesheet needs only one entry.

Which page becomes the final index.html depends on the build configuration — see Build Configurations.

Example: a component library

The following tps.json is for an imaginary component library, Acme UI, that compiles to acme.js and ships a handful of third-party scripts, its own stylesheets, and a fonts folder.

tps.json
{
  "fileName": "acme.js",
  "output": "$(OutDir)tps/",

  // Build both readable and minified output so a referencing project can pick
  // one based on its own Debug/Release build (see Build Configurations).
  "outputFormatting": "Both",

  // A library has no page of its own.
  "html": { "disabled": true },

  "resources": [
    // 1. Third-party dependencies, concatenated into one file. Declared twice —
    //    once as .js, once as .min.js — because resource JS is linked by name and
    //    is never re-minified, so each build configuration needs its own entry.
    {
      "name": "acme-deps.js",
      "files": [ "assets/js/popper.min.js", "assets/js/tippy.min.js", "assets/js/sortable.min.js" ],
      "output": "assets/js"
    },
    {
      "name": "acme-deps.min.js",
      "files": [ "assets/js/popper.min.js", "assets/js/tippy.min.js", "assets/js/sortable.min.js" ],
      "output": "assets/js"
    },

    // 2. Stylesheets concatenated into one file. CSS is linked from both pages,
    //    so a single entry is enough.
    {
      "name": "acme.css",
      "files": [ "assets/css/acme.common.css", "assets/css/acme.button.css", "assets/css/acme.card.css" ],
      "output": "assets/css"
    },

    // 3. A theme the application swaps in at runtime: copied and embedded, but
    //    never linked from the page.
    {
      "name": "acme-dark.css",
      "files": [ "assets/css/acme.dark.css" ],
      "output": "assets/css",
      "load": false
    },

    // 4. A fonts folder, pulled in with a glob as a copy-through group.
    { "name": "fonts", "files": [ "assets/fonts/*" ], "output": "assets/fonts" }
  ]
}

Points worth noting:

  • The library's own acme.js / acme.min.js / acme.meta.js / acme.meta.min.js are not listed — Transpose embeds all four automatically.
  • The dependency bundle in 1 is the case that does still need two entries, because a .min.js name is only linked from index.min.html.
  • Combining the CSS in 2 isn't required, but it keeps the generated index.html tidy and groups related styles into one request.
  • Entry 3 shows load: false: the file lands in the output of every consuming project, but nothing loads it until the application does.
  • The fonts glob in 4 matches only files directly under assets/fonts/.

See also

© 2026 Curiosity. All rights reserved.