Skip to content

Commit 3fd5bc9

Browse files
committed
implement a new html-oriented manifest format
This implements a new v5 schema for fastboot. Unlike the previous json-oriented formats, this is an html-oriented format. HTML is better understood by general purpose build tools, which makes it easier to integrate with embroider. It also allows us to eliminate some redundancies -- for example, the app config no longer needs to exist in both package.json and the meta tags, since the HTML oriented format can use it directly from the meta tags. In package.json, the v5 schema supports: - `fastboot.schemaVersion: 5` - `fastboot.moduleWhitelist: []`: unchanged meaning from v4. - `fastboot.htmlEntrypoint: 'index.html'`: the path to your HTML entrypoint file - `name`: note that in the new format, we take the appName directly from the package.json top level. This field is used for nothing else by the time we get to fastboot, so there was no reason for redundancy. The HTML entrypoint file is any valid HTML, plus these fastboot-specific extensions: - `<fastboot-script>` tags work like `<script>` tags, but they will only run in fastboot and be stripped out before serving to browsers. - `<script data-fastboot-ignore></script>` will *not* run in fastboot, and the data attribute will be stripped out before serving to browsers. - `<script src="https://some-cdn.com/app.js" data-fastboot-src="assets/app.js"></script>` tells fastboot the local path to an asset that may have a different public URL for browser consumption. The data-fastboot-src attribute is stripped before serving to browsers. New html-oriented manifest format for embroider implementing data-fastboot-ignore and data-fastboot-src making htmlEntrypoint the new v5 schema And refactoring so we truly hide the differences in schema versions from the rest of the program. schema v5 This makes the htmlEntrypoint format be the official v5 schema.
1 parent 85fe688 commit 3fd5bc9

File tree

12 files changed

+85253
-222
lines changed

12 files changed

