Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow customizing order of bify transforms/plugins #13483

Closed
wants to merge 7 commits into from
245 changes: 154 additions & 91 deletions development/build/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,13 @@ function createFactoredBuild({
}) {
return async function () {
// create bundler setup and apply defaults
const buildConfiguration = createBuildConfiguration();
buildConfiguration.label = 'primary';
const { bundlerOpts, events } = buildConfiguration;
const buildConfiguration = createBuildConfiguration({ label: 'primary' });
const {
addDirectOptions,
addEntry,
addPlugin,
mcmire marked this conversation as resolved.
Show resolved Hide resolved
events,
} = buildConfiguration;

// devMode options
const reloadOnChange = Boolean(devMode);
Expand All @@ -369,7 +373,7 @@ function createFactoredBuild({
});

// set bundle entries
bundlerOpts.entries = [...entryFiles];
addEntry(...entryFiles);

// setup lavamoat
// lavamoat will add lavapack but it will be removed by bify-module-groups
Expand All @@ -386,13 +390,13 @@ function createFactoredBuild({
),
writeAutoPolicy: process.env.WRITE_AUTO_POLICY,
};
Object.assign(bundlerOpts, lavamoatBrowserify.args);
bundlerOpts.plugin.push([lavamoatBrowserify, lavamoatOpts]);
addDirectOptions(lavamoatBrowserify.args);
addPlugin(lavamoatBrowserify, lavamoatOpts);

// setup bundle factoring with bify-module-groups plugin
// note: this will remove lavapack, but its ok bc we manually readd it later
Object.assign(bundlerOpts, bifyModuleGroups.plugin.args);
bundlerOpts.plugin = [...bundlerOpts.plugin, [bifyModuleGroups.plugin]];
addDirectOptions(bifyModuleGroups.plugin.args);
addPlugin(bifyModuleGroups.plugin);

// instrument pipeline
let sizeGroupMap;
Expand Down Expand Up @@ -527,9 +531,8 @@ function createNormalBundle({
}) {
return async function () {
// create bundler setup and apply defaults
const buildConfiguration = createBuildConfiguration();
buildConfiguration.label = label;
const { bundlerOpts, events } = buildConfiguration;
const buildConfiguration = createBuildConfiguration({ label });
const { addEntry, addRequire, events } = buildConfiguration;

// devMode options
const reloadOnChange = Boolean(devMode);
Expand All @@ -549,13 +552,13 @@ function createNormalBundle({
});

// set bundle entries
bundlerOpts.entries = [...extraEntries];
addEntry(...extraEntries);
if (entryFilepath) {
bundlerOpts.entries.push(entryFilepath);
addEntry(entryFilepath);
}

if (modulesToExpose) {
bundlerOpts.require = bundlerOpts.require.concat(modulesToExpose);
addRequire(...modulesToExpose);
}

// instrument pipeline
Expand All @@ -576,19 +579,86 @@ function createNormalBundle({
};
}

function createBuildConfiguration() {
const label = '(unnamed bundle)';
function createBuildConfiguration({ label = '(unnamed bundle)' } = {}) {
const directOptions = {};
const entries = [];
const requires = [];
const externals = [];
const ignores = [];
const excludes = [];
const transformsAndPlugins = [];
const events = new EventEmitter();
const bundlerOpts = {
entries: [],
transform: [],
plugin: [],
require: [],
// non-standard bify options
manualExternal: [],
manualIgnore: [],

const addDirectOptions = (options) => {
for (const [key, value] of Object.entries(options)) {
directOptions[key] = value;
}
};

const addEntry = (...givenEntries) => {
entries.push(...givenEntries);
};

const addRequire = (...givenRequires) => {
requires.push(...givenRequires);
};

const addExternal = (...givenExternals) => {
externals.push(...givenExternals);
};

const addIgnore = (...givenIgnores) => {
ignores.push(...givenIgnores);
};

const addExclude = (...givenExcludes) => {
excludes.push(...givenExcludes);
};

const addTransform = (transform, transformOptions = {}) => {
transformsAndPlugins.push({
type: 'transform',
value: transform,
options: transformOptions,
});
};

const addPlugin = (plugin, pluginOptions = {}) => {
transformsAndPlugins.push({
type: 'plugin',
value: plugin,
options: pluginOptions,
});
};

const buildBundler = () => {
const bundler = browserify(directOptions);
entries.forEach((entry) => bundler.add(entry));
externals.forEach((external) => bundler.external(external));
ignores.forEach((ignore) => bundler.ignore(ignore));
excludes.forEach((exclude) => bundler.exclude(exclude));
transformsAndPlugins.forEach((transformOrPlugin) => {
bundler[transformOrPlugin.type](
transformOrPlugin.value,
transformOrPlugin.options,
);
});
return bundler;
};

return {
label,
addDirectOptions,
addEntry,
addRequire,
addExternal,
addIgnore,
addExclude,
addTransform,
addPlugin,
buildBundler,
events,
};
return { bundlerOpts, events, label };
}

function setupBundlerDefaults(
Expand All @@ -605,18 +675,23 @@ function setupBundlerDefaults(
testing,
},
) {
const { bundlerOpts } = buildConfiguration;

Object.assign(bundlerOpts, {
// Source transforms
transform: [
// Remove code that should be excluded from builds of the current type
createRemoveFencedCodeTransform(buildType, shouldLintFenceFiles),
// Transpile top-level code
babelify,
// Inline `fs.readFileSync` files
brfs,
],
const {
addDirectOptions,
addIgnore,
addExclude,
addTransform,
} = buildConfiguration;

// Remove code that should be excluded from builds of the current type
addTransform(
createRemoveFencedCodeTransform(buildType, shouldLintFenceFiles),
);
// Transpile top-level code
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where tsify will go. According to the documentation, it needs to go before babelify.

addTransform(babelify);
// Inline `fs.readFileSync` files
addTransform(brfs);

addDirectOptions({
// Use entryFilepath for moduleIds, easier to determine origin file
fullPaths: devMode,
// For sourcemaps
Expand All @@ -625,18 +700,17 @@ function setupBundlerDefaults(

// Ensure react-devtools are not included in non-dev builds
if (!devMode || testing) {
bundlerOpts.manualIgnore.push('react-devtools');
bundlerOpts.manualIgnore.push('remote-redux-devtools');
addIgnore('react-devtools', 'remote-redux-devtools');
}

// Inject environment variables via node-style `process.env`
if (envVars) {
bundlerOpts.transform.push([envify(envVars), { global: true }]);
addTransform(envify(envVars), { global: true });
}

// Ensure that any files that should be ignored are excluded from the build
if (ignoredFiles) {
bundlerOpts.manualExclude = ignoredFiles;
addExclude(...ignoredFiles);
}

// Setup reload on change
Expand All @@ -654,10 +728,10 @@ function setupBundlerDefaults(
}
}

function setupReloadOnChange({ bundlerOpts, events }) {
function setupReloadOnChange({ addPlugin, addDirectOptions, events }) {
// Add plugin to options
Object.assign(bundlerOpts, {
plugin: [...bundlerOpts.plugin, watchify],
addPlugin(watchify);
addDirectOptions({
// Required by watchify
cache: {},
packageCache: {},
Expand All @@ -672,13 +746,12 @@ function setupReloadOnChange({ bundlerOpts, events }) {
});
}

function setupMinification(buildConfiguration) {
function setupMinification({ events }) {
const minifyOpts = {
mangle: {
reserved: ['MetamaskInpageProvider'],
},
};
const { events } = buildConfiguration;
events.on('configurePipeline', ({ pipeline }) => {
pipeline.get('minify').push(
// this is the "gulp-terser-js" wrapper around the latest version of terser
Expand All @@ -704,8 +777,7 @@ function setupMinification(buildConfiguration) {
});
}

function setupSourcemaps(buildConfiguration, { devMode }) {
const { events } = buildConfiguration;
function setupSourcemaps({ events }, { devMode }) {
events.on('configurePipeline', ({ pipeline }) => {
pipeline.get('sourcemaps:init').push(sourcemaps.init({ loadMaps: true }));
pipeline
Expand All @@ -721,56 +793,47 @@ function setupSourcemaps(buildConfiguration, { devMode }) {
}

async function bundleIt(buildConfiguration) {
const { label, bundlerOpts, events } = buildConfiguration;
const bundler = browserify(bundlerOpts);

// manually apply non-standard options
bundler.external(bundlerOpts.manualExternal);
bundler.ignore(bundlerOpts.manualIgnore);
if (Array.isArray(bundlerOpts.manualExclude)) {
bundler.exclude(bundlerOpts.manualExclude);
}

const { label, buildBundler, events } = buildConfiguration;
const bundler = buildBundler();
// output build logs to terminal
bundler.on('log', log);

// forward update event (used by watchify)
bundler.on('update', () => performBundle());
bundler.on('update', () => performBundle({ bundler, events }));

console.log(`Bundle start: "${label}"`);
await performBundle();
await performBundle({ bundler, events });
console.log(`Bundle end: "${label}"`);
}

async function performBundle() {
// this pipeline is created for every bundle
// the labels are all the steps you can hook into
const pipeline = labeledStreamSplicer([
'groups',
[],
'vinyl',
[],
'sourcemaps:init',
[],
'minify',
[],
'sourcemaps:write',
[],
'dest',
[],
]);
const bundleStream = bundler.bundle();
// trigger build pipeline instrumentations
events.emit('configurePipeline', { pipeline, bundleStream });
// start bundle, send into pipeline
bundleStream.pipe(pipeline);
// nothing will consume pipeline, so let it flow
pipeline.resume();

await endOfStream(pipeline);

// call the completion event to handle any post-processing
events.emit('bundleDone');
}
async function performBundle({ bundler, events }) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see a real reason this was nested within bundleIt, and considering most of bundleIt is this function anyway, I pulled it out.

// this pipeline is created for every bundle
// the labels are all the steps you can hook into
const pipeline = labeledStreamSplicer([
'groups',
[],
'vinyl',
[],
'sourcemaps:init',
[],
'minify',
[],
'sourcemaps:write',
[],
'dest',
[],
]);
const bundleStream = bundler.bundle();
// trigger build pipeline instrumentations
events.emit('configurePipeline', { pipeline, bundleStream });
// start bundle, send into pipeline
bundleStream.pipe(pipeline);
// nothing will consume pipeline, so let it flow
pipeline.resume();

await endOfStream(pipeline);

// call the completion event to handle any post-processing
events.emit('bundleDone');
}

function getEnvironmentVariables({ buildType, devMode, testing }) {
Expand Down