build(bazel): generate aio stackblitz and example zips

Can be served by running bazel run //aio:serve
This commit is contained in:
Derek Cormier
2022-04-05 12:59:52 -07:00
committed by Joey Perrott
parent 655427f9b8
commit 9cb9161876
12 changed files with 245 additions and 104 deletions
+19
View File
@@ -0,0 +1,19 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
package(default_visibility = ["//visibility:public"])
nodejs_binary(
name = "generate-example-zips",
data = [
"exampleZipper.mjs",
"//aio/tools/transforms",
"@aio_npm//archiver",
"@aio_npm//canonical-path",
"@aio_npm//fs-extra",
"@aio_npm//globby",
],
entry_point = "generateZips.mjs",
# --preserve-symlinks-main is not enabled by default (see https://github.com/bazelbuild/rules_nodejs/pull/2176)
# However it seems to be required for mjs entry points to resolve node_modules within the sandbox.
templated_args = ["--node_options=--preserve-symlinks-main"],
)
+10 -2
View File
@@ -19,7 +19,11 @@ export class ExampleZipper {
let gpathStackblitz = path.join(sourceDirName, '**/*stackblitz.json');
let gpathZipper = path.join(sourceDirName, '**/zipper.json');
let configFileNames = globbySync([gpathStackblitz, gpathZipper], { ignore: ['**/node_modules/**'] });
let configFileNames = globbySync([gpathStackblitz, gpathZipper], {
ignore: ['**/node_modules/**'],
dot: true // Include subpaths that begin with '.' when using a wildcard inclusion.
// Needed to include the bazel .cache folder on Linux.
});
configFileNames.forEach((configFileName) => {
this._zipExample(configFileName, sourceDirName, outputDirName);
});
@@ -152,7 +156,11 @@ export class ExampleZipper {
gpaths.push(...alwaysExcludes);
let fileNames = globbySync(gpaths, { ignore: ['**/node_modules/**'] });
let fileNames = globbySync(gpaths, {
ignore: ['**/node_modules/**'],
dot: true // Include subpaths that begin with '.' when using a wildcard inclusion.
// Needed to include the bazel .cache folder on Linux.
});
let zip = this._createZipArchive(outputFileName);
fileNames.forEach((fileName) => {
+9 -4
View File
@@ -1,9 +1,14 @@
import path from 'canonical-path';
import {fileURLToPath} from 'url';
import {ExampleZipper} from './exampleZipper.mjs';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const EXAMPLES_PATH = path.join(__dirname, '../../content/examples');
const ZIPS_PATH = path.join(__dirname, '../../src/generated/zips');
const argv = process.argv.slice(2);
if (argv.length !== 2) {
console.error("Usage: node generateZips.mjs [examples-path] [output-path]");
process.exit(1);
}
const EXAMPLES_PATH = argv[0];
const OUTPUT_PATH = argv[1];
const ZIPS_PATH = path.join(OUTPUT_PATH, 'generated', 'zips');
new ExampleZipper(EXAMPLES_PATH, ZIPS_PATH);
+17
View File
@@ -0,0 +1,17 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
package(default_visibility = ["//visibility:public"])
nodejs_binary(
name = "example-boilerplate",
data = [
"constants.js",
"//aio/content/examples",
"@aio_npm//canonical-path",
"@aio_npm//fs-extra",
"@aio_npm//ignore",
"@aio_npm//shelljs",
"@aio_npm//yargs",
] + glob(["shared/**"]),
entry_point = "example-boilerplate.js",
)
+1
View File
@@ -4,3 +4,4 @@ exports.EXAMPLES_BASE_PATH = path.resolve(__dirname, '../../content/examples');
exports.EXAMPLE_CONFIG_FILENAME = 'example-config.json';
exports.SHARED_PATH = path.resolve(__dirname, 'shared');
exports.STACKBLITZ_CONFIG_FILENAME = 'stackblitz.json';
exports.BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH = process.env.BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH;
+21 -13
View File
@@ -4,7 +4,7 @@ const ignore = require('ignore');
const path = require('canonical-path');
const shelljs = require('shelljs');
const yargs = require('yargs');
const {EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, SHARED_PATH} = require('./constants');
const {EXAMPLES_BASE_PATH, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, EXAMPLE_CONFIG_FILENAME, SHARED_PATH} = require('./constants');
const SHARED_NODE_MODULES_PATH = path.resolve(SHARED_PATH, 'node_modules');
@@ -22,13 +22,16 @@ class ExampleBoilerPlate {
this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules');
const gitignore = ignore().add(fs.readFileSync(path.resolve(BOILERPLATE_BASE_PATH, '.gitignore'), 'utf8'));
if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) {
throw new Error(
`The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` +
'Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?');
}
shelljs.exec(`yarn --cwd ${SHARED_PATH} ngcc --properties es2015 main`);
// TODO(bazel): Comment this out until example tests are run with bazel. The node_modules folder isn't
// needed to build the examples.
//
// if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) {
// throw new Error(
// `The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` +
// 'Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?');
// }
//
// shelljs.exec(`yarn --cwd ${SHARED_PATH} ngcc --properties es2015 main`);
exampleFolders.forEach(exampleFolder => {
const exampleConfig = this.loadJsonFile(path.resolve(exampleFolder, EXAMPLE_CONFIG_FILENAME));
@@ -43,26 +46,31 @@ class ExampleBoilerPlate {
);
const isPathIgnored = absolutePath => boilerplateIgnore.ignores(path.relative(BOILERPLATE_BASE_PATH, absolutePath));
// TODO(bazel): Comment this out until example tests are being run with bazel. The node_modules folder isn't
// needed to build the examples.
//
// Link the node modules - requires admin access (on Windows) because it adds symlinks
const destinationNodeModules = path.resolve(exampleFolder, 'node_modules');
fs.ensureSymlinkSync(SHARED_NODE_MODULES_PATH, destinationNodeModules);
// const destinationNodeModules = path.resolve(exampleFolder, 'node_modules');
// fs.ensureSymlinkSync(SHARED_NODE_MODULES_PATH, destinationNodeModules);
const boilerPlateType = exampleConfig.projectType || 'cli';
const boilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, boilerPlateType);
const outputPath = path.join(BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, path.basename(exampleFolder));
shelljs.mkdir('-p', outputPath);
// All example types other than `cli` and `systemjs` are based on `cli`. Copy over the `cli`
// boilerplate files first.
// (Some of these files might be later overwritten by type-specific files.)
if (boilerPlateType !== 'cli' && boilerPlateType !== 'systemjs') {
this.copyDirectoryContents(BOILERPLATE_CLI_PATH, exampleFolder, isPathIgnored);
this.copyDirectoryContents(BOILERPLATE_CLI_PATH, outputPath, isPathIgnored);
}
// Copy the type-specific boilerplate files.
this.copyDirectoryContents(boilerPlateBasePath, exampleFolder, isPathIgnored);
this.copyDirectoryContents(boilerPlateBasePath, outputPath, isPathIgnored);
// Copy the common boilerplate files (unless explicitly not used).
if (exampleConfig.useCommonBoilerplate !== false) {
this.copyDirectoryContents(BOILERPLATE_COMMON_PATH, exampleFolder, isPathIgnored);
this.copyDirectoryContents(BOILERPLATE_COMMON_PATH, outputPath, isPathIgnored);
}
});
}
+19
View File
@@ -0,0 +1,19 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
package(default_visibility = ["//visibility:public"])
nodejs_binary(
name = "generate-stackblitz",
data = [
"builder.mjs",
"//aio/tools/transforms",
"@aio_npm//canonical-path",
"@aio_npm//fs-extra",
"@aio_npm//globby",
"@aio_npm//jsdom",
],
entry_point = "generateStackblitz.mjs",
# --preserve-symlinks-main is not enabled by default (see https://github.com/bazelbuild/rules_nodejs/pull/2176)
# However it seems to be required for mjs entry points to resolve node_modules within the sandbox.
templated_args = ["--node_options=--preserve-symlinks-main"],
)
+24 -35
View File
@@ -3,17 +3,13 @@ import path from 'canonical-path';
import fs from 'fs-extra';
import {globbySync} from 'globby';
import jsdom from 'jsdom';
import {fileURLToPath} from 'url';
import regionExtractor from '../transforms/examples-package/services/region-parser.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export class StackblitzBuilder {
constructor(basePath, destPath) {
this.basePath = basePath;
this.destPath = destPath;
this.copyrights = this._buildCopyrightStrings();
this._boilerplatePackageJsons = {};
}
@@ -24,7 +20,10 @@ export class StackblitzBuilder {
// When testing it sometimes helps to look a just one example directory like so:
// const stackblitzPaths = path.join(this.basePath, '**/testing/*stackblitz.json');
const stackblitzPaths = path.join(this.basePath, '**/*stackblitz.json');
const fileNames = globbySync(stackblitzPaths, { ignore: ['**/node_modules/**'] });
const fileNames = globbySync(stackblitzPaths, { ignore: ['**/node_modules/**'],
dot: true // Include subpaths that begin with '.' when using a wildcard inclusion.
// Needed to include the bazel .cache folder on Linux.
});
let failed = false;
fileNames.forEach((configFileName) => {
try {
@@ -79,42 +78,28 @@ export class StackblitzBuilder {
// main: string - name of file that will become index.html in the stackblitz - defaults to index.html
// file: string - name of file to display within the stackblitz (e.g. `"file": "app/app.module.ts"`)
_buildStackblitzFrom(configFileName) {
// replace ending 'stackblitz.json' with 'stackblitz.no-link.html' to create output file name;
const outputFileName = configFileName.replace(/stackblitz\.json$/, 'stackblitz.no-link.html');
let altFileName;
if (this.destPath && this.destPath.length > 0) {
const partPath = path.dirname(path.relative(this.basePath, outputFileName));
altFileName = path.join(this.destPath, partPath, path.basename(outputFileName)).replace('.no-link.', '.');
}
try {
const config = this._initConfigAndCollectFileNames(configFileName);
const postData = this._createPostData(config, configFileName);
// replace ending 'stackblitz.json' with 'stackblitz.html' to create output file name;
const outputFileName = configFileName.replace(/stackblitz\.json$/, 'stackblitz.html');
const partPath = path.dirname(path.relative(this.basePath, outputFileName));
const outputFilePath = path.join(this.destPath, partPath, path.basename(outputFileName));
const config = this._initConfigAndCollectFileNames(configFileName);
const postData = this._createPostData(config, configFileName);
this._addStackblitzrc(postData);
this._addStackblitzrc(postData);
const html = this._createStackblitzHtml(config, postData);
fs.writeFileSync(outputFileName, html, 'utf-8');
if (altFileName) {
const altDirName = path.dirname(altFileName);
fs.ensureDirSync(altDirName);
fs.writeFileSync(altFileName, html, 'utf-8');
}
} catch (e) {
// if we fail delete the outputFile if it exists because it is an old one.
if (fs.existsSync(outputFileName)) {
fs.unlinkSync(outputFileName);
}
if (altFileName && fs.existsSync(altFileName)) {
fs.unlinkSync(altFileName);
}
throw e;
}
const html = this._createStackblitzHtml(config, postData);
const outputDirName = path.dirname(outputFilePath);
fs.ensureDirSync(outputDirName);
fs.writeFileSync(outputFilePath, html, 'utf-8');
}
_checkForOutdatedConfig() {
// Ensure that nobody is trying to use the old config filenames (i.e. `plnkr.json`).
const plunkerPaths = path.join(this.basePath, '**/*plnkr.json');
const fileNames = globbySync(plunkerPaths, { ignore: ['**/node_modules/**'] });
const fileNames = globbySync(plunkerPaths, { ignore: ['**/node_modules/**'],
dot: true // Include subpaths that begin with '.' when using a wildcard inclusion.
// Needed to include the bazel .cache folder on Linux.
});
if (fileNames.length) {
const readmePath = path.join(__dirname, 'README.md');
@@ -309,7 +294,11 @@ export class StackblitzBuilder {
gpaths.push(...defaultExcludes);
config.fileNames = globbySync(gpaths, { ignore: ['**/node_modules/**'] });
config.fileNames = globbySync(gpaths, {
ignore: ['**/node_modules/**'],
dot: true // Include subpaths that begin with '.' when using a wildcard inclusion.
// Needed to include the bazel .cache folder on Linux.
});
return config;
}
@@ -1,9 +1,14 @@
import {dirname, join} from 'path';
import {fileURLToPath} from 'url';
import {join} from 'path';
import {StackblitzBuilder} from './builder.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const EXAMPLES_PATH = join(__dirname, '../../content/examples');
const LIVE_EXAMPLES_PATH = join(__dirname, '../../src/generated/live-examples');
const argv = process.argv.slice(2);
if (argv.length !== 2) {
console.error("Usage: node generateStackblitz.mjs [examples-path] [output-path]");
process.exit(1);
}
const EXAMPLES_PATH = argv[0];
const OUTPUT_PATH = argv[1];
const LIVE_EXAMPLES_PATH = join(OUTPUT_PATH, 'generated', 'live-examples');
new StackblitzBuilder(EXAMPLES_PATH, LIVE_EXAMPLES_PATH).build();