diff --git a/cli/cli.ts b/cli/cli.ts index 0fc07fd37524..6418a675742d 100644 --- a/cli/cli.ts +++ b/cli/cli.ts @@ -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'); @@ -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) { @@ -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() { @@ -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}`); @@ -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"); + } } } @@ -1021,7 +1016,7 @@ function uploadCoreAsync(opts: UploadOptions) { } if (opts.localDir) { - let cfg: pxt.WebConfig = { + let cfg: Partial = { "relprefix": opts.localDir, "verprefix": "", "workerjs": opts.localDir + "worker.js", @@ -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)}`); @@ -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 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[]) { @@ -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"); @@ -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]) @@ -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`); + } + } } } diff --git a/cli/server.ts b/cli/server.ts index b30b43049e94..c66ee6900ae0 100644 --- a/cli/server.ts +++ b/cli/server.ts @@ -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"; @@ -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", @@ -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]; @@ -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)) { diff --git a/cli/subwebapp.ts b/cli/subwebapp.ts new file mode 100644 index 000000000000..b470685bd90c --- /dev/null +++ b/cli/subwebapp.ts @@ -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; \ No newline at end of file diff --git a/cli/tsconfig.json b/cli/tsconfig.json index e55bf65f5db0..de85380ab811 100644 --- a/cli/tsconfig.json +++ b/cli/tsconfig.json @@ -17,6 +17,7 @@ "sourceMap": false, "moduleResolution": "node", "incremental": false, - "skipLibCheck": true + "skipLibCheck": true, + "resolveJsonModule": true } } \ No newline at end of file diff --git a/cli/webapps-config.json b/cli/webapps-config.json new file mode 100644 index 000000000000..048acb7f28e3 --- /dev/null +++ b/cli/webapps-config.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 43010467d7c0..80558301dc0b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -19,6 +19,8 @@ const clean = () => rimraf("built").then(() => rimraf("temp")); const update = () => exec("git pull", true).then(() => exec("npm install", true)) const noop = () => Promise.resolve(); +const SUB_WEBAPPS = require("./cli/webapps-config.json").webapps; + /** onlineline */ const onlinelearning = () => { const tasks = ["schedule", "projects"].map(fn => @@ -82,7 +84,7 @@ const pxtembed = () => gulp.src([ .pipe(concat("pxtembed.js")) .pipe(gulp.dest("built/web")); -const pxtjs = () => gulp.src([ +const buildpxtjs = () => gulp.src([ "pxtcompiler/ext-typescript/lib/typescript.js", "built/pxtlib.js", "built/pxtcompiler.js", @@ -99,6 +101,11 @@ const pxtjs = () => gulp.src([ `)) .pipe(gulp.dest("built")); +const copySubappsConfig = () => gulp.src("cli/webapps-config.json") + .pipe(gulp.dest("built")); + +const pxtjs = gulp.parallel(buildpxtjs, copySubappsConfig); + const pxtdts = () => gulp.src("built/cli.d.ts") .pipe(concat("pxt.d.ts")) .pipe(gulp.dest("built")); @@ -221,24 +228,8 @@ function updatestrings() { ], true); } -function updateSkillMapStrings() { - return buildStrings("built/skillmap-strings.json", ["skillmap/src"], true); -} - -function updateAuthcodeStrings() { - return buildStrings("built/authcode-strings.json", ["authcode/src"], true); -} - -function updateMultiplayerStrings() { - return buildStrings("built/multiplayer-strings.json", ["multiplayer/src"], true); -} - -function updateKioskStrings() { - return buildStrings("built/kiosk-strings.json", ["kiosk/src"], true); -} - -function updateTeacherToolStrings() { - return buildStrings("built/teachertool-strings.json", ["teachertool/src"], true); +function updateWebappStrings(name) { + return buildStrings(`built/${name}-strings.json`, [`${name}/src`], true); } // TODO: Copied from Jakefile; should be async @@ -519,32 +510,40 @@ const copyMonaco = gulp.series( stripMonacoSourceMaps ); -/******************************************************** - Skillmap -*********************************************************/ +function createWebappTasks(root, outname) { + outname = outname || root; + const outdir = `built/web/${outname}`; -const skillmapRoot = "skillmap"; -const skillmapOut = "built/web/skillmap"; + const cleanWebapp = () => rimraf(outdir); -const cleanSkillmap = () => rimraf(skillmapOut); + const npmBuildWebapp = () => exec("npm run build", true, { cwd: root }); -const npmBuildSkillmap = () => exec("npm run build", true, { cwd: skillmapRoot }); + const buildWebapp = async () => await npmBuildWebapp(); -const buildSkillmap = async () => await npmBuildSkillmap(); + const copyWebappCss = () => gulp.src(`${root}/build/static/css/*`) + .pipe(gulp.dest(`${outdir}/css`)); -const copySkillmapCss = () => gulp.src(`${skillmapRoot}/build/static/css/*`) - .pipe(gulp.dest(`${skillmapOut}/css`)); + const copyWebappJs = () => gulp.src(`${root}/build/static/js/*`) + .pipe(gulp.dest(`${outdir}/js`)); -const copySkillmapJs = () => gulp.src(`${skillmapRoot}/build/static/js/*`) - .pipe(gulp.dest(`${skillmapOut}/js`)); + const copyWebappHtml = () => rimraf(`webapp/public/${outname}.html`) + .then(() => gulp.src(`${root}/build/index.html`) + .pipe(replace(/="\/static\//g, `="/blb/${outname}/`)) + .pipe(concat(`${outname}.html`)) + .pipe(gulp.dest("webapp/public"))); -const copySkillmapHtml = () => rimraf("webapp/public/skillmap.html") - .then(() => gulp.src(`${skillmapRoot}/build/index.html`) - .pipe(replace(/="\/static\//g, `="/blb/skillmap/`)) - .pipe(concat("skillmap.html")) - .pipe(gulp.dest("webapp/public"))); + const result = gulp.series(cleanWebapp, buildWebapp, gulp.series(copyWebappCss, copyWebappJs, copyWebappHtml)); -const skillmap = gulp.series(cleanSkillmap, buildSkillmap, gulp.series(copySkillmapCss, copySkillmapJs, copySkillmapHtml)); + exports[outname] = result; + + return result; +} + +/******************************************************** + Skillmap +*********************************************************/ + +const skillmap = createWebappTasks("skillmap"); const buildSkillmapTests = () => compileTsProject("skillmap/tests", "built/tests"); const copySkillmapTests = () => gulp.src([ @@ -568,109 +567,25 @@ const testSkillmap = gulp.series(buildSkillmapTests, copySkillmapTests, runSkill Authcode *********************************************************/ -const authcodeRoot = "authcode"; -const authcodeOut = "built/web/authcode"; - -const cleanAuthcode = () => rimraf(authcodeOut); - -const npmBuildAuthcode = () => exec("npm run build", true, { cwd: authcodeRoot }); - -const buildAuthcode = async () => await npmBuildAuthcode(); - -const copyAuthcodeCss = () => gulp.src(`${authcodeRoot}/build/static/css/*`) - .pipe(gulp.dest(`${authcodeOut}/css`)); - -const copyAuthcodeJs = () => gulp.src(`${authcodeRoot}/build/static/js/*`) - .pipe(gulp.dest(`${authcodeOut}/js`)); - -const copyAuthcodeHtml = () => rimraf("webapp/public/authcode.html") - .then(() => gulp.src(`${authcodeRoot}/build/index.html`) - .pipe(replace(/="\/static\//g, `="/blb/authcode/`)) - .pipe(concat("authcode.html")) - .pipe(gulp.dest("webapp/public"))); - -const authcode = gulp.series(cleanAuthcode, buildAuthcode, gulp.series(copyAuthcodeCss, copyAuthcodeJs, copyAuthcodeHtml)); +const authcode = createWebappTasks("authcode"); /******************************************************** Multiplayer *********************************************************/ -const multiplayerRoot = "multiplayer"; -const multiplayerOut = "built/web/multiplayer"; - -const cleanMultiplayer = () => rimraf(multiplayerOut); - -const npmBuildMultiplayer = () => exec("npm run build", true, { cwd: multiplayerRoot }); - -const buildMultiplayer = async () => await npmBuildMultiplayer(); - -const copyMultiplayerCss = () => gulp.src(`${multiplayerRoot}/build/static/css/*`) - .pipe(gulp.dest(`${multiplayerOut}/css`)); - -const copyMultiplayerJs = () => gulp.src(`${multiplayerRoot}/build/static/js/*`) - .pipe(gulp.dest(`${multiplayerOut}/js`)); - -const copyMultiplayerHtml = () => rimraf("webapp/public/multiplayer.html") - .then(() => gulp.src(`${multiplayerRoot}/build/index.html`) - .pipe(replace(/="\/static\//g, `="/blb/multiplayer/`)) - .pipe(concat("multiplayer.html")) - .pipe(gulp.dest("webapp/public"))); - -const multiplayer = gulp.series(cleanMultiplayer, buildMultiplayer, gulp.series(copyMultiplayerCss, copyMultiplayerJs, copyMultiplayerHtml)); +const multiplayer = createWebappTasks("multiplayer"); /******************************************************** Kiosk *********************************************************/ -const kioskRoot = "kiosk"; -const kioskOut = "built/web/kiosk"; - -const cleanKiosk = () => rimraf(kioskOut); - -const npmBuildKiosk = () => exec("npm run build", true, { cwd: kioskRoot }); - -const buildKiosk = async () => await npmBuildKiosk(); - -const copyKioskCss = () => gulp.src(`${kioskRoot}/build/static/css/*`) - .pipe(gulp.dest(`${kioskOut}/css`)); - -const copyKioskJs = () => gulp.src(`${kioskRoot}/build/static/js/*`) - .pipe(gulp.dest(`${kioskOut}/js`)); - -const copyKioskHtml = () => rimraf("webapp/public/kiosk.html") - .then(() => gulp.src(`${kioskRoot}/build/index.html`) - .pipe(replace(/="\/static\//g, `="/blb/kiosk/`)) - .pipe(concat("kiosk.html")) - .pipe(gulp.dest("webapp/public"))); - -const kiosk = gulp.series(cleanKiosk, buildKiosk, gulp.series(copyKioskCss, copyKioskJs, copyKioskHtml)); +const kiosk = createWebappTasks("kiosk"); /******************************************************** Teacher Tool *********************************************************/ -const teacherToolRoot = "teachertool"; -const teacherToolOut = "built/web/teachertool"; - -const cleanTeacherTool = () => rimraf(teacherToolOut); - -const npmBuildTeacherTool = () => exec("npm run build", true, { cwd: teacherToolRoot }); - -const buildTeacherTool = async () => await npmBuildTeacherTool(); - -const copyTeacherToolCss = () => gulp.src(`${teacherToolRoot}/build/static/css/*`) - .pipe(gulp.dest(`${teacherToolOut}/css`)); - -const copyTeacherToolJs = () => gulp.src(`${teacherToolRoot}/build/static/js/*`) - .pipe(gulp.dest(`${teacherToolOut}/js`)); - -const copyTeacherToolHtml = () => rimraf("webapp/public/teachertool.html") - .then(() => gulp.src(`${teacherToolRoot}/build/index.html`) - .pipe(replace(/="\/static\//g, `="/blb/teachertool/`)) - .pipe(concat("teachertool.html")) - .pipe(gulp.dest("webapp/public"))); - -const teacherTool = gulp.series(cleanTeacherTool, buildTeacherTool, gulp.series(copyTeacherToolCss, copyTeacherToolJs, copyTeacherToolHtml)); +const teacherTool = createWebappTasks("teachertool"); /******************************************************** Webapp build wrappers @@ -680,13 +595,8 @@ const shouldBuildWebapps = () => (process.argv.indexOf("--no-webapps") === -1 && const maybeUpdateWebappStrings = () => { if (!shouldBuildWebapps()) return noop; - return gulp.parallel( - updateSkillMapStrings, - updateAuthcodeStrings, - updateMultiplayerStrings, - updateKioskStrings, - updateTeacherToolStrings, - ); + + return gulp.parallel(...SUB_WEBAPPS.map(app => () => updateWebappStrings(app.name))); }; const maybeBuildWebapps = () => { @@ -863,11 +773,6 @@ exports.watch = initWatch; exports.watchCli = initWatchCli; exports.testlanguageservice = testlanguageservice; exports.onlinelearning = onlinelearning; -exports.skillmap = skillmap; -exports.authcode = authcode; -exports.multiplayer = multiplayer; -exports.kiosk = kiosk; -exports.teacherTool = teacherTool; exports.tt = teacherTool; exports.icons = buildSVGIcons; exports.testhelpers = testhelpers; diff --git a/package.json b/package.json index a0ccc8568bf2..911f09491524 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "built/*.js", "built/**/*.d.ts", "built/pxt-common.json", + "built/webapps-config.json", "built/web/fonts", "built/web/*.js", "built/web/*.css", @@ -34,16 +35,8 @@ "built/web/vs/editor/editor.main.js", "built/web/vs/language/typescript/lib/*.js", "built/web/vs/language/typescript/src/*.js", - "built/web/skillmap/css/*.css", - "built/web/skillmap/js/*.js", - "built/web/authcode/css/*.css", - "built/web/authcode/js/*.js", - "built/web/multiplayer/css/*.css", - "built/web/multiplayer/js/*.js", - "built/web/kiosk/css/*.css", - "built/web/kiosk/js/*.js", - "built/web/teachertool/css/*.css", - "built/web/teachertool/js/*.js", + "built/web/*/css/*.css", + "built/web/*/js/*.js", "pxtcompiler/ext-typescript/lib/lib.d.ts", "pxtcompiler/ext-typescript/lib/typescript.js", "pxtcompiler/ext-typescript/lib/typescriptServices.d.ts", diff --git a/scripts/npm-prepare.js b/scripts/npm-prepare.js index 902f1d16ad53..18f85d0a7869 100644 --- a/scripts/npm-prepare.js +++ b/scripts/npm-prepare.js @@ -1,16 +1,9 @@ const ju = require("../jakeutil"); - -const apps = [ - 'skillmap', - 'authcode', - 'multiplayer', - 'kiosk', - 'teachertool' -]; +const webapps = require("../cli/webapps-config.json").webapps; (async () => { - for (const app of apps) { - console.log(`Installing ${app}...`); - await ju.exec(`cd ${app} && npm install --no-update-notifier && cd ..`, true); + for (const app of webapps) { + console.log(`Installing ${app.name}...`); + await ju.exec(`cd ${app.name} && npm install --no-update-notifier && cd ..`, true); } })();