mirror of https://github.com/CesiumGS/cesium.git
1306 lines
40 KiB
JavaScript
1306 lines
40 KiB
JavaScript
import child_process from "node:child_process";
|
|
import { existsSync, statSync } from "node:fs";
|
|
import { readFile, writeFile } from "node:fs/promises";
|
|
import { EOL } from "node:os";
|
|
import path from "node:path";
|
|
import { finished } from "node:stream/promises";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import esbuild from "esbuild";
|
|
import { globby } from "globby";
|
|
import glslStripComments from "glsl-strip-comments";
|
|
import gulp from "gulp";
|
|
import { rimraf } from "rimraf";
|
|
|
|
import { mkdirp } from "mkdirp";
|
|
|
|
// 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.
|
|
const scope = "cesium";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const projectRoot = path.join(__dirname, "..");
|
|
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
|
|
export async function getVersion() {
|
|
const data = await readFile(packageJsonPath, "utf8");
|
|
const { version } = JSON.parse(data);
|
|
return version;
|
|
}
|
|
|
|
async function getCopyrightHeader() {
|
|
const copyrightHeaderTemplate = await readFile(
|
|
path.join("Source", "copyrightHeader.js"),
|
|
"utf8",
|
|
);
|
|
return copyrightHeaderTemplate.replace("${version}", await getVersion());
|
|
}
|
|
|
|
function escapeCharacters(token) {
|
|
return token.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
|
}
|
|
|
|
function constructRegex(pragma, exclusive) {
|
|
const prefix = exclusive ? "exclude" : "include";
|
|
pragma = escapeCharacters(pragma);
|
|
|
|
const s =
|
|
`[\\t ]*\\/\\/>>\\s?${prefix}Start\\s?\\(\\s?(["'])${pragma}\\1\\s?,\\s?pragmas\\.${pragma}\\s?\\)\\s?;?` +
|
|
// multiline code block
|
|
`[\\s\\S]*?` +
|
|
// end comment
|
|
`[\\t ]*\\/\\/>>\\s?${prefix}End\\s?\\(\\s?(["'])${pragma}\\2\\s?\\)\\s?;?\\s?[\\t ]*\\n?`;
|
|
|
|
return new RegExp(s, "gm");
|
|
}
|
|
|
|
const pragmas = {
|
|
debug: false,
|
|
};
|
|
const stripPragmaPlugin = {
|
|
name: "strip-pragmas",
|
|
setup: (build) => {
|
|
build.onLoad({ filter: /\.js$/ }, async (args) => {
|
|
let source = await readFile(args.path, { encoding: "utf8" });
|
|
|
|
try {
|
|
for (const key in pragmas) {
|
|
if (pragmas.hasOwnProperty(key)) {
|
|
source = source.replace(constructRegex(key, pragmas[key]), "");
|
|
}
|
|
}
|
|
|
|
return { contents: source };
|
|
} catch (e) {
|
|
return {
|
|
errors: {
|
|
text: e.message,
|
|
},
|
|
};
|
|
}
|
|
});
|
|
},
|
|
};
|
|
|
|
// Print an esbuild warning
|
|
function printBuildWarning({ location, text }) {
|
|
const { column, file, line, lineText, suggestion } = location;
|
|
|
|
let message = `\n
|
|
> ${file}:${line}:${column}: warning: ${text}
|
|
${lineText}
|
|
`;
|
|
|
|
if (suggestion && suggestion !== "") {
|
|
message += `\n${suggestion}`;
|
|
}
|
|
|
|
console.log(message);
|
|
}
|
|
|
|
// Ignore `eval` warnings in third-party code we don't have control over
|
|
function handleBuildWarnings(result) {
|
|
for (const warning of result.warnings) {
|
|
if (!warning.location.file.includes("protobufjs.js")) {
|
|
printBuildWarning(warning);
|
|
}
|
|
}
|
|
}
|
|
|
|
export const defaultESBuildOptions = () => {
|
|
return {
|
|
bundle: true,
|
|
color: true,
|
|
legalComments: `inline`,
|
|
logLimit: 0,
|
|
target: `es2020`,
|
|
};
|
|
};
|
|
|
|
export async function getFilesFromWorkspaceGlobs(workspaceGlobs) {
|
|
let files = [];
|
|
// Iterate over each workspace and generate declarations for each file.
|
|
for (const workspace of Object.keys(workspaceGlobs)) {
|
|
// Since workspace source files are provided relative to the workspace,
|
|
// the workspace path needs to be prepended.
|
|
const workspacePath = `packages/${workspace.replace(`${scope}/`, ``)}`;
|
|
const filesPaths = workspaceGlobs[workspace].map((glob) => {
|
|
if (glob.indexOf(`!`) === 0) {
|
|
return `!`.concat(workspacePath, `/`, glob.replace(`!`, ``));
|
|
}
|
|
return workspacePath.concat("/", glob);
|
|
});
|
|
|
|
files = files.concat(await globby(filesPaths));
|
|
}
|
|
return files;
|
|
}
|
|
|
|
const inlineWorkerPath = "Build/InlineWorkers.js";
|
|
|
|
/**
|
|
* @typedef {object} CesiumBundles
|
|
* @property {object} esm The ESM bundle.
|
|
* @property {object} iife The IIFE bundle, for use in browsers.
|
|
* @property {object} node The CommonJS bundle, for use in NodeJS.
|
|
*/
|
|
|
|
/**
|
|
* Bundles all individual modules, optionally minifying and stripping out debug pragmas.
|
|
* @param {object} options
|
|
* @param {string} options.path Directory where build artifacts are output
|
|
* @param {boolean} [options.minify=false] true if the output should be minified
|
|
* @param {boolean} [options.removePragmas=false] true if the output should have debug pragmas stripped out
|
|
* @param {boolean} [options.sourcemap=false] true if an external sourcemap should be generated
|
|
* @param {boolean} [options.iife=false] true if an IIFE style module should be built
|
|
* @param {boolean} [options.node=false] true if a CJS style node module should be built
|
|
* @param {boolean} [options.incremental=false] true if build output should be cached for repeated builds
|
|
* @param {boolean} [options.write=true] true if build output should be written to disk. If false, the files that would have been written as in-memory buffers
|
|
* @returns {Promise<CesiumBundles>}
|
|
*/
|
|
export async function bundleCesiumJs(options) {
|
|
const buildConfig = defaultESBuildOptions();
|
|
buildConfig.entryPoints = ["Source/Cesium.js"];
|
|
buildConfig.minify = options.minify;
|
|
buildConfig.sourcemap = options.sourcemap;
|
|
buildConfig.plugins = options.removePragmas ? [stripPragmaPlugin] : undefined;
|
|
buildConfig.write = options.write;
|
|
buildConfig.banner = {
|
|
js: await getCopyrightHeader(),
|
|
};
|
|
// print errors immediately, and collect warnings so we can filter out known ones
|
|
buildConfig.logLevel = "info";
|
|
|
|
const contexts = {};
|
|
const incremental = options.incremental;
|
|
let build = esbuild.build;
|
|
if (incremental) {
|
|
build = esbuild.context;
|
|
}
|
|
|
|
// Build ESM
|
|
const esm = await build({
|
|
...buildConfig,
|
|
format: "esm",
|
|
outfile: path.join(options.path, "index.js"),
|
|
});
|
|
|
|
if (incremental) {
|
|
contexts.esm = esm;
|
|
} else {
|
|
handleBuildWarnings(esm);
|
|
}
|
|
|
|
// Build IIFE
|
|
if (options.iife) {
|
|
const iifeWorkers = await bundleWorkers({
|
|
iife: true,
|
|
minify: options.minify,
|
|
sourcemap: false,
|
|
path: options.path,
|
|
removePragmas: options.removePragmas,
|
|
incremental: incremental,
|
|
write: options.write,
|
|
});
|
|
|
|
const iife = await build({
|
|
...buildConfig,
|
|
format: "iife",
|
|
inject: [inlineWorkerPath],
|
|
globalName: "Cesium",
|
|
outfile: path.join(options.path, "Cesium.js"),
|
|
logOverride: {
|
|
"empty-import-meta": "silent",
|
|
},
|
|
});
|
|
|
|
if (incremental) {
|
|
contexts.iife = iife;
|
|
contexts.iifeWorkers = iifeWorkers;
|
|
} else {
|
|
handleBuildWarnings(iife);
|
|
rimraf.sync(inlineWorkerPath);
|
|
}
|
|
}
|
|
|
|
if (options.node) {
|
|
const node = await build({
|
|
...buildConfig,
|
|
format: "cjs",
|
|
platform: "node",
|
|
logOverride: {
|
|
"empty-import-meta": "silent",
|
|
},
|
|
define: {
|
|
// TransformStream is a browser-only implementation depended on by zip.js
|
|
TransformStream: "null",
|
|
},
|
|
outfile: path.join(options.path, "index.cjs"),
|
|
});
|
|
|
|
if (incremental) {
|
|
contexts.node = node;
|
|
} else {
|
|
handleBuildWarnings(node);
|
|
}
|
|
}
|
|
|
|
return contexts;
|
|
}
|
|
|
|
function filePathToModuleId(moduleId) {
|
|
return moduleId.substring(0, moduleId.lastIndexOf(".")).replace(/\\/g, "/");
|
|
}
|
|
|
|
const workspaceSourceFiles = {
|
|
engine: [
|
|
"packages/engine/Source/**/*.js",
|
|
"!packages/engine/Source/*.js",
|
|
"!packages/engine/Source/Workers/**",
|
|
"packages/engine/Source/Workers/createTaskProcessorWorker.js",
|
|
"!packages/engine/Source/ThirdParty/Workers/**.js",
|
|
"!packages/engine/Source/ThirdParty/google-earth-dbroot-parser.js",
|
|
"!packages/engine/Source/ThirdParty/_*",
|
|
],
|
|
widgets: ["packages/widgets/Source/**/*.js"],
|
|
};
|
|
|
|
/**
|
|
* Generates export declaration from a file from a workspace.
|
|
*
|
|
* @param {string} workspace The workspace the file belongs to.
|
|
* @param {string} file The file.
|
|
* @returns {string} The export declaration.
|
|
*/
|
|
function generateDeclaration(workspace, file) {
|
|
let assignmentName = path.basename(file, path.extname(file));
|
|
|
|
let moduleId = file;
|
|
moduleId = filePathToModuleId(moduleId);
|
|
|
|
if (moduleId.indexOf("Source/Shaders") > -1) {
|
|
assignmentName = `_shaders${assignmentName}`;
|
|
}
|
|
assignmentName = assignmentName.replace(/(\.|-)/g, "_");
|
|
return `export { ${assignmentName} } from '@${scope}/${workspace}';`;
|
|
}
|
|
|
|
/**
|
|
* Creates a single entry point file, Cesium.js, which imports all individual modules exported from the Cesium API.
|
|
* @returns {Buffer} contents
|
|
*/
|
|
export async function createCesiumJs() {
|
|
const version = await getVersion();
|
|
let contents = `export const VERSION = '${version}';\n`;
|
|
|
|
// Iterate over each workspace and generate declarations for each file.
|
|
for (const workspace of Object.keys(workspaceSourceFiles)) {
|
|
const files = await globby(workspaceSourceFiles[workspace]);
|
|
const declarations = files.map((file) =>
|
|
generateDeclaration(workspace, file),
|
|
);
|
|
contents += declarations.join(`${EOL}`);
|
|
contents += "\n";
|
|
}
|
|
await writeFile("Source/Cesium.js", contents, { encoding: "utf-8" });
|
|
|
|
return contents;
|
|
}
|
|
|
|
/**
|
|
* Bundles all individual modules, optionally minifying and stripping out debug pragmas.
|
|
* @param {object} options
|
|
* @param {string} options.outputDirectory Directory where build artifacts are output
|
|
* @param {string} options.entryPoint script to bundle
|
|
* @param {boolean} [options.minify=false] true if the output should be minified
|
|
* @param {boolean} [options.removePragmas=false] true if the output should have debug pragmas stripped out
|
|
* @param {boolean} [options.sourcemap=false] true if an external sourcemap should be generated
|
|
* @param {boolean} [options.incremental=false] true if build output should be cached for repeated builds
|
|
* @param {boolean} [options.write=true] true if build output should be written to disk. If false, the files that would have been written as in-memory buffers
|
|
*/
|
|
export async function bundleIndexJs(options) {
|
|
const buildConfig = {
|
|
...defaultESBuildOptions(),
|
|
entryPoints: [options.entryPoint],
|
|
minify: options.minify,
|
|
sourcemap: options.sourcemap,
|
|
plugins: options.removePragmas ? [stripPragmaPlugin] : undefined,
|
|
write: options.write,
|
|
banner: {
|
|
js: await getCopyrightHeader(),
|
|
},
|
|
// print errors immediately, and collect warnings so we can filter out known ones
|
|
logLevel: "info",
|
|
};
|
|
|
|
const contexts = {};
|
|
const incremental = options.incremental ?? false;
|
|
const build = incremental ? esbuild.context : esbuild.build;
|
|
|
|
// Build ESM
|
|
const esm = await build({
|
|
...buildConfig,
|
|
format: "esm",
|
|
outfile: path.join(options.outputDirectory, "index.js"),
|
|
// NOTE: doing this requires an importmap defined in the browser but avoids multiple CesiumJS instances
|
|
external: options.entryPoint.includes("engine") ? [] : ["@cesium/engine"],
|
|
});
|
|
|
|
if (incremental) {
|
|
contexts.esm = esm;
|
|
} else {
|
|
handleBuildWarnings(esm);
|
|
}
|
|
|
|
return contexts;
|
|
}
|
|
|
|
const workspaceSpecFiles = {
|
|
engine: ["packages/engine/Specs/**/*Spec.js"],
|
|
widgets: ["packages/widgets/Specs/**/*Spec.js"],
|
|
};
|
|
|
|
/**
|
|
* Creates a single entry point file, Specs/SpecList.js, which imports all individual spec files.
|
|
* @returns {Buffer} contents
|
|
*/
|
|
export async function createCombinedSpecList() {
|
|
const version = await getVersion();
|
|
let contents = `export const VERSION = '${version}';\n`;
|
|
|
|
for (const workspace of Object.keys(workspaceSpecFiles)) {
|
|
const files = await globby(workspaceSpecFiles[workspace]);
|
|
for (const file of files) {
|
|
contents += `import '../${file}';\n`;
|
|
}
|
|
}
|
|
|
|
await writeFile(path.join("Specs", "SpecList.js"), contents, {
|
|
encoding: "utf-8",
|
|
});
|
|
|
|
return contents;
|
|
}
|
|
|
|
/**
|
|
* @param {object} options
|
|
* @param {string} options.path output directory
|
|
* @param {boolean} [options.iife=false] true if the worker output should be inlined into a top-level iife file, ie. in Cesium.js
|
|
* @param {boolean} [options.minify=false] true if the worker output should be minified
|
|
* @param {boolean} [options.removePragmas=false] true if debug pragma should be removed
|
|
* @param {boolean} [options.sourcemap=false] true if an external sourcemap should be generated
|
|
* @param {boolean} [options.incremental=false] true if build output should be cached for repeated builds
|
|
* @param {boolean} [options.write=true] true if build output should be written to disk. If false, the files that would have been written as in-memory buffers
|
|
*/
|
|
export async function bundleWorkers(options) {
|
|
// Copy ThirdParty workers
|
|
const thirdPartyWorkers = await globby([
|
|
"packages/engine/Source/ThirdParty/Workers/**.js",
|
|
"!packages/engine/Source/ThirdParty/Workers/basis_transcoder.js",
|
|
]);
|
|
|
|
const thirdPartyWorkerConfig = defaultESBuildOptions();
|
|
thirdPartyWorkerConfig.bundle = false;
|
|
thirdPartyWorkerConfig.entryPoints = thirdPartyWorkers;
|
|
thirdPartyWorkerConfig.outdir = options.path;
|
|
thirdPartyWorkerConfig.minify = options.minify;
|
|
thirdPartyWorkerConfig.outbase = "packages/engine/Source";
|
|
await esbuild.build(thirdPartyWorkerConfig);
|
|
|
|
// Bundle Cesium workers
|
|
const workers = await globby(["packages/engine/Source/Workers/**"]);
|
|
const workerConfig = defaultESBuildOptions();
|
|
workerConfig.bundle = true;
|
|
workerConfig.external = ["fs", "path"];
|
|
|
|
if (options.iife) {
|
|
let contents = ``;
|
|
const files = await globby(workers);
|
|
const declarations = files.map((file) => {
|
|
let assignmentName = path.basename(file, path.extname(file));
|
|
assignmentName = assignmentName.replace(/(\.|-)/g, "_");
|
|
return `export const ${assignmentName} = () => { import('./${file}'); };`;
|
|
});
|
|
contents += declarations.join(`${EOL}`);
|
|
contents += "\n";
|
|
|
|
workerConfig.globalName = "CesiumWorkers";
|
|
workerConfig.format = "iife";
|
|
workerConfig.stdin = {
|
|
contents: contents,
|
|
resolveDir: ".",
|
|
};
|
|
workerConfig.minify = options.minify;
|
|
workerConfig.write = false;
|
|
workerConfig.logOverride = {
|
|
"empty-import-meta": "silent",
|
|
};
|
|
workerConfig.plugins = options.removePragmas
|
|
? [stripPragmaPlugin]
|
|
: undefined;
|
|
} else {
|
|
workerConfig.format = "esm";
|
|
workerConfig.splitting = true;
|
|
workerConfig.banner = {
|
|
js: await getCopyrightHeader(),
|
|
};
|
|
workerConfig.entryPoints = workers;
|
|
workerConfig.outdir = path.join(options.path, "Workers");
|
|
workerConfig.minify = options.minify;
|
|
workerConfig.write = options.write;
|
|
}
|
|
|
|
const incremental = options.incremental;
|
|
let build = esbuild.build;
|
|
if (incremental) {
|
|
build = esbuild.context;
|
|
}
|
|
|
|
if (!options.iife) {
|
|
return build(workerConfig);
|
|
}
|
|
|
|
//if iife, write this output to it's own file in which the script content is exported
|
|
const writeInjectionCode = (result) => {
|
|
const bundle = result.outputFiles[0].contents;
|
|
const base64 = Buffer.from(bundle).toString("base64");
|
|
const contents = `globalThis.CESIUM_WORKERS = atob("${base64}");`;
|
|
return writeFile(inlineWorkerPath, contents);
|
|
};
|
|
|
|
if (incremental) {
|
|
const context = await build(workerConfig);
|
|
const rebuild = context.rebuild;
|
|
context.rebuild = async () => {
|
|
const result = await rebuild();
|
|
if (result) {
|
|
await writeInjectionCode(result);
|
|
}
|
|
return result;
|
|
};
|
|
return context;
|
|
}
|
|
|
|
const result = await build(workerConfig);
|
|
return writeInjectionCode(result);
|
|
}
|
|
|
|
const shaderFiles = [
|
|
"packages/engine/Source/Shaders/**/*.glsl",
|
|
"packages/engine/Source/ThirdParty/Shaders/*.glsl",
|
|
];
|
|
export async function glslToJavaScript(minify, minifyStateFilePath, workspace) {
|
|
await writeFile(minifyStateFilePath, minify.toString());
|
|
const minifyStateFileLastModified = existsSync(minifyStateFilePath)
|
|
? statSync(minifyStateFilePath).mtime.getTime()
|
|
: 0;
|
|
|
|
// collect all currently existing JS files into a set, later we will remove the ones
|
|
// we still are using from the set, then delete any files remaining in the set.
|
|
const leftOverJsFiles = {};
|
|
|
|
const files = await globby([
|
|
`packages/${workspace}/Source/Shaders/**/*.js`,
|
|
`packages/${workspace}/Source/ThirdParty/Shaders/*.js`,
|
|
]);
|
|
files.forEach(function (file) {
|
|
leftOverJsFiles[path.normalize(file)] = true;
|
|
});
|
|
|
|
const builtinFunctions = [];
|
|
const builtinConstants = [];
|
|
const builtinStructs = [];
|
|
|
|
const glslFiles = await globby(shaderFiles);
|
|
await Promise.all(
|
|
glslFiles.map(async function (glslFile) {
|
|
glslFile = path.normalize(glslFile);
|
|
const baseName = path.basename(glslFile, ".glsl");
|
|
const jsFile = `${path.join(path.dirname(glslFile), baseName)}.js`;
|
|
|
|
// identify built in functions, structs, and constants
|
|
const baseDir = path.join(
|
|
`packages/${workspace}/`,
|
|
"Source",
|
|
"Shaders",
|
|
"Builtin",
|
|
);
|
|
if (
|
|
glslFile.indexOf(path.normalize(path.join(baseDir, "Functions"))) === 0
|
|
) {
|
|
builtinFunctions.push(baseName);
|
|
} else if (
|
|
glslFile.indexOf(path.normalize(path.join(baseDir, "Constants"))) === 0
|
|
) {
|
|
builtinConstants.push(baseName);
|
|
} else if (
|
|
glslFile.indexOf(path.normalize(path.join(baseDir, "Structs"))) === 0
|
|
) {
|
|
builtinStructs.push(baseName);
|
|
}
|
|
|
|
delete leftOverJsFiles[jsFile];
|
|
|
|
const jsFileExists = existsSync(jsFile);
|
|
const jsFileModified = jsFileExists
|
|
? statSync(jsFile).mtime.getTime()
|
|
: 0;
|
|
const glslFileModified = statSync(glslFile).mtime.getTime();
|
|
|
|
if (
|
|
jsFileExists &&
|
|
jsFileModified > glslFileModified &&
|
|
jsFileModified > minifyStateFileLastModified
|
|
) {
|
|
return;
|
|
}
|
|
|
|
let contents = await readFile(glslFile, { encoding: "utf8" });
|
|
contents = contents.replace(/\r\n/gm, "\n");
|
|
|
|
let copyrightComments = "";
|
|
const extractedCopyrightComments = contents.match(
|
|
/\/\*\*(?:[^*\/]|\*(?!\/)|\n)*?@license(?:.|\n)*?\*\//gm,
|
|
);
|
|
if (extractedCopyrightComments) {
|
|
copyrightComments = `${extractedCopyrightComments.join("\n")}\n`;
|
|
}
|
|
|
|
if (minify) {
|
|
contents = glslStripComments(contents);
|
|
contents = contents
|
|
.replace(/\s+$/gm, "")
|
|
.replace(/^\s+/gm, "")
|
|
.replace(/\n+/gm, "\n");
|
|
contents += "\n";
|
|
}
|
|
|
|
contents = contents.split('"').join('\\"').replace(/\n/gm, "\\n\\\n");
|
|
contents = `${copyrightComments}\
|
|
//This file is automatically rebuilt by the Cesium build process.\n\
|
|
export default "${contents}";\n`;
|
|
|
|
return writeFile(jsFile, contents);
|
|
}),
|
|
);
|
|
|
|
// delete any left over JS files from old shaders
|
|
Object.keys(leftOverJsFiles).forEach(function (filepath) {
|
|
rimraf.sync(filepath);
|
|
});
|
|
|
|
const generateBuiltinContents = function (contents, builtins, path) {
|
|
for (let i = 0; i < builtins.length; i++) {
|
|
const builtin = builtins[i];
|
|
contents.imports.push(
|
|
`import czm_${builtin} from './${path}/${builtin}.js'`,
|
|
);
|
|
contents.builtinLookup.push(`czm_${builtin} : ` + `czm_${builtin}`);
|
|
}
|
|
};
|
|
|
|
//generate the JS file for Built-in GLSL Functions, Structs, and Constants
|
|
const contents = {
|
|
imports: [],
|
|
builtinLookup: [],
|
|
};
|
|
generateBuiltinContents(contents, builtinConstants, "Constants");
|
|
generateBuiltinContents(contents, builtinStructs, "Structs");
|
|
generateBuiltinContents(contents, builtinFunctions, "Functions");
|
|
|
|
const fileContents = `//This file is automatically rebuilt by the Cesium build process.\n${contents.imports.join(
|
|
"\n",
|
|
)}\n\nexport default {\n ${contents.builtinLookup.join(",\n ")}\n};\n`;
|
|
|
|
return writeFile(
|
|
path.join(
|
|
`packages/${workspace}/`,
|
|
"Source",
|
|
"Shaders",
|
|
"Builtin",
|
|
"CzmBuiltins.js",
|
|
),
|
|
fileContents,
|
|
);
|
|
}
|
|
|
|
const externalResolvePlugin = {
|
|
name: "external-cesium",
|
|
setup: (build) => {
|
|
// In Specs, when we import files from the source files, we import
|
|
// them from the index.js files. This plugin replaces those imports
|
|
// with the IIFE Cesium.js bundle that's loaded in the browser
|
|
// in SpecRunner.html.
|
|
build.onResolve({ filter: new RegExp(`index\.js$`) }, () => {
|
|
return {
|
|
path: "Cesium",
|
|
namespace: "external-cesium",
|
|
};
|
|
});
|
|
|
|
build.onResolve({ filter: /@cesium/ }, () => {
|
|
return {
|
|
path: "Cesium",
|
|
namespace: "external-cesium",
|
|
};
|
|
});
|
|
|
|
build.onLoad(
|
|
{
|
|
filter: new RegExp(`^Cesium$`),
|
|
namespace: "external-cesium",
|
|
},
|
|
() => {
|
|
const contents = `module.exports = Cesium`;
|
|
return {
|
|
contents,
|
|
};
|
|
},
|
|
);
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Creates a template html file in the Sandcastle app listing the gallery of demos
|
|
* @param {boolean} [noDevelopmentGallery=false] true if the development gallery should not be included in the list
|
|
* @returns {Promise<any>}
|
|
*/
|
|
export async function createGalleryList(noDevelopmentGallery) {
|
|
const demoObjects = [];
|
|
const demoJSONs = [];
|
|
const output = path.join("Apps", "Sandcastle", "gallery", "gallery-index.js");
|
|
|
|
const fileList = ["Apps/Sandcastle/gallery/**/*.html"];
|
|
if (noDevelopmentGallery) {
|
|
fileList.push("!Apps/Sandcastle/gallery/development/**/*.html");
|
|
}
|
|
|
|
// In CI, the version is set to something like '1.43.0-branch-name-buildNumber'
|
|
// We need to extract just the Major.Minor version
|
|
const version = await getVersion();
|
|
const majorMinor = version.match(/^(.*)\.(.*)\./);
|
|
const major = majorMinor[1];
|
|
const minor = Number(majorMinor[2]) - 1; // We want the last release, not current release
|
|
const tagVersion = `${major}.${minor}`;
|
|
|
|
// Get an array of demos that were added since the last release.
|
|
// This includes newly staged local demos as well.
|
|
let newDemos = [];
|
|
try {
|
|
newDemos = child_process
|
|
.execSync(
|
|
`git diff --name-only --diff-filter=A ${tagVersion} Apps/Sandcastle/gallery/*.html`,
|
|
{ stdio: ["pipe", "pipe", "ignore"] },
|
|
)
|
|
.toString()
|
|
.trim()
|
|
.split("\n");
|
|
} catch {
|
|
// On a Cesium fork, tags don't exist so we can't generate the list.
|
|
}
|
|
|
|
let helloWorld;
|
|
const files = await globby(fileList);
|
|
files.forEach(function (file) {
|
|
const demo = filePathToModuleId(
|
|
path.relative("Apps/Sandcastle/gallery", file),
|
|
);
|
|
|
|
const demoObject = {
|
|
name: demo,
|
|
isNew: newDemos.includes(file),
|
|
};
|
|
|
|
if (existsSync(`${file.replace(".html", "")}.jpg`)) {
|
|
demoObject.img = `${demo}.jpg`;
|
|
}
|
|
|
|
demoObjects.push(demoObject);
|
|
|
|
if (demo === "Hello World") {
|
|
helloWorld = demoObject;
|
|
}
|
|
});
|
|
|
|
demoObjects.sort(function (a, b) {
|
|
if (a.name < b.name) {
|
|
return -1;
|
|
} else if (a.name > b.name) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
});
|
|
|
|
const helloWorldIndex = Math.max(demoObjects.indexOf(helloWorld), 0);
|
|
|
|
for (let i = 0; i < demoObjects.length; ++i) {
|
|
demoJSONs[i] = JSON.stringify(demoObjects[i], null, 2);
|
|
}
|
|
|
|
const contents = `\
|
|
// This file is automatically rebuilt by the Cesium build process.\n\
|
|
const hello_world_index = ${helloWorldIndex};\n\
|
|
const VERSION = '${version}';\n\
|
|
const gallery_demos = [${demoJSONs.join(", ")}];\n\
|
|
const has_new_gallery_demos = ${newDemos.length > 0 ? "true;" : "false;"}\n`;
|
|
|
|
await writeFile(output, contents);
|
|
|
|
// Compile CSS for Sandcastle
|
|
return esbuild.build({
|
|
entryPoints: [
|
|
path.join("Apps", "Sandcastle", "templates", "bucketRaw.css"),
|
|
],
|
|
minify: true,
|
|
banner: {
|
|
css: "/* This file is automatically rebuilt by the Cesium build process. */\n",
|
|
},
|
|
outfile: path.join("Apps", "Sandcastle", "templates", "bucket.css"),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Helper function to copy files.
|
|
*
|
|
* @param {string[]} globs The file globs to be copied.
|
|
* @param {string} destination The path to copy the files to.
|
|
* @param {string} base The base path to omit from the globs when files are copied. Defaults to "".
|
|
* @returns {Promise<Buffer>} A promise containing the stream output as a buffer.
|
|
*/
|
|
export async function copyFiles(globs, destination, base) {
|
|
const stream = gulp
|
|
.src(globs, { nodir: true, base: base ?? "", encoding: false })
|
|
.pipe(gulp.dest(destination));
|
|
|
|
await finished(stream);
|
|
return stream;
|
|
}
|
|
|
|
/**
|
|
* Copy assets from engine.
|
|
*
|
|
* @param {string} destination The path to copy files to.
|
|
* @returns {Promise<void>} A promise that completes when all assets are copied to the destination.
|
|
*/
|
|
export async function copyEngineAssets(destination) {
|
|
const engineStaticAssets = [
|
|
"packages/engine/Source/**",
|
|
"!packages/engine/Source/**/*.js",
|
|
"!packages/engine/Source/**/*.ts",
|
|
"!packages/engine/Source/**/*.glsl",
|
|
"!packages/engine/Source/**/*.css",
|
|
"!packages/engine/Source/**/*.md",
|
|
];
|
|
|
|
await copyFiles(engineStaticAssets, destination, "packages/engine/Source");
|
|
|
|
// Since the CesiumWidget was part of the Widgets folder, the files must be manually
|
|
// copied over to the right directory.
|
|
|
|
await copyFiles(
|
|
["packages/engine/Source/Widget/**", "!packages/engine/Source/Widget/*.js"],
|
|
path.join(destination, "Widgets/CesiumWidget"),
|
|
"packages/engine/Source/Widget",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Copy assets from widgets.
|
|
*
|
|
* @param {string} destination The path to copy files to.
|
|
* @returns {Promise<void>} A promise that completes when all assets are copied to the destination.
|
|
*/
|
|
export async function copyWidgetsAssets(destination) {
|
|
const widgetsStaticAssets = [
|
|
"packages/widgets/Source/**",
|
|
"!packages/widgets/Source/**/*.js",
|
|
"!packages/widgets/Source/**/*.ts",
|
|
"!packages/widgets/Source/**/*.css",
|
|
"!packages/widgets/Source/**/*.glsl",
|
|
"!packages/widgets/Source/**/*.md",
|
|
];
|
|
|
|
await copyFiles(widgetsStaticAssets, destination, "packages/widgets/Source");
|
|
}
|
|
|
|
/**
|
|
* Creates .jshintrc for use in Sandcastle
|
|
* @returns {Buffer} contents
|
|
*/
|
|
export async function createJsHintOptions() {
|
|
const jshintrc = JSON.parse(
|
|
await readFile(path.join("Apps", "Sandcastle", ".jshintrc"), {
|
|
encoding: "utf8",
|
|
}),
|
|
);
|
|
|
|
const contents = `\
|
|
// This file is automatically rebuilt by the Cesium build process.\n\
|
|
const sandcastleJsHintOptions = ${JSON.stringify(jshintrc, null, 4)};\n`;
|
|
|
|
await writeFile(
|
|
path.join("Apps", "Sandcastle", "jsHintOptions.js"),
|
|
contents,
|
|
);
|
|
|
|
return contents;
|
|
}
|
|
|
|
/**
|
|
* Bundles spec files for testing in the browser and on the command line with karma.
|
|
* @param {object} options
|
|
* @param {boolean} [options.incremental=false] true if the build should be cached for repeated rebuilds
|
|
* @param {boolean} [options.write=false] true if build output should be written to disk. If false, the files that would have been written as in-memory buffers
|
|
* @returns {Promise<any>}
|
|
*/
|
|
export async function bundleCombinedSpecs(options) {
|
|
options = options || {};
|
|
|
|
let build = esbuild.build;
|
|
if (options.incremental) {
|
|
build = esbuild.context;
|
|
}
|
|
|
|
return build({
|
|
entryPoints: [
|
|
"Specs/spec-main.js",
|
|
"Specs/SpecList.js",
|
|
"Specs/karma-main.js",
|
|
],
|
|
bundle: true,
|
|
format: "esm",
|
|
sourcemap: true,
|
|
outdir: path.join("Build", "Specs"),
|
|
plugins: [externalResolvePlugin],
|
|
write: options.write,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Bundles test worker in used specs.
|
|
* @param {object} options
|
|
* @param {boolean} [options.incremental=false] true if the build should be cached for repeated rebuilds
|
|
* @param {boolean} [options.write=false] true if build output should be written to disk. If false, the files that would have been written as in-memory buffers
|
|
* @returns {Promise<any>}
|
|
*/
|
|
export async function bundleTestWorkers(options) {
|
|
options = options || {};
|
|
|
|
let build = esbuild.build;
|
|
if (options.incremental) {
|
|
build = esbuild.context;
|
|
}
|
|
|
|
const workers = await globby(["Specs/TestWorkers/**.js"]);
|
|
return build({
|
|
entryPoints: workers,
|
|
bundle: true,
|
|
format: "esm",
|
|
sourcemap: true,
|
|
outdir: path.join("Build", "Specs", "TestWorkers"),
|
|
external: ["fs", "path"],
|
|
write: options.write,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates the index.js for a package.
|
|
*
|
|
* @param {string} workspace The workspace to create the index.js for.
|
|
* @returns
|
|
*/
|
|
export async function createIndexJs(workspace) {
|
|
const version = await getVersion();
|
|
let contents = `globalThis.CESIUM_VERSION = "${version}";\n`;
|
|
|
|
// Iterate over all provided source files for the workspace and export the assignment based on file name.
|
|
const workspaceSources = workspaceSourceFiles[workspace];
|
|
if (!workspaceSources) {
|
|
throw new Error(`Unable to find source files for workspace: ${workspace}`);
|
|
}
|
|
|
|
const files = await globby(workspaceSources);
|
|
files.forEach(function (file) {
|
|
file = path.relative(`packages/${workspace}`, file);
|
|
|
|
let moduleId = file;
|
|
moduleId = filePathToModuleId(moduleId);
|
|
|
|
// Rename shader files, such that ViewportQuadFS.glsl is exported as _shadersViewportQuadFS in JS.
|
|
|
|
let assignmentName = path.basename(file, path.extname(file));
|
|
if (moduleId.indexOf(`Source/Shaders/`) === 0) {
|
|
assignmentName = `_shaders${assignmentName}`;
|
|
}
|
|
assignmentName = assignmentName.replace(/(\.|-)/g, "_");
|
|
contents += `export { default as ${assignmentName} } from './${moduleId}.js';${EOL}`;
|
|
});
|
|
|
|
await writeFile(`packages/${workspace}/index.js`, contents, {
|
|
encoding: "utf-8",
|
|
});
|
|
|
|
return contents;
|
|
}
|
|
|
|
/**
|
|
* Creates a single entry point file by importing all individual spec files.
|
|
* @param {string[]} files The individual spec files.
|
|
* @param {string} workspace The workspace.
|
|
* @param {string} outputPath The path the file is written to.
|
|
*/
|
|
async function createSpecListForWorkspace(files, workspace, outputPath) {
|
|
let contents = "";
|
|
files.forEach(function (file) {
|
|
contents += `import './${filePathToModuleId(file).replace(
|
|
`packages/${workspace}/Specs/`,
|
|
"",
|
|
)}.js';\n`;
|
|
});
|
|
|
|
await writeFile(outputPath, contents, {
|
|
encoding: "utf-8",
|
|
});
|
|
|
|
return contents;
|
|
}
|
|
|
|
/**
|
|
* Bundles CSS files.
|
|
*
|
|
* @param {object} options
|
|
* @param {string[]} options.filePaths The file paths to bundle.
|
|
* @param {boolean} options.sourcemap
|
|
* @param {boolean} options.minify
|
|
* @param {string} options.outdir The output directory.
|
|
* @param {string} options.outbase The
|
|
*/
|
|
async function bundleCSS(options) {
|
|
// Configure options for esbuild.
|
|
const esBuildOptions = defaultESBuildOptions();
|
|
esBuildOptions.entryPoints = await globby(options.filePaths);
|
|
esBuildOptions.loader = {
|
|
".gif": "text",
|
|
".png": "text",
|
|
};
|
|
esBuildOptions.sourcemap = options.sourcemap;
|
|
esBuildOptions.minify = options.minify;
|
|
esBuildOptions.outdir = options.outdir;
|
|
esBuildOptions.outbase = options.outbase;
|
|
|
|
await esbuild.build(esBuildOptions);
|
|
}
|
|
|
|
const workspaceCssFiles = {
|
|
engine: ["packages/engine/Source/**/*.css"],
|
|
widgets: ["packages/widgets/Source/**/*.css"],
|
|
};
|
|
|
|
/**
|
|
* Bundles spec files for testing in the browser.
|
|
*
|
|
* @param {object} options
|
|
* @param {boolean} [options.incremental=false] True if builds should be generated incrementally.
|
|
* @param {string} options.outbase The base path the output files are relative to.
|
|
* @param {string} options.outdir The directory to place the output in.
|
|
* @param {string} options.specListFile The path to the SpecList.js file
|
|
* @param {boolean} [options.write=true] True if bundles generated are written to files instead of in-memory buffers.
|
|
* @returns {object} The bundle generated from Specs.
|
|
*/
|
|
async function bundleSpecs(options) {
|
|
const incremental = options.incremental ?? true;
|
|
const write = options.write ?? true;
|
|
|
|
const buildOptions = {
|
|
bundle: true,
|
|
format: "esm",
|
|
outdir: options.outdir,
|
|
sourcemap: true,
|
|
target: "es2020",
|
|
write: write,
|
|
};
|
|
|
|
let build = esbuild.build;
|
|
if (incremental) {
|
|
build = esbuild.context;
|
|
}
|
|
|
|
// When bundling specs for a workspace, the spec-main.js and karma-main.js
|
|
// are bundled separately since they use a different outbase than the workspace's SpecList.js.
|
|
await build({
|
|
...buildOptions,
|
|
entryPoints: ["Specs/spec-main.js", "Specs/karma-main.js"],
|
|
});
|
|
|
|
return build({
|
|
...buildOptions,
|
|
entryPoints: [options.specListFile],
|
|
outbase: options.outbase,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Builds the engine workspace.
|
|
*
|
|
* @param {object} options
|
|
* @param {boolean} [options.incremental=false] True if builds should be generated incrementally.
|
|
* @param {boolean} [options.minify=false] True if bundles should be minified.
|
|
* @param {boolean} [options.write=true] True if bundles generated are written to files instead of in-memory buffers.
|
|
*/
|
|
export const buildEngine = async (options) => {
|
|
options = options || {};
|
|
|
|
const incremental = options.incremental ?? false;
|
|
const minify = options.minify ?? false;
|
|
const write = options.write ?? true;
|
|
|
|
// Create Build folder to place build artifacts.
|
|
mkdirp.sync("packages/engine/Build");
|
|
|
|
// Convert GLSL files to JavaScript modules.
|
|
await glslToJavaScript(
|
|
minify,
|
|
"packages/engine/Build/minifyShaders.state",
|
|
"engine",
|
|
);
|
|
|
|
// Create index.js
|
|
await createIndexJs("engine");
|
|
|
|
const contexts = await bundleIndexJs({
|
|
minify: minify,
|
|
incremental: incremental,
|
|
sourcemap: true,
|
|
removePragmas: false,
|
|
outputDirectory: path.join(
|
|
`packages/engine/Build`,
|
|
`${!minify ? "Unminified" : "Minified"}`,
|
|
),
|
|
write: write,
|
|
entryPoint: `packages/engine/index.js`,
|
|
});
|
|
|
|
// Build workers.
|
|
await bundleWorkers({
|
|
...options,
|
|
iife: false,
|
|
path: "packages/engine/Build",
|
|
});
|
|
|
|
// Create SpecList.js
|
|
const specFiles = await globby(workspaceSpecFiles["engine"]);
|
|
const specListFile = path.join("packages/engine/Specs", "SpecList.js");
|
|
await createSpecListForWorkspace(specFiles, "engine", specListFile);
|
|
|
|
await bundleSpecs({
|
|
incremental: incremental,
|
|
outbase: "packages/engine/Specs",
|
|
outdir: "packages/engine/Build/Specs",
|
|
specListFile: specListFile,
|
|
write: write,
|
|
});
|
|
|
|
return contexts;
|
|
};
|
|
|
|
/**
|
|
* Builds the widgets workspace.
|
|
*
|
|
* @param {object} options
|
|
* @param {boolean} [options.incremental=false] True if builds should be generated incrementally.
|
|
* @param {boolean} [options.minify=false] True if bundles should be minified.
|
|
* @param {boolean} [options.write=true] True if bundles generated are written to files instead of in-memory buffers.
|
|
*/
|
|
export const buildWidgets = async (options) => {
|
|
options = options || {};
|
|
|
|
const incremental = options.incremental ?? false;
|
|
const minify = options.minify ?? false;
|
|
const write = options.write ?? true;
|
|
|
|
// Generate Build folder to place build artifacts.
|
|
mkdirp.sync("packages/widgets/Build");
|
|
|
|
// Create index.js
|
|
await createIndexJs("widgets");
|
|
|
|
const contexts = await bundleIndexJs({
|
|
minify: minify,
|
|
incremental: incremental,
|
|
sourcemap: true,
|
|
removePragmas: false,
|
|
outputDirectory: path.join(
|
|
`packages/widgets/Build`,
|
|
`${!minify ? "Unminified" : "Minified"}`,
|
|
),
|
|
write: write,
|
|
entryPoint: `packages/widgets/index.js`,
|
|
});
|
|
|
|
// Create SpecList.js
|
|
const specFiles = await globby(workspaceSpecFiles["widgets"]);
|
|
const specListFile = path.join("packages/widgets/Specs", "SpecList.js");
|
|
await createSpecListForWorkspace(specFiles, "widgets", specListFile);
|
|
|
|
await bundleSpecs({
|
|
incremental: incremental,
|
|
outbase: "packages/widgets/Specs",
|
|
outdir: "packages/widgets/Build/Specs",
|
|
specListFile: specListFile,
|
|
write: write,
|
|
});
|
|
|
|
return contexts;
|
|
};
|
|
|
|
/**
|
|
* Build CesiumJS.
|
|
*
|
|
* @param {object} options
|
|
* @param {boolean} [options.development=true] True if build is targeted for development.
|
|
* @param {boolean} [options.iife=true] True if IIFE bundle should be generated.
|
|
* @param {boolean} [options.incremental=true] True if builds should be generated incrementally.
|
|
* @param {boolean} [options.minify=false] True if bundles should be minified.
|
|
* @param {boolean} [options.node=true] True if CommonJS bundle should be generated.
|
|
* @param {boolean} options.outputDirectory The directory where the output should go.
|
|
* @param {boolean} [options.removePragmas=false] True if debug pragmas should be removed.
|
|
* @param {boolean} [options.sourcemap=true] True if sourcemap should be included in the generated bundles.
|
|
* @param {boolean} [options.write=true] True if bundles generated are written to files instead of in-memory buffers.
|
|
*/
|
|
export async function buildCesium(options) {
|
|
const development = options.development ?? true;
|
|
const iife = options.iife ?? true;
|
|
const incremental = options.incremental ?? false;
|
|
const minify = options.minify ?? false;
|
|
const node = options.node ?? true;
|
|
const removePragmas = options.removePragmas ?? false;
|
|
const sourcemap = options.sourcemap ?? true;
|
|
const write = options.write ?? true;
|
|
|
|
// Generate Build folder to place build artifacts.
|
|
mkdirp.sync("Build");
|
|
const outputDirectory =
|
|
options.outputDirectory ??
|
|
path.join("Build", `Cesium${!minify ? "Unminified" : ""}`);
|
|
rimraf.sync(outputDirectory);
|
|
|
|
await writeFile(
|
|
"Build/package.json",
|
|
JSON.stringify({
|
|
type: "commonjs",
|
|
}),
|
|
"utf8",
|
|
);
|
|
|
|
// Create Cesium.js
|
|
await createCesiumJs();
|
|
|
|
// Create SpecList.js
|
|
await createCombinedSpecList();
|
|
|
|
// Bundle ThirdParty files.
|
|
await bundleCSS({
|
|
filePaths: [
|
|
"packages/engine/Source/ThirdParty/google-earth-dbroot-parser.js",
|
|
],
|
|
minify: minify,
|
|
sourcemap: sourcemap,
|
|
outdir: outputDirectory,
|
|
outbase: "packages/engine/Source",
|
|
});
|
|
|
|
// Bundle CSS files.
|
|
await bundleCSS({
|
|
filePaths: workspaceCssFiles[`engine`],
|
|
outdir: path.join(outputDirectory, "Widgets/CesiumWidget"),
|
|
outbase: "packages/engine/Source/Widget",
|
|
});
|
|
await bundleCSS({
|
|
filePaths: workspaceCssFiles[`widgets`],
|
|
outdir: path.join(outputDirectory, "Widgets"),
|
|
outbase: "packages/widgets/Source",
|
|
});
|
|
|
|
const workersContext = await bundleWorkers({
|
|
iife: false,
|
|
minify: minify,
|
|
sourcemap: sourcemap,
|
|
path: outputDirectory,
|
|
removePragmas: removePragmas,
|
|
incremental: incremental,
|
|
write: write,
|
|
});
|
|
|
|
// Generate bundles.
|
|
const contexts = await bundleCesiumJs({
|
|
minify: minify,
|
|
iife: iife,
|
|
incremental: incremental,
|
|
sourcemap: sourcemap,
|
|
removePragmas: removePragmas,
|
|
path: outputDirectory,
|
|
node: node,
|
|
write: write,
|
|
});
|
|
|
|
await Promise.all([createJsHintOptions(), createGalleryList(!development)]);
|
|
|
|
// Generate Specs bundle.
|
|
const specsContext = await bundleCombinedSpecs({
|
|
incremental: incremental,
|
|
write: write,
|
|
});
|
|
|
|
const testWorkersContext = await bundleTestWorkers({
|
|
incremental: incremental,
|
|
write: write,
|
|
});
|
|
|
|
// Copy static assets to the Build folder.
|
|
|
|
await copyEngineAssets(outputDirectory);
|
|
await copyWidgetsAssets(path.join(outputDirectory, "Widgets"));
|
|
|
|
// Copy static assets to Source folder.
|
|
|
|
await copyEngineAssets("Source");
|
|
await copyFiles(
|
|
["packages/engine/Source/ThirdParty/**/*.js"],
|
|
"Source/ThirdParty",
|
|
"packages/engine/Source/ThirdParty",
|
|
);
|
|
|
|
await copyWidgetsAssets("Source/Widgets");
|
|
await copyFiles(
|
|
["packages/widgets/Source/**/*.css"],
|
|
"Source/Widgets",
|
|
"packages/widgets/Source",
|
|
);
|
|
|
|
// WORKAROUND:
|
|
// Since CesiumWidget was originally part of the Widgets folder, we need to fix up any
|
|
// references to it when we put it back in the Widgets folder, as expected by the
|
|
// combined CesiumJS structure.
|
|
const widgetsCssBuffer = await readFile("Source/Widgets/widgets.css");
|
|
const widgetsCssContents = widgetsCssBuffer
|
|
.toString()
|
|
.replace("../../engine/Source/Widget", "./CesiumWidget");
|
|
await writeFile("Source/Widgets/widgets.css", widgetsCssContents);
|
|
|
|
const lighterCssBuffer = await readFile("Source/Widgets/lighter.css");
|
|
const lighterCssContents = lighterCssBuffer
|
|
.toString()
|
|
.replace("../../engine/Source/Widget", "./CesiumWidget");
|
|
await writeFile("Source/Widgets/lighter.css", lighterCssContents);
|
|
|
|
return {
|
|
esm: contexts.esm,
|
|
iife: contexts.iife,
|
|
iifeWorkers: contexts.iifeWorkers,
|
|
node: contexts.node,
|
|
specs: specsContext,
|
|
workers: workersContext,
|
|
testWorkers: testWorkersContext,
|
|
};
|
|
}
|