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
22 changes: 20 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@
"type": "npm",
"script": "watch:extension",
"isBackground": true,
"problemMatcher": "$tsc-watch"
"problemMatcher": {
"owner": "custom",
"pattern": {
"regexp": "."
},
"background": {
"activeOnStart": true,
"beginsPattern": ".*Building the extension.*",
"endsPattern": ".*Watching the extension\\.\\.\\."
}
}
},
{
"label": "watch:webviews",
Expand All @@ -28,13 +38,21 @@
}
},
{
"label": "watch",
"label": "watch-all",
"dependsOn": [
"watch:extension",
"watch:webviews"
],
"dependsOrder": "parallel"
},
{
"label": "watch",
"dependsOn": [
"compile",
"watch-all"
],
"dependsOrder": "sequence"
},
{
"label": "compile",
"type": "npm",
Expand Down
89 changes: 3 additions & 86 deletions build/esbuild.build.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,97 +3,14 @@
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

const { execSync } = require('child_process');
const esbuild = require('esbuild');
const { esmAliasPlugin, esbuildProblemMatcherPlugin, nativeNodeModulesPlugin, svgrPlugin, verbosePlugin } = require('./esbuild.plugins.cjs');
const { webviews, srcDir, outDir } = require('./esbuild.settings.cjs');
const { sassPlugin } = require('esbuild-sass-plugin');
const { cp, mkdir, stat } = require('node:fs/promises');
const path = require('path');
const { sync } = require('fast-glob');
const { buildExtension } = require('./esbuild.extension.cjs');
const { buildWebviews } = require('./esbuild.webviews.cjs');

const production = process.argv.includes('--production');

// eslint-disable no-console

// Run type-checking

/// Verify the extension
try {
// execSync('tsc --noEmit', { stdio: 'inherit' });
execSync('tsc --noEmit -p tsconfig.json', { stdio: 'inherit' });
} catch (err) {
console.error('❌ TypeScript type-checking failed.');
process.exit(1);
}

console.log(`esbuild: building for production: ${production ? 'Yes' : 'No'}`);

const baseConfig = {
bundle: true,
target: 'chrome108',
minify: production,
sourcemap: !production,
logLevel: 'warning',
logOverride: {
'equals-negative-zero': 'silent'
}
};

async function buildExtension() {
console.log(`📦 Building the extension for ${ production ? 'Production' : 'Development'}...`);

if (production) {
// Build the extension.js
const extConfig = {
...baseConfig,
platform: 'node',
format: 'cjs',
entryPoints: [`./${srcDir}/extension.ts`],
outfile: `${outDir}/${srcDir}/extension.js`,
external: [ 'vscode', 'shelljs', 'jsonc-parser' ],
plugins: [
nativeNodeModulesPlugin(),
esbuildProblemMatcherPlugin(production) // this one is to be added to the end of plugins array
]
};
await esbuild.build(extConfig);
console.log('✅ Extension build completed');
} else {
// Build the Extension for development
const srcFiles = sync(`${srcDir}/**/*.{js,ts}`, { absolute: false });
const devExtConfig = {
...baseConfig,
platform: 'node',
format: 'cjs',
entryPoints: srcFiles.map(f => `./${f}`),
outbase: srcDir,
outdir: `${outDir}/${srcDir}`,
external: [ 'vscode', 'shelljs', 'jsonc-parser', '@aws-sdk/client-s3' ],
plugins: [
// verbosePlugin(),
esmAliasPlugin(),
nativeNodeModulesPlugin(),
esbuildProblemMatcherPlugin(production) // this one is to be added to the end of plugins array
]
};

await esbuild.build(devExtConfig);

const jsonFiles = sync('src/**/*.json', { absolute: false });
for (const file of jsonFiles) {
const dest = path.join('out', file);
await cp(file, dest, { recursive: false, force: true });
}
await cp('package.json', 'out/package.json');
console.log('✅ Extension build completed');
}
}

async function buildAll() {
await buildExtension();
await buildWebviews();
await buildExtension();
await buildWebviews();
}

buildAll().catch(err => {
Expand Down
140 changes: 140 additions & 0 deletions build/esbuild.extension.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

const { execSync } = require('child_process');
const esbuild = require('esbuild');
const { esmAliasPlugin, esbuildProblemMatcherPlugin, nativeNodeModulesPlugin } = require('./esbuild.plugins.cjs');
const { srcDir, outDir } = require('./esbuild.settings.cjs');
const { cp } = require('node:fs/promises');
const path = require('path');
const { sync } = require('fast-glob');

const production = process.argv.includes('--production');
const isWatch = process.argv.includes('--watch');

// eslint-disable no-console

const baseConfig = {
bundle: true,
target: 'chrome108',
minify: production,
sourcemap: !production,
logLevel: 'warning',
logOverride: {
'equals-negative-zero': 'silent'
}
};

async function copyJsonFiles() {
const jsonFiles = sync('src/**/*.json', { absolute: false });
for (const file of jsonFiles) {
const dest = path.join('out', file);
await cp(file, dest, { recursive: false, force: true });
}
await cp('package.json', 'out/package.json');
}

async function buildExtension() {
// Only run type-checking on non-watch builds
if (!isWatch) {
console.log('🔍 Running TypeScript type-checking...');
try {
execSync('tsc --noEmit -p tsconfig.json', { stdio: 'inherit' });
} catch (err) {
console.error('❌ TypeScript type-checking failed.');
process.exit(1);
}
}

console.log(`📦 Building the extension for ${production ? 'Production' : 'Development'}...`);

if (production) {
// Build the extension.js (single bundle for production)
const extConfig = {
...baseConfig,
platform: 'node',
format: 'cjs',
entryPoints: [`./${srcDir}/extension.ts`],
outfile: `${outDir}/${srcDir}/extension.js`,
external: ['vscode', 'shelljs', 'jsonc-parser'],
plugins: [
nativeNodeModulesPlugin(),
esbuildProblemMatcherPlugin(production)
]
};
await esbuild.build(extConfig);
await copyJsonFiles();
console.log('✅ Extension build completed');
} else {
// Build the Extension for development (individual files)
const srcFiles = sync(`${srcDir}/**/*.{js,ts}`, { absolute: false });
const devExtConfig = {
...baseConfig,
platform: 'node',
format: 'cjs',
entryPoints: srcFiles.map(f => `./${f}`),
outbase: srcDir,
outdir: `${outDir}/${srcDir}`,
external: ['vscode', 'shelljs', 'jsonc-parser', '@aws-sdk/client-s3'],
plugins: [
esmAliasPlugin(),
nativeNodeModulesPlugin(),
esbuildProblemMatcherPlugin(production)
]
};

if (isWatch) {
try {
const ctx = await esbuild.context({
...devExtConfig,
plugins: [
...devExtConfig.plugins,
{
name: 'rebuild-hook',
setup(build) {
build.onEnd(result => {
if (result.errors.length === 0) {
console.log('🔁 Extension rebuild succeeded');
copyJsonFiles().catch(err =>
console.error('❌ Failed to copy JSON files after rebuild:', err)
);
} else {
console.error('❌ Extension rebuild errors:', result.errors);
}
});
}
}
]
});
await ctx.watch();
await copyJsonFiles().catch(err => {
console.error('❌ Failed to copy JSON files on initial watch setup:', err);
});
console.log('👀 Watching the extension...');

// Keep the process alive even if there are errors
// esbuild will continue watching and rebuild on changes
await new Promise(() => {}); // Never resolves - keeps watch running
} catch (err) {
console.error('❌ Failed to start extension watcher:', err);
console.error('⚠️ Watch mode failed to start. Please fix errors and restart.');
process.exit(1);
}
} else {
await esbuild.build(devExtConfig);
await copyJsonFiles();
console.log('✅ Extension build completed');
}
}
}

if (require.main === module) {
buildExtension().catch(err => {
console.error('❌ Extension build failed:', err);
process.exit(1);
});
}

module.exports = { buildExtension };
72 changes: 43 additions & 29 deletions build/esbuild.webviews.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ const isWatch = process.argv.includes('--watch');

// eslint-disable no-console

// Verify the WebViews
try {
execSync('tsc --noEmit -p ./src/webview/tsconfig.json', { stdio: 'inherit' });
} catch (err) {
console.error('❌ TypeScript type-checking failed.');
process.exit(1);
// Verify the WebViews (skip in watch mode - VS Code editor handles this)
if (!isWatch) {
try {
execSync('tsc --noEmit -p ./src/webview/tsconfig.json', { stdio: 'inherit' });
} catch (err) {
console.error('❌ TypeScript type-checking failed.');
process.exit(1);
}
}

const baseConfig = {
Expand Down Expand Up @@ -53,30 +55,42 @@ async function buildWebviews() {
};

if (isWatch) {
const ctx = await esbuild.context({
...devWebViewConfig,
plugins: [
...devWebViewConfig.plugins,
{
name: 'rebuild-hook',
setup(build) {
build.onEnd(result => {
if (result.errors.length === 0) {
console.log('🔁 Rebuild succeeded');
copyHtmlFiles().catch(err =>
console.error('❌ Failed to copy HTML files after rebuild:', err)
);
} else {
console.error('❌ Rebuild errors:', result.errors);
}
});
try {
const ctx = await esbuild.context({
...devWebViewConfig,
plugins: [
...devWebViewConfig.plugins,
{
name: 'rebuild-hook',
setup(build) {
build.onEnd(result => {
if (result.errors.length === 0) {
console.log('🔁 Rebuild succeeded');
copyHtmlFiles().catch(err =>
console.error('❌ Failed to copy HTML files after rebuild:', err)
);
} else {
console.error('❌ Rebuild errors:', result.errors);
}
});
}
}
}
]
});
await ctx.watch();
await copyHtmlFiles();
console.log('👀 Watching the webviews...');
]
});
await ctx.watch();
await copyHtmlFiles().catch(err => {
console.error('❌ Failed to copy HTML files on initial watch setup:', err);
});
console.log('👀 Watching the webviews...');

// Keep the process alive even if there are errors
// esbuild will continue watching and rebuild on changes
await new Promise(() => {}); // Never resolves - keeps watch running
} catch (err) {
console.error('❌ Failed to start webviews watcher:', err);
console.error('⚠️ Watch mode failed to start. Please fix errors and restart.');
process.exit(1);
}
} else {
await esbuild.build(devWebViewConfig);
await copyHtmlFiles();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"build": "npm run prebuild-esm && node ./build/esbuild.build.cjs && npm run bundle-tools",
"vscode:prepublish": "npm install --ignore-scripts && npm run clean && npm run lint && npm run prebuild-esm && node ./build/esbuild.build.cjs --production && npm run bundle-tools && npm prune --omit=dev",
"prebuild-esm": "node ./build/esbuild.transform-esm.cjs",
"watch:extension": "tsc -p tsconfig.json --watch",
"watch:extension": "node ./build/esbuild.extension.cjs --watch",
"watch:webviews": "node ./build/esbuild.webviews.cjs --watch",
"bundle-tools": "node ./build/bundle-tools.cjs --platform",
"verify-tools": "node ./build/verify-tools.cjs",
Expand Down
Loading