Skip to content

Commit

Permalink
Refactor all of our various cra build steps (#9907)
Browse files Browse the repository at this point in the history
* refactor all of our various cra build steps

* fix referenceerror from import

* remove webapp names array in server.ts

* move config into json and use in prepare script

* copy config to built and use config for strings
  • Loading branch information
riknoll authored Mar 6, 2024
1 parent 038ac49 commit d800fdd
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 270 deletions.
174 changes: 84 additions & 90 deletions cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import * as pyconv from './pyconv';
import * as gitfs from './gitfs';
import * as crowdin from './crowdin';
import * as youtube from './youtube';
import { SUB_WEBAPPS } from './subwebapp';

const rimraf: (f: string, opts: any, cb: (err: Error, res: any) => void) => void = require('rimraf');

Expand All @@ -40,6 +41,7 @@ let forceBuild = false; // don't use cache

Error.stackTraceLimit = 100;


function parseHwVariant(parsed: commandParser.ParsedCommand) {
let hwvariant = parsed && parsed.flags["hwvariant"] as string;
if (hwvariant) {
Expand Down Expand Up @@ -354,23 +356,16 @@ function onlyExts(files: string[], exts: string[]) {
}

function pxtFileList(pref: string) {
return nodeutil.allFiles(pref + "webapp/public")
let allFiles = nodeutil.allFiles(pref + "webapp/public")
.concat(onlyExts(nodeutil.allFiles(pref + "built/web", { maxDepth: 1 }), [".js", ".css"]))
.concat(nodeutil.allFiles(pref + "built/web/fonts", { maxDepth: 1 }))
.concat(nodeutil.allFiles(pref + "built/web/vs", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/skillmap", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/authcode", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/multiplayer", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/kiosk", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/teachertool", { maxDepth: 4 }))
}
.concat(nodeutil.allFiles(pref + "built/web/vs", { maxDepth: 4 }));

function semverCmp(a: string, b: string) {
let parse = (s: string) => {
let v = s.split(/\./).map(parseInt)
return v[0] * 100000000 + v[1] * 10000 + v[2]
for (const subapp of SUB_WEBAPPS) {
allFiles = allFiles.concat(nodeutil.allFiles(pref + `built/web/${subapp.name}`, { maxDepth: 4 }))
}
return parse(a) - parse(b)

return allFiles;
}

function checkIfTaggedCommitAsync() {
Expand All @@ -394,7 +389,7 @@ function checkIfTaggedCommitAsync() {

let readJson = nodeutil.readJson;

function ciAsync() {
async function ciAsync() {
forceCloudBuild = true;
const buildInfo = ciBuildInfo();
pxt.log(`ci build using ${buildInfo.ci}`);
Expand Down Expand Up @@ -447,54 +442,54 @@ function ciAsync() {
let pkg = readJson("package.json")
if (pkg["name"] == "pxt-core") {
pxt.log("pxt-core build");
return checkIfTaggedCommitAsync()
.then(isTaggedCommit => {
pxt.log(`is tagged commit: ${isTaggedCommit}`);
let p = npmPublishAsync();
if (branch === "master" && isTaggedCommit) {
if (uploadDocs)
p = p
.then(() => buildWebStringsAsync())
.then(() => crowdin.execCrowdinAsync("upload", "built/webstrings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/skillmap-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/authcode-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/multiplayer-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/kiosk-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/teachertool-strings.json"));
if (uploadApiStrings)
p = p.then(() => crowdin.execCrowdinAsync("upload", "built/strings.json"))
if (uploadDocs || uploadApiStrings)
p = p.then(() => crowdin.internalUploadTargetTranslationsAsync(uploadApiStrings, uploadDocs));

const isTaggedCommit = await checkIfTaggedCommitAsync();
pxt.log(`is tagged commit: ${isTaggedCommit}`);
await npmPublishAsync();
if (branch === "master" && isTaggedCommit) {
if (uploadDocs) {
await buildWebStringsAsync();
await crowdin.execCrowdinAsync("upload", "built/webstrings.json");

for (const subapp of SUB_WEBAPPS) {
await crowdin.execCrowdinAsync("upload", `built/${subapp.name}-strings.json`);
}
return p;
});
}
if (uploadApiStrings) {
await crowdin.execCrowdinAsync("upload", "built/strings.json");
}
if (uploadDocs || uploadApiStrings) {
await crowdin.internalUploadTargetTranslationsAsync(uploadApiStrings, uploadDocs);
pxt.log("translations uploaded");
}
else {
pxt.log("skipping translations upload");
}
}
} else {
pxt.log("target build");
return internalBuildTargetAsync()
.then(() => internalCheckDocsAsync(true))
.then(() => blockTestsAsync())
.then(() => npmPublishAsync())
.then(() => {
if (!process.env["PXT_ACCESS_TOKEN"]) {
// pull request, don't try to upload target
pxt.log('no token, skipping upload')
return Promise.resolve();
}
const trg = readLocalPxTarget();
const label = `${trg.id}/${tag || latest}`;
pxt.log(`uploading target with label ${label}...`);
return uploadTargetAsync(label);
})
.then(() => {
pxt.log("target uploaded");
if (uploadDocs || uploadApiStrings) {
return crowdin.internalUploadTargetTranslationsAsync(uploadApiStrings, uploadDocs)
.then(() => pxt.log("translations uploaded"));
} else {
pxt.log("skipping translations upload");
return Promise.resolve();
}
});
await internalBuildTargetAsync();
await internalCheckDocsAsync(true);
await blockTestsAsync();
await npmPublishAsync();

if (!process.env["PXT_ACCESS_TOKEN"]) {
// pull request, don't try to upload target
pxt.log('no token, skipping upload')
return;
}
const trg = readLocalPxTarget();
const label = `${trg.id}/${tag || latest}`;
pxt.log(`uploading target with label ${label}...`);
await uploadTargetAsync(label);

pxt.log("target uploaded");
if (uploadDocs || uploadApiStrings) {
await crowdin.internalUploadTargetTranslationsAsync(uploadApiStrings, uploadDocs);
pxt.log("translations uploaded");
} else {
pxt.log("skipping translations upload");
}
}
}

Expand Down Expand Up @@ -1021,7 +1016,7 @@ function uploadCoreAsync(opts: UploadOptions) {
}

if (opts.localDir) {
let cfg: pxt.WebConfig = {
let cfg: Partial<pxt.WebConfig> = {
"relprefix": opts.localDir,
"verprefix": "",
"workerjs": opts.localDir + "worker.js",
Expand All @@ -1047,13 +1042,13 @@ function uploadCoreAsync(opts: UploadOptions) {
"docsUrl": opts.localDir + "docs.html",
"multiUrl": opts.localDir + "multi.html",
"asseteditorUrl": opts.localDir + "asseteditor.html",
"skillmapUrl": opts.localDir + "skillmap.html",
"authcodeUrl": opts.localDir + "authcode.html",
"multiplayerUrl": opts.localDir + "multiplayer.html",
"kioskUrl": opts.localDir + "kiosk.html",
"teachertoolUrl": opts.localDir + "teachertool.html",
"isStatic": true,
}

for (const subapp of SUB_WEBAPPS) {
(cfg as any)[subapp.name + "Url"] = opts.localDir + subapp.name + ".html";
}

const targetImageLocalPaths = targetImagePaths.map(k =>
`${opts.localDir}${path.join('./docs', k)}`);

Expand Down Expand Up @@ -1100,25 +1095,20 @@ function uploadCoreAsync(opts: UploadOptions) {
"sim.webmanifest",
"workerConfig.js",
"multi.html",
"asseteditor.html",
"skillmap.html",
"authcode.html",
"multiplayer.html",
"kiosk.html",
"teachertool.html",
"asseteditor.html"
]

// expandHtml is manually called on these files before upload
// runs <!-- @include --> substitutions, fills in locale, etc
const expandFiles = [
"index.html",
"skillmap.html",
"authcode.html",
"multiplayer.html",
"kiosk.html",
"teachertool.html",
"index.html"
]

for (const subapp of SUB_WEBAPPS) {
replFiles.push(`${subapp.name}.html`);
expandFiles.push(`${subapp.name}.html`);
}

nodeutil.mkdirP("built/uploadrepl")

function encodeURLs(urls: string[]) {
Expand Down Expand Up @@ -2043,11 +2033,10 @@ async function buildSemanticUIAsync(parsed?: commandParser.ParsedCommand) {
}

// Generate react-common css for skillmap, authcode, and multiplayer (but not kiosk yet)
await Promise.all([
generateReactCommonCss("skillmap"),
generateReactCommonCss("authcode"),
generateReactCommonCss("multiplayer"),
]);

await Promise.all(
SUB_WEBAPPS.filter(app => app.buildCss).map(app => generateReactCommonCss(app.name))
);

// Run postcss with autoprefixer and rtlcss
pxt.debug("running postcss");
Expand All @@ -2072,12 +2061,15 @@ async function buildSemanticUIAsync(parsed?: commandParser.ParsedCommand) {
const rtlcss = require("rtlcss");
const files = [
"semantic.css",
"blockly.css",
"react-common-skillmap.css",
"react-common-authcode.css",
"react-common-multiplayer.css"
"blockly.css"
];

for (const subapp of SUB_WEBAPPS) {
if (subapp.buildCss) {
files.push(`react-common-${subapp.name}.css`);
}
}

for (const cssFile of files) {
const css = await readFileAsync(`built/web/${cssFile}`, "utf8");
const processed = await postcss([cssnano])
Expand All @@ -2093,10 +2085,12 @@ async function buildSemanticUIAsync(parsed?: commandParser.ParsedCommand) {

if (!isPxtCore) {
// This is just to support the local skillmap/cra-app serve for development
nodeutil.cp("built/web/react-common-skillmap.css", "node_modules/pxt-core/skillmap/public/blb");
nodeutil.cp("built/web/react-common-authcode.css", "node_modules/pxt-core/authcode/public/blb");
nodeutil.cp("built/web/semantic.css", "node_modules/pxt-core/skillmap/public/blb");
nodeutil.cp("built/web/semantic.css", "node_modules/pxt-core/authcode/public/blb");
for (const subapp of SUB_WEBAPPS) {
if (subapp.buildCss) {
nodeutil.cp(`built/web/react-common-${subapp.name}.css`, `node_modules/pxt-core/${subapp.name}/public/blb`);
nodeutil.cp(`built/web/semantic.css`, `node_modules/pxt-core/${subapp.name}/public/blb`);
}
}
}
}

Expand Down
29 changes: 8 additions & 21 deletions cli/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import * as querystring from 'querystring';
import * as nodeutil from './nodeutil';
import * as hid from './hid';
import * as net from 'net';
import * as crowdin from './crowdin';
import * as storage from './storage';
import { SUB_WEBAPPS } from './subwebapp';

import { promisify } from "util";

Expand All @@ -25,13 +25,6 @@ let packagedDir = ""
let localHexCacheDir = path.join("built", "hexcache");
let serveOptions: ServeOptions;

const webappNames = [
"kiosk",
"multiplayer",
"eval"
// TODO: Add other webapp names here: "skillmap", "authcode"
];

function setupDocfilesdirs() {
docfilesdirs = [
"docfiles",
Expand Down Expand Up @@ -1073,6 +1066,8 @@ export function serveAsync(options: ServeOptions) {
});
};

const webappNames = SUB_WEBAPPS.filter(w => w.localServeEndpoint).map(w => w.localServeEndpoint);

const webappIdx = webappNames.findIndex(s => new RegExp(`^-{0,3}${s}$`).test(elts[0] || ''));
if (webappIdx >= 0) {
const webappName = webappNames[webappIdx];
Expand Down Expand Up @@ -1184,19 +1179,11 @@ export function serveAsync(options: ServeOptions) {
return
}

if (pathname == "/--skillmap") {
sendFile(path.join(publicDir, 'skillmap.html'));
return
}

if (pathname == "/--authcode") {
sendFile(path.join(publicDir, 'authcode.html'));
return
}

if (pathname == "/--multiplayer") {
sendFile(path.join(publicDir, 'multiplayer.html'));
return
for (const subapp of SUB_WEBAPPS) {
if (subapp.localServeWebConfigUrl && pathname === `/--${subapp.name}`) {
sendFile(path.join(publicDir, `${subapp.name}.html`));
return
}
}

if (/\/-[-]*docs.*$/.test(pathname)) {
Expand Down
14 changes: 14 additions & 0 deletions cli/subwebapp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import config = require("./webapps-config.json");

export interface SubWebAppConfig {
name: string;
buildCss: boolean;

// If true, the local server will seve the "--" endpoint defined in the web config (e.g. /--skilmap)
localServeWebConfigUrl: boolean;

// If defined, the local serve will serve the webapp code at this endpoint (e.g. /eva;)
localServeEndpoint?: string;
}

export const SUB_WEBAPPS: SubWebAppConfig[] = config.webapps;
3 changes: 2 additions & 1 deletion cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"sourceMap": false,
"moduleResolution": "node",
"incremental": false,
"skipLibCheck": true
"skipLibCheck": true,
"resolveJsonModule": true
}
}
32 changes: 32 additions & 0 deletions cli/webapps-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"webapps": [
{
"name": "kiosk",
"buildCss": false,
"localServeWebConfigUrl": false,
"localServeEndpoint": "kiosk"
},
{
"name": "teachertool",
"buildCss": false,
"localServeWebConfigUrl": false,
"localServeEndpoint": "eval"
},
{
"name": "skillmap",
"buildCss": true,
"localServeWebConfigUrl": true
},
{
"name": "multiplayer",
"buildCss": true,
"localServeWebConfigUrl": true,
"localServeEndpoint": "multiplayer"
},
{
"name": "authcode",
"buildCss": true,
"localServeWebConfigUrl": true
}
]
}
Loading

0 comments on commit d800fdd

Please sign in to comment.