Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions apps/test-bundles/just.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
import { preset, task, resolveCwd } from '@fluentui/scripts-tasks';
import * as path from 'path';
import { preset, task, series } from '@fluentui/scripts-tasks';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - parallel-webpack has no types
import { run } from 'parallel-webpack';

import { bundleSizeCollect } from './scripts/bundle-size-collect';
import { mergeBundleSizes } from './scripts/merge-bundlesizes';

preset();

// This pacakge doesn't currently have any files that are included in the eslint task
// (it only runs on src, not config files)
task('code-style', 'prettier');

task('bundle-size-collect', () => {
const packageName = process.env.PACKAGE ?? '';
bundleSizeCollect({ packageName });
});

task('bundle', done => {
run(resolveCwd('webpack.config.js'), {}, done);
const configPath = path.join(__dirname, 'webpack.config.js');
const options = {};
run(configPath, options, done);
});

task('bundle-size-merge', () => {
const root = path.join(__dirname, 'dist');
mergeBundleSizes(
[path.join(root, 'react/bundlesize.json'), path.join(root, 'react-northstar/bundlesize.json')],
path.join(root, 'bundlesizes.json'),
);
});

task('bundle-size', series('bundle', 'bundle-size-collect'));
3 changes: 1 addition & 2 deletions apps/test-bundles/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
"private": true,
"license": "MIT",
"scripts": {
"bundle:size": "just-scripts bundle",
"bundle-size-auditor": "just-scripts bundle-size",
"clean": "just-scripts clean",
"code-style": "just-scripts code-style",
"just": "just-scripts"
},
"devDependencies": {
"@fluentui/eslint-plugin": "*",
"parallel-webpack": "^2.6.0",
"@fluentui/scripts-tasks": "*",
"@fluentui/scripts-webpack": "*"
}
Expand Down
40 changes: 40 additions & 0 deletions apps/test-bundles/scripts/bundle-size-collect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as fs from 'fs';
import * as path from 'path';

/**
*
* collates bundle size information from minified files in apps/test-bundles/dist/<packageName> and writes to apps/test-bundles/dist/<packageName>/bundlesizes.json.
*
* It is uploaded as an artifact by the build definition in Azure Dev Ops and used to compare baseline and PR file size information which gets reported by Size Auditor
*/
export function bundleSizeCollect(config: { packageName: string; filename?: string }) {
const { packageName, filename: outputFilename = 'bundlesize.json' } = config;

if (!packageName) {
throw new Error('🚨 No packageName provided! Set it via env variable name "PACKAGE"');
}

const distRoot = path.join(__dirname, '../dist', packageName.replace('@fluentui/', ''));

const sizes: Record<string, number> = {};

const items = fs.readdirSync(distRoot);
items.forEach(item => {
const file = path.join(distRoot, item);

const isMinifiedJavascriptFile = item.match(/.min.js$/);
if (isMinifiedJavascriptFile) {
sizes[getComponentName(item)] = getFilesizeInBytes(file);
}
});

fs.writeFileSync(path.join(distRoot, outputFilename), JSON.stringify({ sizes }));

function getFilesizeInBytes(fileName: string) {
return fs.statSync(fileName).size;
}

function getComponentName(fileName: string) {
return path.basename(fileName, '.min.js');
}
}
14 changes: 14 additions & 0 deletions apps/test-bundles/scripts/merge-bundlesizes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as fs from 'fs';

export function mergeBundleSizes(configPaths: string[], mergeConfigPath: string) {
const result: { sizes: { [entryName: string]: number } } = {
sizes: {},
};

configPaths.forEach(configPath => {
const json = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
Object.assign(result.sizes, json.sizes);
});

fs.writeFileSync(mergeConfigPath, JSON.stringify(result));
}
45 changes: 32 additions & 13 deletions apps/test-bundles/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-shadow */

