Skip to content

Commit

Permalink
feat(angular-rollup): init test
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherPHolder committed May 28, 2024
1 parent f7725ef commit 91fce76
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 0 deletions.
10 changes: 10 additions & 0 deletions packages/angular-rollup/executors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"executors": {
"bundle": {
"implementation": "./src/executors/bundle/executor",
"schema": "./src/executors/bundle/schema.json",
"description": "Angular Post Processing Rollup Bundler",
"hasher": "./src/executors/bundle/hasher"
}
}
}
11 changes: 11 additions & 0 deletions packages/angular-rollup/src/executors/bundle/executor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { BundleExecutorSchema } from './schema';
import executor from './executor';

const options: BundleExecutorSchema = {};

describe('Bundle Executor', () => {
it('can run', async () => {
const output = await executor(options);
expect(output.success).toBe(true);
});
});
64 changes: 64 additions & 0 deletions packages/angular-rollup/src/executors/bundle/executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { readFileSync, rmSync, readdirSync, renameSync } from 'node:fs';
import { join } from 'node:path';

import { Metafile } from 'esbuild';
import { ManualChunksOption, OutputOptions, PreRenderedChunk, rollup } from 'rollup';

import { BundleExecutorSchema } from './schema';

const POLYFILLS_ENTRY_POINT = 'angular:polyfills:angular:polyfills';
const statsJsonPath = (outputPath: string) => join(outputPath,'stats.json');
const entryChunkPath = (outputPath: string, chunkName: string) => join(outputPath, chunkName);
const noEntryChunkError = () => new Error('No entry chunk found matching @TODO improve error message');
const chunkWithEntryPoint = (entryPoint: string, outputChunks: Metafile['outputs']): string | undefined => {
return Object.keys(outputChunks).find(output => outputChunks[output].entryPoint === entryPoint);
};
const entryChunk = (entryPoint: string, statsJson: Metafile): string => {
const chunkName = chunkWithEntryPoint(entryPoint, statsJson.outputs);
if (!chunkName) throw noEntryChunkError();
return chunkName;
}

function getJson<T = any>(path: string) {
return JSON.parse(readFileSync(join(path), {encoding: 'utf-8'})) as T;
}

export default async function runExecutor(options: BundleExecutorSchema) {
console.log('Executor ran for Bundle', options);

const statsJson = getJson<Metafile>(statsJsonPath(options.outputPath));
const mainChunk = entryChunk(options.main, statsJson);
const polyfillsChunk = entryChunk(POLYFILLS_ENTRY_POINT, statsJson);
const input = [entryChunkPath(options.outputPath, mainChunk), entryChunkPath(options.outputPath, polyfillsChunk)];

const dir = join('tmp', options.outputPath);

const manualChunks: ManualChunksOption = (id, meta) => {
if (id.includes(mainChunk) || id.includes(polyfillsChunk)) return;
if (id.includes("chunk")) return "extra";
return 'vendor';
};

const chunkFileNames = (chunkInfo: PreRenderedChunk): string => {
return `${chunkInfo.type}-${chunkInfo.name}.js`;
}
const output: OutputOptions = {
manualChunks,
chunkFileNames,
dir
};
const b = await rollup({ input });
await b.write(output);

for (const output of Object.keys(statsJson.outputs)) {
if (!output.endsWith('.css')) rmSync(join(options.outputPath, output));
}

for (const output of readdirSync(dir)) {
renameSync(join(dir, output), join(options.outputPath, output));
}

rmSync(dir, {recursive: true});

return { success: true };
}
26 changes: 26 additions & 0 deletions packages/angular-rollup/src/executors/bundle/hasher.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { TaskHasher, HasherContext } from '@nx/devkit';

import { bundleHasher } from './hasher';

describe('bundleHasher', () => {
it('should generate hash', async () => {
const mockHasher: TaskHasher = {
hashTask: jest.fn().mockReturnValue({ value: 'hashed-task' }),
} as unknown as TaskHasher;
const hash = await bundleHasher(
{
id: 'my-task-id',
target: {
project: 'proj',
target: 'target',
},
overrides: {},
outputs: [],
},
{
hasher: mockHasher,
} as unknown as HasherContext,
);
expect(hash).toEqual({ value: 'hashed-task' });
});
});
12 changes: 12 additions & 0 deletions packages/angular-rollup/src/executors/bundle/hasher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CustomHasher } from '@nx/devkit';

/**
* This is a boilerplate custom hasher that matches
* the default Nx hasher. If you need to extend the behavior,
* you can consume workspace details from the context.
*/
export const bundleHasher: CustomHasher = async (task, context) => {
return context.hasher.hashTask(task, context.taskGraph);
};

export default bundleHasher;
4 changes: 4 additions & 0 deletions packages/angular-rollup/src/executors/bundle/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface BundleExecutorSchema {
main: string;
outputPath: string;
} // eslint-disable-line
18 changes: 18 additions & 0 deletions packages/angular-rollup/src/executors/bundle/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://json-schema.org/schema",
"version": 2,
"title": "Bundle executor",
"description": "Post processor for Angular's esbuild builder to reduce chunks",
"type": "object",
"properties": {
"main": {
"type": "string",
"description": "The path to the entry file, relative to project.",
"alias": "entryFile",
"x-completion-type": "file",
"x-completion-glob": "**/*@(.js|.ts)",
"x-priority": "important"
}
},
"required": []
}

0 comments on commit 91fce76

Please sign in to comment.