Skip to content

Commit

Permalink
fix: Fix rollup builds and externals.
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Oct 8, 2020
1 parent a251722 commit 9d74d94
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 100 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ logs/
# Directories
coverage/
build/
cjs/
dist/
esm/
lib/
mjs/
tmp/
node_modules/

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"@boost/event": "^2.1.1",
"@boost/pipeline": "^2.1.2",
"@rollup/plugin-babel": "^5.2.1",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-commonjs": "^15.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"babel-plugin-transform-dev": "^2.0.1",
"builtin-modules": "^3.1.0",
Expand Down
6 changes: 3 additions & 3 deletions src/Packemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Event } from '@boost/event';
import { PooledPipeline, Context } from '@boost/pipeline';
import spdxLicenses from 'spdx-license-list';
import { rollup } from 'rollup';
import getRollupConfig from './configs/rollup';
import { getRollupConfig } from './configs/rollup';
import Build from './Build';
import {
PackemonPackage,
Expand Down Expand Up @@ -127,9 +127,9 @@ export default class Packemon extends Contract<PackemonOptions> {

build.status = 'passed';
} catch (error) {
console.error(`Failed to build package "${build.package.name}": ${error.message}`);

build.status = 'failed';

throw error;
}

build.result?.output.push({
Expand Down
43 changes: 13 additions & 30 deletions src/components/BuildPhase/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ export interface BuildPhaseProps {

export default function BuildPhase({ builds, packemon, onBuilt }: BuildPhaseProps) {
const [errors, setErrors] = useState<Error[]>([]);
const [finishedBuilds, setFinishedBuilds] = useState<Build[]>([]);
const [pendingBuilds, setPendingBuilds] = useState<Build[]>(builds);
const [runningBuilds, setRunningBuilds] = useState<Build[]>([]);

// Start building packages on mount
useEffect(() => {
Expand All @@ -29,34 +26,20 @@ export default function BuildPhase({ builds, packemon, onBuilt }: BuildPhaseProp
});
}, [packemon, builds, onBuilt]);

// Update build list states
useEffect(() => {
const sortBuilds = (buildList: Build[]) => {
const finished: Build[] = [];
const pending: Build[] = [];
const running: Build[] = [];

buildList.forEach((build) => {
if (build.status === 'passed' || build.status === 'failed' || build.status === 'skipped') {
finished.push(build);
} else if (build.status === 'building') {
running.push(build);
} else {
pending.push(build);
}
});

setFinishedBuilds(finished);
setPendingBuilds(pending);
setRunningBuilds(running);
};

packemon.onBuildProgress.listen(sortBuilds);
// Update and sort build list states
const finishedBuilds: Build[] = [];
const pendingBuilds: Build[] = [];
const runningBuilds: Build[] = [];

return () => {
packemon.onBuildProgress.unlisten(sortBuilds);
};
}, [packemon]);
builds.forEach((build) => {
if (build.status === 'passed' || build.status === 'failed' || build.status === 'skipped') {
finishedBuilds.push(build);
} else if (build.status === 'building') {
runningBuilds.push(build);
} else {
pendingBuilds.push(build);
}
});

// Bubble up errors to the main application
if (errors.length > 0) {
Expand Down
96 changes: 57 additions & 39 deletions src/configs/babel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,37 @@ function getPlatformEnvOptions(
}
}

export default function getBabelConfig(
function getSharedConfig(
plugins: PluginItem[],
presets: PluginItem[],
features: FeatureFlags,
): ConfigStructure {
return {
caller: {
name: 'packemon',
},
comments: false,
plugins,
presets,
// Do NOT load root `babel.config.js` as we need full control
configFile: false,
// Do load branch `.babelrc.js` files for granular customization
babelrc: true,
babelrcRoots: features.workspaces,
// Disable source maps
sourceMaps: false,
};
}

// The input config should only parse special syntax, not transform and downlevel.
// This applies to all formats within a build target.
export function getBabelInputConfig(
build: Build,
buildUnit: BuildUnit | null,
features: FeatureFlags,
): Omit<ConfigStructure, 'include' | 'exclude'> {
const plugins: PluginItem[] = [];
const presets: PluginItem[] = [];

// ENVIRONMENT

// This must be determined first before we add other presets or plugins
if (buildUnit) {
const { format, platform, target } = buildUnit;
const envOptions: PresetEnvOptions = {
// Prefer spec compliance over speed
spec: true,
loose: false,
// Consumers must polyfill accordingly
useBuiltIns: false,
// Transform features accordingly
bugfixes: true,
shippedProposals: true,
// Platform specific
...getPlatformEnvOptions(platform, target, format),
};

presets.push(['@babel/preset-env', envOptions]);
}

// PRESETS

if (features.flow) {
presets.push(['@babel/preset-flow', { allowDeclareFields: true }]);
}
Expand Down Expand Up @@ -119,11 +119,41 @@ export default function getBabelConfig(
]);
}

return getSharedConfig(plugins, presets, features);
}

// The output config does all the transformation and downleveling through the preset-env.
// This is handled per output since we need to configure based on target + format combinations.
export function getBabelOutputConfig(
buildUnit: BuildUnit,
features: FeatureFlags,
): ConfigStructure {
const plugins: PluginItem[] = [];
const presets: PluginItem[] = [];

// ENVIRONMENT

const { format, platform, target } = buildUnit;
const envOptions: PresetEnvOptions = {
// Prefer spec compliance over speed
spec: true,
loose: false,
// Consumers must polyfill accordingly
useBuiltIns: false,
// Transform features accordingly
bugfixes: true,
shippedProposals: true,
// Platform specific
...getPlatformEnvOptions(platform, target, format),
};

presets.push(['@babel/preset-env', envOptions]);

// PLUGINS

// Use `Object.assign` when available
// https://babeljs.io/docs/en/babel-plugin-transform-destructuring#usebuiltins
if (buildUnit?.target !== 'legacy') {
if (buildUnit.target !== 'legacy') {
plugins.push(
['@babel/plugin-transform-destructuring', { useBuiltIns: true }],
['@babel/plugin-proposal-object-rest-spread', { useBuiltIns: true }],
Expand All @@ -133,17 +163,5 @@ export default function getBabelConfig(
// Support `__DEV__` shortcuts
plugins.push(['babel-plugin-transform-dev', { evaluate: false }]);

return {
caller: {
name: 'packemon',
},
comments: false,
plugins,
presets,
// Do NOT load root `babel.config.js` as we need full control
configFile: false,
// Do load branch `.babelrc.js` files for granular customization
babelrc: true,
babelrcRoots: features.workspaces,
};
return getSharedConfig(plugins, presets, features);
}
39 changes: 21 additions & 18 deletions src/configs/rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import path from 'path';
import { Path } from '@boost/common';
import { RollupOptions, OutputOptions, ModuleFormat } from 'rollup';
import externals from 'rollup-plugin-node-externals';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import json from '@rollup/plugin-json';
import { getBabelInputPlugin, getBabelOutputPlugin } from '@rollup/plugin-babel';
import getBabelConfig from './babel';
import { getBabelInputConfig, getBabelOutputConfig } from './babel';
import Build from '../Build';
import { FeatureFlags, Format, BuildUnit } from '../types';
import { EXTENSIONS, EXCLUDE } from '../constants';
import getPlatformFromBuild from '../helpers/getPlatformFromBuild';

const sharedPlugins = [resolve({ extensions: EXTENSIONS }), json({ namedExports: false })];
const sharedPlugins = [resolve({ extensions: EXTENSIONS, preferBuiltins: true }), commonjs()];

function getInputFile(build: Build): Path | null {
// eslint-disable-next-line no-restricted-syntax
Expand Down Expand Up @@ -47,41 +47,42 @@ function getModuleFormat(format: Format): ModuleFormat {
return 'cjs';
}

export default function getRollupConfig(
build: Build,
features: FeatureFlags,
): RollupOptions | null {
export function getRollupConfig(build: Build, features: FeatureFlags): RollupOptions | null {
const inputPath = getInputFile(build);

if (!inputPath) {
return null;
}

const input = build.root.relativeTo(inputPath).path();
const packagePath = path.resolve(build.packagePath.append('package.json').path());

const config: RollupOptions = {
cache: build.cache,
external: [packagePath],
input,
output: [],
// Shared output plugins
plugins: [
...sharedPlugins,
// Declare Babel here so we can parse TypeScript/Flow
getBabelInputPlugin({
...getBabelConfig(build, null, features),
babelHelpers: 'bundled',
exclude: EXCLUDE,
extensions: EXTENSIONS,
filename: build.packagePath.path(),
}),
// Mark all dependencies in `package.json` as external
externals({
builtins: true,
deps: true,
devDeps: true,
optDeps: true,
packagePath: path.resolve(build.packagePath.append('package.json').path()),
packagePath,
peerDeps: true,
}),
// Externals MUST be listed before shared plugins
...sharedPlugins,
// Declare Babel here so we can parse TypeScript/Flow
getBabelInputPlugin({
...getBabelInputConfig(build, features),
babelHelpers: 'bundled',
exclude: EXCLUDE,
extensions: EXTENSIONS,
filename: build.packagePath.path(),
}),
],
// Always treeshake for smaller builds
treeshake: true,
Expand All @@ -104,10 +105,12 @@ export default function getRollupConfig(
// Output specific plugins
plugins: [
getBabelOutputPlugin({
...getBabelConfig(build, buildUnit, features),
...getBabelOutputConfig(buildUnit, features),
filename: build.packagePath.path(),
}),
],
// Disable source maps
sourcemap: false,
};

if (format === 'umd') {
Expand Down
14 changes: 12 additions & 2 deletions src/helpers/resolveTsConfig.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { Path, parseFile } from '@boost/common';
import { TSConfigStructure } from '../types';

const cache: Record<string, TSConfigStructure> = {};

export default function resolveTsConfig(path: Path): TSConfigStructure {
const contents = parseFile<TSConfigStructure>(path);
const cacheKey = path.path();

if (cache[cacheKey]) {
return cache[cacheKey];
}

let contents = parseFile<TSConfigStructure>(path);

// TODO deep merge
if (contents.extends) {
return {
contents = {
...resolveTsConfig(path.parent().append(contents.extends)),
...contents,
};
}

cache[cacheKey] = contents;

return contents;
}
Loading

0 comments on commit 9d74d94

Please sign in to comment.