Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f490f63
central sandcastle build function, bundle esm packages
jjspace Sep 19, 2025
814cb73
remove duplicated configs
jjspace Sep 19, 2025
f7c4d62
dont include dev sandcastles in prod
jjspace Sep 19, 2025
aabcb3d
add commit sha to build for CI
jjspace Sep 19, 2025
f3f4075
build TS for sandcastle
jjspace Sep 19, 2025
4de8de1
Merge remote-tracking branch 'origin/main' into sandcastle-build-updates
jjspace Sep 19, 2025
dcc4ec1
fix ci build double //
jjspace Sep 23, 2025
97f606d
move import inside module declaration in package types
jjspace Sep 23, 2025
4aab565
Use proper URLs for import statements
javagl Sep 23, 2025
2fcefac
make sure imports are strings
jjspace Sep 23, 2025
20f3edc
Merge pull request #12911 from CesiumGS/sandcastle-build-updates-windows
jjspace Sep 23, 2025
d350020
Merge remote-tracking branch 'origin/main' into sandcastle-build-updates
jjspace Sep 26, 2025
63c8ccb
clarify build option
jjspace Sep 26, 2025
1bd41e9
further isolate sandcastle build process
jjspace Sep 29, 2025
d83fb76
switch from ts api to tsc cli
jjspace Sep 29, 2025
26a011d
remove extra logs
jjspace Sep 30, 2025
0f7a9c8
switch deployed sandcastle directory
jjspace Sep 30, 2025
c708661
Merge remote-tracking branch 'origin/main' into sandcastle-build-updates
jjspace Oct 3, 2025
b586c14
Merge remote-tracking branch 'origin/main' into sandcastle-build-updates
jjspace Oct 7, 2025
c4e8eea
switch to relative routes for non-prod builds
jjspace Oct 7, 2025
aaf4ae1
move and trim build config
jjspace Oct 7, 2025
b695f5d
adjust prod GH workflow
jjspace Oct 7, 2025
61d330a
correctly build sandcastle for zip file
jjspace Oct 7, 2025
f3ecf5b
build sandcastle on server start when it doesn't exist
jjspace Oct 7, 2025
00dce5a
update release index url to new sandcastle
jjspace Oct 7, 2025
dde0e07
small cleanup, remove excess changes
jjspace Oct 7, 2025
fd85408
adjust config structure
jjspace Oct 7, 2025
bee0278
Merge remote-tracking branch 'origin/main' into sandcastle-build-updates
jjspace Oct 10, 2025
3b6dd1e
update comment
jjspace Oct 14, 2025
da2dd8a
update function names
jjspace Oct 20, 2025
4530967
switch dev-sandcastle to main branch
jjspace Oct 21, 2025
b74d62d
Merge remote-tracking branch 'origin/main' into sandcastle-build-updates
jjspace Oct 23, 2025
ba045e7
convert to options params for clarity
jjspace Oct 23, 2025
b478c3f
rename arguments and functions for clarity
jjspace Oct 24, 2025
8b212bd
rebuild package bundles in dev server
jjspace Oct 27, 2025
22df371
extract gulp tasks to help avoid dynamic imports
jjspace Oct 27, 2025
5cc27ef
small doc link change
jjspace Oct 27, 2025
ba5b5d7
Merge branch 'main' into sandcastle-build-updates
ggetz Oct 30, 2025
9675ce5
don't include engine bundle in npm package
jjspace Oct 31, 2025
c59e106
Merge remote-tracking branch 'origin/main' into sandcastle-build-updates
jjspace Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- name: build apps
run: npm run build-apps
- name: build sandcastle v2
run: npm run build-ci -w packages/sandcastle -- -l warn
run: npm run build-app -w packages/sandcastle -- -l warn
- uses: ./.github/actions/verify-package
- name: deploy to s3
if: ${{ env.AWS_ACCESS_KEY_ID != '' }}
Expand Down
44 changes: 37 additions & 7 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import {
createJsHintOptions,
defaultESBuildOptions,
} from "./scripts/build.js";
import { fileURLToPath } from "url";
import {
buildStatic,
createSandcastleConfig,
} from "./packages/sandcastle/scripts/buildStatic.js";