+85253
-222
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"chalk": "^3.0.0",
2929
"cookie": "^0.4.0",
3030
"debug": "^4.1.1",
31+
"jsdom": "^16.2.2",
3132
"resolve": "^1.15.0",
3233
"simple-dom": "^1.4.0",
3334
"source-map-support": "^0.5.16"
@@ -42,13 +43,14 @@
4243
"eslint-plugin-node": "^11.0.0",
4344
"eslint-plugin-prettier": "^3.1.2",
4445
"express": "^4.17.1",
46+
"fixturify": "^2.1.0",
4547
"lerna-changelog": "^1.0.0",
4648
"mocha": "^7.0.1",
4749
"prettier": "^1.19.1",
4850
"release-it": "^12.4.3",
4951
"release-it-lerna-changelog": "^2.0.0",
5052
"rimraf": "^3.0.1",
51-
"temp": "^0.9.1"
53+
"tmp": "^0.2.1"
5254
},
5355
"engines": {
5456
"node": "10.* || >=12"

src/ember-app.js

Lines changed: 9 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,14 @@
33
const fs = require('fs');
44
const vm = require('vm');
55
const path = require('path');
6-
const chalk = require('chalk');
7-
86
const SimpleDOM = require('simple-dom');
9-
const resolve = require('resolve');
107
const debug = require('debug')('fastboot:ember-app');
118

129
const Sandbox = require('./sandbox');
1310
const FastBootInfo = require('./fastboot-info');
1411
const Result = require('./result');
15-
const FastBootSchemaVersions = require('./fastboot-schema-versions');
16-
const getPackageName = require('./utils/get-package-name');
12+
const { loadConfig } = require('./fastboot-schema');
13+
1714
const Queue = require('./utils/queue');
1815

1916
/**
@@ -36,13 +33,13 @@ class EmberApp {
3633
this.buildSandboxGlobals = options.buildSandboxGlobals || defaultBuildSandboxGlobals;
3734

3835
let distPath = (this.distPath = path.resolve(options.distPath));
39-
let config = this.readPackageJSON(distPath);
36+
let config = loadConfig(distPath);
4037

41-
this.moduleWhitelist = config.moduleWhitelist;
4238
this.hostWhitelist = config.hostWhitelist;
4339
this.config = config.config;
4440
this.appName = config.appName;
45-
this.schemaVersion = config.schemaVersion;
41+
this.html = config.html;
42+
this.sandboxRequire = config.sandboxRequire;
4643

4744
if (process.env.APP_CONFIG) {
4845
let appConfig = JSON.parse(process.env.APP_CONFIG);
@@ -57,14 +54,10 @@ class EmberApp {
5754
this.config = allConfig;
5855
}
5956

60-
this.html = fs.readFileSync(config.htmlFile, 'utf8');
61-
62-
this.sandboxRequire = this.buildWhitelistedRequire(this.moduleWhitelist, distPath);
63-
let filePaths = [require.resolve('./scripts/install-source-map-support')].concat(
64-
config.vendorFiles,
65-
config.appFiles
66-
);
67-
this.scripts = buildScripts(filePaths);
57+
this.scripts = buildScripts([
58+
require.resolve('./scripts/install-source-map-support'),
59+
...config.scripts,
60+
]);
6861

6962
// default to 1 if maxSandboxQueueSize is not defined so the sandbox is pre-warmed when process comes up
7063
const maxSandboxQueueSize = options.maxSandboxQueueSize || 1;
@@ -129,79 +122,6 @@ class EmberApp {
129122
return new Sandbox(globals);
130123
}
131124

132-
/**
133-
* @private
134-
*
135-
* The Ember app runs inside a sandbox that doesn't have access to the normal
136-
* Node.js environment, including the `require` function. Instead, we provide
137-
* our own `require` method that only allows whitelisted packages to be
138-
* requested.
139-
*
140-
* This method takes an array of whitelisted package names and the path to the
141-
* built Ember app and constructs this "fake" `require` function that gets made
142-
* available globally inside the sandbox.
143-
*
144-
* @param {string[]} whitelist array of whitelisted package names
145-
* @param {string} distPath path to the built Ember app
146-
*/
147-
buildWhitelistedRequire(whitelist, distPath) {
148-
let isLegacyWhitelist = this.schemaVersion < FastBootSchemaVersions.strictWhitelist;
149-
150-
whitelist.forEach(function(whitelistedModule) {
151-
debug('module whitelisted; module=%s', whitelistedModule);
152-
153-
if (isLegacyWhitelist) {
154-
let packageName = getPackageName(whitelistedModule);
155-
156-
if (packageName !== whitelistedModule && whitelist.indexOf(packageName) === -1) {
157-
console.error("Package '" + packageName + "' is required to be in the whitelist.");
158-
}
159-
}
160-
});
161-
162-
return function(moduleName) {
163-
let packageName = getPackageName(moduleName);
164-
let isWhitelisted = whitelist.indexOf(packageName) > -1;
165-
166-
if (isWhitelisted) {
167-
try {
168-
let resolvedModulePath = resolve.sync(moduleName, { basedir: distPath });
169-
return require(resolvedModulePath);
170-
} catch (error) {
171-
if (error.code === 'MODULE_NOT_FOUND') {
172-
return require(moduleName);
173-
} else {
174-
throw error;
175-
}
176-
}
177-
}
178-
179-
if (isLegacyWhitelist) {
180-
if (whitelist.indexOf(moduleName) > -1) {
181-
let nodeModulesPath = path.join(distPath, 'node_modules', moduleName);
182-
183-
if (fs.existsSync(nodeModulesPath)) {
184-
return require(nodeModulesPath);
185-
} else {
186-
return require(moduleName);
187-
}
188-
} else {
189-
throw new Error(
190-
"Unable to require module '" + moduleName + "' because it was not in the whitelist."
191-
);
192-
}
193-
}
194-
195-
throw new Error(
196-
"Unable to require module '" +
197-
moduleName +
198-
"' because its package '" +
199-
packageName +
200-
"' was not in the whitelist."
201-
);
202-
};
203-
}
204-
205125
/**
206126
* Perform any cleanup that is needed
207127
*/
@@ -430,99 +350,6 @@ class EmberApp {
430350

431351
return result;
432352
}
433-
434-
/**
435-
* Given the path to a built Ember app, reads the FastBoot manifest
436-
* information from its `package.json` file.
437-
*/
438-
readPackageJSON(distPath) {
439-
let pkgPath = path.join(distPath, 'package.json');
440-
let file;
441-
442-
try {
443-
file = fs.readFileSync(pkgPath);
444-
} catch (e) {
445-
throw new Error(
446-
`Couldn't find ${pkgPath}. You may need to update your version of ember-cli-fastboot.`
447-
);
448-
}
449-
450-
let manifest;
451-
let schemaVersion;
452-
let pkg;
453-
454-
try {
455-
pkg = JSON.parse(file);
456-
manifest = pkg.fastboot.manifest;
457-
schemaVersion = pkg.fastboot.schemaVersion;
458-
} catch (e) {
459-
throw new Error(
460-
`${pkgPath} was malformed or did not contain a manifest. Ensure that you have a compatible version of ember-cli-fastboot.`
461-
);
462-
}
463-
464-
const currentSchemaVersion = FastBootSchemaVersions.latest;
465-
// set schema version to 1 if not defined
466-
schemaVersion = schemaVersion || FastBootSchemaVersions.base;
467-
debug(
468-
'Current schemaVersion from `ember-cli-fastboot` is %s while latest schema version is %s',
469-
schemaVersion,
470-
currentSchemaVersion
471-
);
472-
if (schemaVersion > currentSchemaVersion) {
473-
let errorMsg = chalk.bold.red(
474-
'An incompatible version between `ember-cli-fastboot` and `fastboot` was found. Please update the version of fastboot library that is compatible with ember-cli-fastboot.'
475-
);
476-
throw new Error(errorMsg);
477-
}
478-
479-
if (schemaVersion < FastBootSchemaVersions.manifestFileArrays) {
480-
// transform app and vendor file to array of files
481-
manifest = this.transformManifestFiles(manifest);
482-
}
483-
484-
let config = pkg.fastboot.config;
485-
let appName = pkg.fastboot.appName;
486-
if (schemaVersion < FastBootSchemaVersions.configExtension) {
487-
// read from the appConfig tree
488-
if (pkg.fastboot.appConfig) {
489-
appName = pkg.fastboot.appConfig.modulePrefix;
490-
config = {};
491-
config[appName] = pkg.fastboot.appConfig;
492-
}
493-
}
494-
495-
debug('reading array of app file paths from manifest');
496-
let appFiles = manifest.appFiles.map(function(appFile) {
497-
return path.join(distPath, appFile);
498-
});
499-
500-
debug('reading array of vendor file paths from manifest');
501-
let vendorFiles = manifest.vendorFiles.map(function(vendorFile) {
502-
return path.join(distPath, vendorFile);
503-
});
504-
505-
return {
506-
appFiles,
507-
vendorFiles,
508-
htmlFile: path.join(distPath, manifest.htmlFile),
509-
moduleWhitelist: pkg.fastboot.moduleWhitelist,
510-
hostWhitelist: pkg.fastboot.hostWhitelist,
511-
config,
512-
appName,
513-
schemaVersion,
514-
};
515-
}
516-
517-
/**
518-
* Function to transform the manifest app and vendor files to an array.
519-
*/
520-
transformManifestFiles(manifest) {
521-
manifest.appFiles = [manifest.appFile];
522-
manifest.vendorFiles = [manifest.vendorFile];
523-
524-
return manifest;
525-
}
526353
}
527354

528355
/*

src/fastboot-schema-versions.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)