UNPKG

fuse-box

Version:

Fuse-Box a bundler that does it right

319 lines (258 loc) • 10.9 kB
import * as path from "path"; import { each } from "realm-utils"; import { FuseBox, FuseBoxOptions } from "../../core/FuseBox"; import * as fs from "fs"; import * as appRoot from "app-root-path"; import { removeFolder } from "../../Utils"; import * as fsExtra from "fs-extra"; import { QuantumPlugin } from "../../index"; const jsdom = require("jsdom"); export class TestFolder { folder: string; constructor(public customName?: string) { } public make() { this.folder = path.join(appRoot.path, ".fusebox", "tests", this.customName ? this.customName : new Date().getTime().toString()); fsExtra.ensureDirSync(this.folder); } public shouldFindFile(file: string) { let target = path.join(this.folder, file); if (!fs.existsSync(target)) { throw new Error(`Expected to find file ${target}`) } return target; } public readFile(file: string): string { let target = this.shouldFindFile(file); return fs.readFileSync(target).toString(); } public writeFile(file: string, contents: string): void { let target = this.shouldFindFile(file); fs.writeFileSync(target, contents) } public clean() { removeFolder(this.folder); } } export function getStubsFolder() { return path.join(appRoot.path, "src/tests/stubs"); } export function createOptimisedBundleEnv(opts: any) { const name = opts.name || `test-${new Date().getTime()}`; let tmpFolder = path.join(appRoot.path, ".fusebox", "tests", name); const optimisedBundleOpts = opts.options || {} fsExtra.ensureDirSync(tmpFolder); let localPath = path.join(tmpFolder, name); const output: any = { modules: {}, }; const scripts = []; let modulesFolder = path.join(localPath, "modules"); if (opts.stubs) { modulesFolder = path.join(appRoot.path, "src/tests/stubs/test_modules"); } // creating modules return each(opts.modules, (moduleParams, name) => { return new Promise((resolve, reject) => { moduleParams.output = path.join(modulesFolder, name, "index.js"); moduleParams.package = name; moduleParams.cache = false; moduleParams.log = moduleParams.log || false; moduleParams.tsConfig = path.join(appRoot.path, "src/tests/fixtures", "tsconfig.json"); const fuse = FuseBox.init(moduleParams); fuse.bundle("index.js").cache(false).instructions(moduleParams.instructions); return fuse.run().then(bundle => { if (moduleParams.onDone) { moduleParams.onDone({ localPath, filePath: moduleParams.output, projectDir: path.join(localPath, "project"), }); } scripts.push(moduleParams.output); return resolve(); }).catch(reject); }); }).then(() => { const projectOptions = opts.project; projectOptions.output = path.join(localPath, "project", "index.js"); projectOptions.cache = false; projectOptions.log = projectOptions.log || false; projectOptions.tsConfig = path.join(appRoot.path, "src/tests/fixtures", "tsconfig.json"); projectOptions.modulesFolder = modulesFolder; projectOptions.plugins = projectOptions.plugins || []; projectOptions.plugins.push(QuantumPlugin(optimisedBundleOpts)) const fuse = FuseBox.init(projectOptions); fuse.bundle("index.js").cache(false).log(false).instructions(projectOptions.instructions) return fuse.run().then(producer => { const contents = {}; const bundles = producer.sortBundles(); bundles.forEach(bundle => { contents[bundle.name] = bundle.generatedCode.toString() scripts.push(bundle.context.output.lastPrimaryOutput.path) }); return new Promise((resolve, reject) => { if (optimisedBundleOpts && optimisedBundleOpts.target === "server") { let results = [] scripts.forEach(script => { results.push(require(script)); }); output.bundles = results; return resolve(output); } else { jsdom.env({ html: "<html><head></head><body></body></html>", scripts: scripts, virtualConsole: jsdom.createVirtualConsole().sendTo(console), done: function (err, window) { if (err) { return reject(err); } output.contents = contents; output.window = window return resolve(output); } }); } }); }); }).then(() => { setTimeout(() => { removeFolder(localPath); }, 5); return output; }); } export function createEnv(opts: any) { const name = opts.name || `test-${new Date().getTime()}`; let tmpFolder = path.join(appRoot.path, ".fusebox", "tests", name); const serverOnly = opts.server === true; fsExtra.ensureDirSync(tmpFolder); let localPath = path.join(tmpFolder, name); const output: any = { modules: {}, }; const scripts = []; const modulesFolder = path.join(localPath, "modules"); // creating modules return each(opts.modules, (moduleParams, name) => { return new Promise((resolve, reject) => { moduleParams.output = path.join(modulesFolder, name, "index.js"); moduleParams.package = name; moduleParams.cache = false; moduleParams.log = false; moduleParams.tsConfig = path.join(appRoot.path, "src/tests/fixtures", "tsconfig.json"); const fuse = FuseBox.init(moduleParams); fuse.bundle("index.js").cache(false).instructions(moduleParams.instructions); return fuse.run().then(bundle => { if (moduleParams.onDone) { moduleParams.onDone({ localPath, filePath: moduleParams.output, projectDir: path.join(localPath, "project"), }); } if (serverOnly) { output.modules[name] = require(moduleParams.output); } else { scripts.push(moduleParams.output); } return resolve(); }).catch(reject); }); }).then(() => { const projectOptions = opts.project; projectOptions.output = path.join(localPath, "project", "index.js"); projectOptions.cache = false; projectOptions.log = false; projectOptions.tsConfig = path.join(appRoot.path, "src/tests/fixtures", "tsconfig.json"); projectOptions.modulesFolder = modulesFolder; const fuse = FuseBox.init(projectOptions); fuse.bundle("index.js").cache(false).log(false).instructions(projectOptions.instructions) return fuse.run().then(producer => { if (producer.bundles) { producer.bundles.forEach(bundle => { projectOptions.output = bundle.context.output.lastPrimaryOutput.path }) } let contents = fs.readFileSync(projectOptions.output); const length = contents.buffer.byteLength; output.projectContents = contents; output.dist = path.dirname(projectOptions.output) output.projectSize = length; output.shouldExistInDist = (name) => { let target = path.join(output.dist, name); if (!fs.existsSync(target)) { throw new Error(`Expected to find ${name} in dist!`); } } if (serverOnly) { output.project = require(projectOptions.output); } else { scripts.push(projectOptions.output); return new Promise((resolve, reject) => { jsdom.env({ html: "<html><head></head><body></body></html>", scripts: scripts, done: function (err, window) { if (err) { return reject(err); } output.project = window; output.projectSize = length; output.querySelector = window.document.querySelector output.querySelectorAll = window.document.querySelectorAll; output.projectContents = contents; return resolve(output); } }); }); } }); }).then(() => { setTimeout(() => { removeFolder(localPath); }, 5); return output; }); } export class TestingFuseBox extends FuseBox { constructor(opts: FuseBoxOptions, public tmpFolder: string) { super(opts); } public runAndLoad(modules: string[], callback: (any, string) => any) { // todo: move cleanup to afterAll const cleanup = (result) => { setTimeout(() => { removeFolder(this.tmpFolder); }, 15); return result; }; return this.run().then(producer => { return modules.reduce((acc, m) => { const bundle = producer.bundles.get(m); if (!bundle) { throw new Error(`Module ${m} not found`); } acc[m] = require(bundle.context.output.lastPrimaryOutput.path); return acc; }, {}); }) .then(loaded => callback(loaded, path.dirname(this.opts.output)) || loaded) .then(cleanup, (e) => { throw cleanup(e); }); } } export function createFuseBox(opts: any): TestingFuseBox { const name = opts.name || `test-${new Date().getTime()}`; let tmpFolder = path.join(appRoot.path, ".fusebox", "tests", name); fsExtra.ensureDirSync(tmpFolder); const defaultProjectOptions = { output: path.join(tmpFolder, "dist", "$name.js"), cache: false, log: false, tsConfig: path.join(appRoot.path, "src/tests/fixtures", "tsconfig.json") }; const projectOptions = Object.assign({}, defaultProjectOptions, opts); return new TestingFuseBox(projectOptions, tmpFolder); }