// Determines the scope of the workspace packages. If the scope is set to cesium, the workspaces should be @cesium/engine.
// This should match the scope of the dependencies of the root level package.json.
Expand Down Expand Up @@ -1229,13 +1234,6 @@ function generateTypeScriptDefinitions(
"raiseEvent(...arguments: Parameters<Listener>): void;",
);

// Wrap the source to actually be inside of a declared cesium module
// and add any workaround and private utility types.
source = `declare module "@${scope}/${workspaceName}" {
${source}
}
`;

if (importModules) {
let imports = "";
Object.keys(importModules).forEach((workspace) => {
Expand All @@ -1249,6 +1247,13 @@ ${source}
source = imports + source;
}

// Wrap the source to actually be inside of a declared cesium module
// and add any workaround and private utility types.
source = `declare module "@${scope}/${workspaceName}" {
${source}
}
`;

// Write the final source file back out
writeFileSync(definitionsPath, source);

Expand Down Expand Up @@ -1741,6 +1746,31 @@ async function buildSandcastle() {
return Promise.all(streams.map((s) => finished(s)));
}

// TODO: clean up
export async function buildNewSandcastle() {
const __dirname = dirname(fileURLToPath(import.meta.url));
const newConfig = createSandcastleConfig({
outDir: join(__dirname, "./Apps/Sandcastle2"),
viteBase: "/Apps/Sandcastle2",
cesiumBaseUrl: "/Build/CesiumUnminified",
imports: {
cesium: {
path: "/Source/Cesium.js",
typesPath: "/Source/Cesium.d.ts",
},
"@cesium/engine": {
path: "/packages/engine/Build/Unminified/index.js",
typesPath: "/packages/engine/index.d.ts",
},
"@cesium/widgets": {
path: "/packages/widgets/Build/Unminified/index.js",
typesPath: "/packages/widgets/index.d.ts",
},
},
});
await buildStatic(newConfig);
}

async function buildCesiumViewer() {
const cesiumViewerOutputDirectory = isProduction
? "Build/CesiumViewer"
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
"build-ts": "gulp buildTs",
"build-third-party": "gulp buildThirdParty",
"build-apps": "gulp buildApps",
"build-sandcastle": "npm run build-app --workspace packages/sandcastle",
"build-sandcastle": "gulp buildNewSandcastle",
"clean": "gulp clean",
"cloc": "gulp cloc",
"coverage": "gulp coverage",
Expand Down Expand Up @@ -171,4 +171,4 @@
}
}
}
}
}
2 changes: 1 addition & 1 deletion packages/sandcastle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This package is the application for Sandcastle.
- `npm run dev`: run the development server
- `npm run build`: alias for `npm run build-app`
- `npm run build-app`: build to static files in `/Apps/Sandcastle2` for hosting/access from the root cesium dev server
- `npm run build-ci`: build to static files in `/Apps/Sandcastle2` and configure paths as needed for CI deployment
- If the env variable `BASE_URL` is set it will be prefixed on all required paths in the application. This is useful for building to a "nested" url like we do in CI

Linting and style is managed under the project root's scripts.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ labels:
- Development
- Entities
thumbnail: thumbnail.jpg
development: true
1 change: 1 addition & 0 deletions packages/sandcastle/gallery/fog/sandcastle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ description: Control fog parameters.
labels:
- Development
thumbnail: thumbnail.jpg
development: true
1 change: 0 additions & 1 deletion packages/sandcastle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"dev": "npm run build-gallery && vite --config vite.config.dev.ts",
"build": "npm run build-app",
"build-app": "tsc -b && npm run build-gallery && vite build --config vite.config.app.ts",
"build-ci": "tsc -b && npm run build-gallery && vite build --config vite.config.ci.ts",
"build-prod": "tsc -b && npm run build-gallery && vite build --config vite.config.prod.ts",
"build-gallery": "node scripts/buildGallery.js"
},
Expand Down
6 changes: 4 additions & 2 deletions packages/sandcastle/sandcastle.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import process from "process";