// @ts-check
const {
buildEntries,
Expand All @@ -8,21 +10,38 @@ const {
createEntry,
} = require('./webpackUtils');

const packageName = process.env.PACKAGE;
/**
*
* @param {string} packageName
* @returns
*/
function getEntries(packageName) {
if (packageName === '@fluentui/react-northstar') {
createFluentNorthstarFixtures();
const entries = buildEntries('@fluentui/react-northstar');
return entries;
}

if (packageName === '@fluentui/react') {
createFluentReactFixtures();
createEntry('@fluentui/keyboard-key');

const entries = buildEntries('@fluentui/react');
entries['keyboard-key'] = buildEntry('@fluentui/keyboard-key');
return entries;
}

console.error('🚨 packageName needs to be one of `@fluentui/react` or `@fluentui/react-northstar`!');
process.exit(1);
}

let entries;
if (packageName === '@fluentui/react-northstar') {
createFluentNorthstarFixtures();
entries = buildEntries('@fluentui/react-northstar');
} else if (packageName === '@fluentui/react') {
createFluentReactFixtures();
createEntry('@fluentui/keyboard-key');
const packageName = process.env.PACKAGE ?? '';

entries = buildEntries('@fluentui/react');
entries['keyboard-key'] = buildEntry('@fluentui/keyboard-key');
} else {
console.error('🚨 No packageName provided!');
if (!packageName) {
console.error('🚨 No packageName provided! Set it via env variable name "PACKAGE"');
process.exit(1);
}
const entries = getEntries(packageName);
const config = createWebpackConfig(entries, packageName);

module.exports = createWebpackConfig(entries, packageName);
module.exports = config;
29 changes: 25 additions & 4 deletions apps/test-bundles/webpackUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ const TerserPlugin = require('terser-webpack-plugin');

const FIXTURE_PATH = 'temp/fixtures/';

/**
*
* @param {{[entryName:string]:{entryPath:string, includeStats:boolean}}} entries
* @param {string} packageName
* @returns
*/
function createWebpackConfig(entries, packageName) {
const normalizedPkgName = packageName.replace('@fluentui/', '');
return Object.keys(entries).map(entryName => {
/** @type {BundleAnalyzerPlugin.Options} */
let anaylizerPluginOptions = {
Expand Down Expand Up @@ -53,6 +60,10 @@ function createWebpackConfig(entries, packageName) {
entry: {
[entryName]: entryPath,
},
output: {
filename: `[name].min.js`,
path: path.resolve(__dirname, 'dist', normalizedPkgName),
},
externals: {
react: 'React',
'react-dom': 'ReactDOM',
Expand Down Expand Up @@ -130,6 +141,9 @@ function createFluentReactFixtures() {
});
}

/**
* @param {string} packageName
*/
function createEntry(packageName) {
try {
// import everything from a single package
Expand All @@ -145,11 +159,13 @@ function createEntry(packageName) {
/**
* Build webpack entries from created fixtures.
*
* @param {string} packageName
* @param {{[entryName:string]:{entryPath:string, includeStats:boolean}}} [entries]
* @param {boolean} [includeStats] - Stats are generated and used by the size auditor report
* to check more details on what caused the bundle size change. Due to stats generation being slow,
* and therefore slowing down CI significantly, setting this to true to avoid stats generation.
* If bundle size is changed unexpectedly, developers can drill down deeper on the problem by
* locally running bundle tests.
to check more details on what caused the bundle size change. Due to stats generation being slow,
and therefore slowing down CI significantly, setting this to true to avoid stats generation.
If bundle size is changed unexpectedly, developers can drill down deeper on the problem by
locally running bundle tests.
*/
function buildEntries(packageName, entries = {}, includeStats = true) {
const folderName = getFolderName(packageName);
Expand All @@ -169,6 +185,8 @@ function buildEntries(packageName, entries = {}, includeStats = true) {

/**
* Build entries for single fixture with top level import.
* @param {string} packageName
* @param {boolean} [includeStats]
*/
function buildEntry(packageName, includeStats = true) {
const folderName = getFolderName(packageName);
Expand All @@ -179,6 +197,9 @@ function buildEntry(packageName, includeStats = true) {
};
}

/**
* @param {string} packageName
*/
function getFolderName(packageName) {
return packageName.replace('@fluentui/', '');
}
Expand Down
99 changes: 14 additions & 85 deletions azure-pipelines.bundlesize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ variables:
- template: .devops/templates/variables.yml

jobs:
- job: bundlesize
- job: bundle_size
workspace:
clean: all
pool: '1ES-Host-Ubuntu'
Expand Down Expand Up @@ -53,7 +53,7 @@ jobs:

- template: .devops/templates/cleanup.yml

- job: build_react
- job: bundle_size_auditor
workspace:
clean: all
timeoutInMinutes: 75
Expand All @@ -66,110 +66,39 @@ jobs:
filePath: yarn-ci.sh
displayName: yarn

- script: yarn build --to @fluentui/react @fluentui/keyboard-key
displayName: yarn build to @fluentui/react
- script: yarn build --to @fluentui/react @fluentui/keyboard-key @fluentui/react-northstar
displayName: build @fluentui/react, @fluentui/react-northstar

- script: yarn workspace @fluentui/test-bundles bundle:size
displayName: yarn bundle @fluentui/test-bundles
- script: yarn workspace @fluentui/test-bundles bundle-size-auditor
displayName: create @fluentui/react bundle-size entries
env:
PACKAGE: '@fluentui/react'

- script: yarn bundlesizecollect
displayName: 'Collate Bundle Size Information'

- task: PublishBuildArtifacts@1
displayName: 'Publish Bundle Size information to Azure Dev Ops Artifacts'
inputs:
PathtoPublish: 'apps/test-bundles/dist/bundlesize.json'
ArtifactName: bundlesize-react

- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact dist folder upon build for debug'
inputs:
PathtoPublish: 'apps/test-bundles/dist'
ArtifactName: distdrop-react

- template: .devops/templates/cleanup.yml

- job: build_northstar
workspace:
clean: all
timeoutInMinutes: 75
pool: '1ES-Host-Ubuntu'
steps:
- template: .devops/templates/tools.yml

- task: Bash@3
inputs:
filePath: yarn-ci.sh
displayName: yarn

- script: yarn build --to @fluentui/react-northstar
displayName: yarn build to @fluentui/react-northstar

- script: yarn workspace @fluentui/test-bundles bundle:size
displayName: yarn bundle @fluentui/test-bundles
- script: yarn workspace @fluentui/test-bundles bundle-size-auditor
displayName: create @fluentui/react-northstar bundle-size entries
env:
PACKAGE: '@fluentui/react-northstar'

- script: yarn bundlesizecollect
displayName: 'Collate Bundle Size Information'
- script: yarn workspace @fluentui/test-bundles just-scripts bundle-size-merge
displayName: 'Merge @fluentui/react, @fluentui/react-northstar to bundlesizes.json'

- task: PublishBuildArtifacts@1
displayName: 'Publish Bundle Size information to Azure Dev Ops Artifacts'
displayName: 'Publish Merged Bundle Size information'
inputs:
PathtoPublish: 'apps/test-bundles/dist/bundlesize.json'
ArtifactName: bundlesize-northstar
PathtoPublish: 'apps/test-bundles/dist/bundlesizes.json'

- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact dist folder upon build for debug'
inputs:
PathtoPublish: 'apps/test-bundles/dist'
ArtifactName: distdrop-northstar
ArtifactName: distdrop

- template: .devops/templates/cleanup.yml

- job: merge
pool: '1ES-Host-Ubuntu'
dependsOn:
- build_northstar
- build_react
steps:
- checkout: none

- task: DownloadPipelineArtifact@2
displayName: 'Download Pipeline Artifact: @fluentui/react'
inputs:
artifactName: 'bundlesize-react'
targetPath: '$(Build.ArtifactStagingDirectory)/react'

- task: DownloadPipelineArtifact@2
displayName: 'Download Pipeline Artifact: @fluentui/react-northstar'
inputs:
artifactName: 'bundlesize-northstar'
targetPath: '$(Build.ArtifactStagingDirectory)/react-northstar'

- script: 'sudo apt-get install jq'
displayName: 'Install jq'

- script: jq -c -s 'reduce .[] as $item ({}; . * $item)' $(Build.ArtifactStagingDirectory)/react-northstar/bundlesize.json $(Build.ArtifactStagingDirectory)/react/bundlesize.json > $(Build.ArtifactStagingDirectory)/bundlesizes.json
displayName: 'Merge @fluentui/react, @fluentui/react-components & @fluentui/react-northstar to bundlesizes.json'

- task: PublishBuildArtifacts@1
displayName: 'Publish Merged Bundle Size information'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)/bundlesizes.json'

- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact dist folder upon build for debug'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: distdrop

- job: lightrail
pool: server
dependsOn:
- merge
- bundle_size_auditor
steps:
- task: odefun.odsp-lightrail-tasks-partner.odsp-lightrail-tasks-SizeAuditorWorker.SizeAuditorWorker@0
displayName: 'Size Auditor Check on LightRail'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"buildto": "lage build --verbose --to",
"buildto:lerna": "node ./scripts/executors/buildTo.js",
"bundle": "lage bundle --verbose",
"bundlesizecollect": "node ./scripts/generators/bundle-size-collect",
"change": "beachball change --no-commit",
"check:change": "beachball check",
"check:modified-files": "node -r ./scripts/ts-node/register ./scripts/executors/check-for-modified-files",
Expand Down Expand Up @@ -287,6 +286,7 @@
"node-polyfill-webpack-plugin": "1.0.2",
"nx": "15.6.3",
"p-queue": "6.6.2",
"parallel-webpack": "2.6.0",
"parse-diff": "0.7.1",
"path-browserify": "1.0.1",
"plop": "2.6.0",
Expand Down
Loading