const config = {
root: ".",
sourceUrl: "https://github.com/CesiumGS/cesium/blob/main/packages/sandcastle",
publicDir: "./public",
publicDirectory: "./public",
gallery: {
files: ["gallery"],
searchOptions: {
Expand All @@ -19,7 +21,7 @@ const config = {
labels: [],
development: false,
},
includeDevelopment: true,
includeDevelopment: !process.env.PROD,
},
};

Expand Down
10 changes: 7 additions & 3 deletions packages/sandcastle/scripts/buildGallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,11 @@ export async function buildGalleryList(options = {}) {
if (
check(!/^[a-zA-Z0-9-.]+$/.test(slug), `"${slug}" is not a valid slug`) ||
check(!title, `${slug} - Missing title`) ||
check(!description, `${slug} - Missing description`)
check(!description, `${slug} - Missing description`) ||
check(
!development && labels.includes("Development"),
`${slug} has Development label but not marked as development sandcastle`,
)
) {
continue;
}
Expand Down Expand Up @@ -300,7 +304,7 @@ if (import.meta.url.endsWith(`${pathToFileURL(process.argv[1])}`)) {

try {
const config = await import(pathToFileURL(configPath).href);
const { root, publicDir, gallery, sourceUrl } = config.default;
const { root, publicDirectory, gallery, sourceUrl } = config.default;

// Paths are specified relative to the config file
const configDir = dirname(configPath);
Expand All @@ -316,7 +320,7 @@ if (import.meta.url.endsWith(`${pathToFileURL(process.argv[1])}`)) {

buildGalleryOptions = {
rootDirectory: configRoot,
publicDirectory: publicDir,
publicDirectory: publicDirectory,
galleryFiles: files,
sourceUrl,
defaultThumbnail,
Expand Down
141 changes: 141 additions & 0 deletions packages/sandcastle/scripts/buildStatic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { build, defineConfig } from "vite";
import baseConfig from "../vite.config.js";
import { fileURLToPath } from "url";
import { viteStaticCopy } from "vite-plugin-static-copy";
import { dirname, join } from "path";
import { cesiumPathReplace, insertImportMap } from "../vite-plugins.js";
import typescriptCompile from "./typescriptCompile.js";

/** @import { UserConfig } from 'vite' */

/**
* @typedef {Object} ImportObject
* @property {string} path The path to use for the import map. ie the path the app can expect to find this at
* @property {string} typesPath The path to use for intellisense types in monaco
*/

/**
* @typedef {Object<string, ImportObject>} ImportList
*/

/**
* Check if the given key is in the imports list and throw an error if not
* @param {ImportList} imports
* @param {string} name
*/
function checkForImport(imports, name) {
if (!imports[name]) {
throw new Error(`Missing import for ${name}`);
}
}

const __dirname = dirname(fileURLToPath(import.meta.url));

/**
* Create the Vite configuration for building Sandcastle.
* Set where it should build to and the base path for vite and CesiumJS files.
*
* Most importantly specify the paths the app can find the library imports.
*
* If you are copying files to the built directory ensure the source files exist BEFORE attempting to build Sandcastle
*
* @param {object} options
* @param {string} options.outDir Path to build files into
* @param {string} options.viteBase Base path for files/routes
* @param {string} options.cesiumBaseUrl Base path for CesiumJS. This should include the CesiumJS assets and workers etc.
* @param {string} [options.commitSha] Optional commit hash to display in the top right of the application
* @param {ImportList} options.imports Set of imports to add to the import map for the iframe and standalone html pages. These paths should match the URL where it can be accessed within the current environment.
* @param {{src: string, dest: string}[]} [options.copyExtraFiles] Extra paths passed to viteStaticCopy. Use this to consolidate files for a singular static deployment (ie during production). Source paths should be absolute, dest paths should be relative to the page root. It is up to you to ensure these files exist BEFORE building sandcastle.
*/
export function createSandcastleConfig({
outDir,
viteBase,
cesiumBaseUrl,
commitSha,
imports,
copyExtraFiles = [],
}) {
/** @type {UserConfig} */
const config = { ...baseConfig };

config.base = viteBase;

config.build = {
...config.build,
outDir: outDir,
};

const copyPlugin = viteStaticCopy({
targets: [
{ src: "templates/Sandcastle.(d.ts|js)", dest: "templates" },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the TS build output to the public directory instead to save a step?

...copyExtraFiles,
],
});

checkForImport(imports, "cesium");
checkForImport(imports, "@cesium/engine");
checkForImport(imports, "@cesium/widgets");
if (imports["Sandcastle"]) {
throw new Error(
"Don't specify the Sandcastle import this is taken care of internally",
);
}

/** @type {Object<string, string>} */
const importMap = {
Sandcastle: `${viteBase}/templates/Sandcastle.js`,
};
/** @type {Object<string, string>} */
const typePaths = {
Sandcastle: "templates/Sandcastle.d.ts",
};
for (const [key, value] of Object.entries(imports)) {
importMap[key] = value.path;
typePaths[key] = value.typesPath;
}

config.define = {
...config.define,
__VITE_TYPE_IMPORT_PATHS__: JSON.stringify(typePaths),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like we'er bending over backwards to get the type definition locations. I'm thinking this would be a lot easier if we build out the definitions relative to the bundled files—Then, we wouldn't need to configure the path to Source/Cesium.d.ts and instead could get the path at runtime based on the resolved module URLs from the import maps:

const cesiumModulePath = import.meta.resolve("cesium");
const tsdPath = new URL("./Cesium.d.ts", cesiumModulePath).href;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of this change but it would involve some larger changes with the rest of our build systems. Happy to take a look at it at some point but I think I'd prefer to leave this as is for this current PR. Maybe it's rather verbose in the config but at least it should be clear what it's doing.

__COMMIT_SHA__: JSON.stringify(commitSha ?? undefined),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason not to use process.env.GITHUB_SHA directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may not always want to use it. For example in Prod we don't want to show it but it's currently set in the github workflow. Doing it this way makes it customizable and explicit from wherever we call this function. Using the env variable directly creates more, almost, "side effect" logic that people have to be aware of

};

const plugins = config.plugins ?? [];
config.plugins = [
...plugins,
copyPlugin,
cesiumPathReplace(cesiumBaseUrl),
insertImportMap(importMap, ["bucket.html", "standalone.html"]),
];

return defineConfig(config);
}

/**
* Build Sandcastle out to a specified location as static files.
* The config should be generated with the <code>createSandcastleConfig</code> function.
*
* The build will only set up the paths for "external" resources from the app.
* If you are copying files to the built directory ensure the source files exist BEFORE attempting to build Sandcastle
*
* @param {UserConfig} config
*/
export async function buildStatic(config) {
// We have to do the compile for the Sandcastle API outside of the vite build
// because we need to reference the js file and types directly from the app
// and we don't want them bundled with the rest of the code
const exitCode = typescriptCompile(
join(__dirname, "../templates/tsconfig.lib.json"),
);

if (exitCode === 0) {
console.log(`Sandcastle typescript build complete`);
} else {
throw new Error("Sandcastle typescript build failed");
}

await build({
...config,
root: join(__dirname, "../"),
});
}
Loading
Loading