Skip to content

Commit 51ba84d

Browse files
committed
fix: address PR #94 review comments
- Remove fastly-runtime.js from test coverage exclusion - Use exact version for esbuild dependency (no caret) - Fix copyright years to 2025 across affected files - Add validateBundle() method using wrangler/fastly CLI - Use fastly-runtime.js for logger import to avoid webpackIgnore 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: Lars Trieloff <[email protected]>
1 parent 557872e commit 51ba84d

File tree

6 files changed

+120
-16
lines changed

6 files changed

+120
-16
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"main": "src/index.js",
66
"type": "module",
77
"scripts": {
8-
"test": "c8 --exclude 'test/fixtures/**' --exclude 'src/template/fastly-runtime.js' mocha -i -g Integration",
9-
"integration-ci": "c8 --exclude 'test/fixtures/**' --exclude 'src/template/fastly-runtime.js' mocha -g Integration",
8+
"test": "c8 --exclude 'test/fixtures/**' mocha -i -g Integration",
9+
"integration-ci": "c8 --exclude 'test/fixtures/**' mocha -g Integration",
1010
"lint": "eslint .",
1111
"semantic-release": "semantic-release",
1212
"semantic-release-dry": "semantic-release --dry-run --branches $CI_BRANCH",
@@ -64,7 +64,7 @@
6464
"@fastly/js-compute": "3.35.2",
6565
"chalk-template": "1.1.2",
6666
"constants-browserify": "1.0.0",
67-
"esbuild": "^0.25.0",
67+
"esbuild": "0.25.0",
6868
"form-data": "4.0.4",
6969
"fs-extra": "11.3.0",
7070
"tar": "7.5.2"

src/EdgeESBuildBundler.js

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 Adobe. All rights reserved.
2+
* Copyright 2025 Adobe. All rights reserved.
33
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License. You may obtain a copy
55
* of the License at http://www.apache.org/licenses/LICENSE-2.0
@@ -10,6 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212
import { fileURLToPath } from 'url';
13+
import { execSync, spawnSync } from 'child_process';
1314
import path from 'path';
1415
import fse from 'fs-extra';
1516
import * as esbuild from 'esbuild';
@@ -233,9 +234,107 @@ export default class EdgeESBuildBundler extends BaseBundler {
233234
].join('\n'), { name: 'wrangler.toml' });
234235
}
235236

237+
/**
238+
* Checks if a command is available in the system PATH
239+
* @param {string} command - The command to check
240+
* @returns {boolean} - True if the command is available
241+
*/
236242
// eslint-disable-next-line class-methods-use-this
237-
validateBundle() {
238-
// TODO: validate edge bundle
239-
// Could potentially use wrangler/viceroy for validation
243+
isCommandAvailable(command) {
244+
try {
245+
execSync(`which ${command}`, { stdio: 'ignore' });
246+
return true;
247+
} catch {
248+
return false;
249+
}
250+
}
251+
252+
/**
253+
* Validates the edge bundle using wrangler (Cloudflare) or viceroy (Fastly) if available.
254+
* This helps catch runtime issues before deployment.
255+
*/
256+
async validateBundle() {
257+
const { cfg } = this;
258+
const bundlePath = cfg.edgeBundle;
259+
const bundleDir = path.dirname(path.resolve(cfg.cwd, bundlePath));
260+
261+
// Try wrangler validation first (Cloudflare)
262+
const hasWrangler = this.isCommandAvailable('wrangler');
263+
if (hasWrangler) {
264+
cfg.log.info('--: validating edge bundle with wrangler...');
265+
try {
266+
// Create a minimal wrangler.toml for validation
267+
const wranglerToml = path.join(bundleDir, 'wrangler.toml');
268+
const wranglerConfig = [
269+
'name = "validation-test"',
270+
`main = "${path.basename(bundlePath)}"`,
271+
'compatibility_date = "2024-01-01"',
272+
'no_bundle = true',
273+
].join('\n');
274+
await fse.writeFile(wranglerToml, wranglerConfig);
275+
276+
// Run wrangler deploy --dry-run to validate without deploying
277+
const result = spawnSync('wrangler', ['deploy', '--dry-run'], {
278+
cwd: bundleDir,
279+
stdio: 'pipe',
280+
timeout: 30000,
281+
});
282+
283+
// Clean up temporary wrangler.toml
284+
await fse.remove(wranglerToml);
285+
286+
if (result.status === 0) {
287+
cfg.log.info(chalk`{green ok:} wrangler validation passed`);
288+
} else {
289+
const stderr = result.stderr?.toString() || '';
290+
cfg.log.warn(chalk`{yellow warn:} wrangler validation issues: ${stderr}`);
291+
}
292+
} catch (err) {
293+
cfg.log.warn(chalk`{yellow warn:} wrangler validation failed: ${err.message}`);
294+
}
295+
}
296+
297+
// Try Fastly validation (via fastly CLI which uses viceroy)
298+
const hasFastly = this.isCommandAvailable('fastly');
299+
if (hasFastly) {
300+
cfg.log.info('--: validating edge bundle with fastly (viceroy)...');
301+
try {
302+
// Create a minimal fastly.toml for validation
303+
const fastlyToml = path.join(bundleDir, 'fastly.toml');
304+
const fastlyConfig = [
305+
'manifest_version = 2',
306+
'name = "validation-test"',
307+
'language = "javascript"',
308+
'[scripts]',
309+
'build = ""',
310+
].join('\n');
311+
await fse.writeFile(fastlyToml, fastlyConfig);
312+
313+
// Run fastly compute serve with --skip-build to validate
314+
// Use a short timeout and immediately kill to just check if bundle loads
315+
const result = spawnSync('fastly', ['compute', 'serve', '--skip-build', '--file', path.basename(bundlePath)], {
316+
cwd: bundleDir,
317+
stdio: 'pipe',
318+
timeout: 5000,
319+
});
320+
321+
// Clean up temporary fastly.toml
322+
await fse.remove(fastlyToml);
323+
324+
// Check if it started successfully (will timeout, but no errors means valid)
325+
const stderr = result.stderr?.toString() || '';
326+
if (!stderr.includes('error') && !stderr.includes('Error')) {
327+
cfg.log.info(chalk`{green ok:} fastly validation passed`);
328+
} else {
329+
cfg.log.warn(chalk`{yellow warn:} fastly validation issues: ${stderr}`);
330+
}
331+
} catch (err) {
332+
cfg.log.warn(chalk`{yellow warn:} fastly validation failed: ${err.message}`);
333+
}
334+
}
335+
336+
if (!hasWrangler && !hasFastly) {
337+
cfg.log.info('--: skipping bundle validation (neither wrangler nor fastly CLI installed)');
338+
}
240339
}
241340
}

src/template/context-logger.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212
/* eslint-env serviceworker */
13+
import { getLogger } from './fastly-runtime.js';
1314

1415
/**
1516
* Normalizes log input to always be an object.
@@ -59,12 +60,16 @@ export function createFastlyLogger(context) {
5960
const loggers = {};
6061
let loggersReady = false;
6162
let loggerPromise = null;
62-
let loggerModule = null;
63+
let LoggerClass = null;
6364

64-
// Initialize Fastly logger module asynchronously
65-
// eslint-disable-next-line import/no-unresolved
66-
loggerPromise = import(/* webpackIgnore: true */ 'fastly:logger').then((module) => {
67-
loggerModule = module;
65+
// Initialize Fastly logger module asynchronously using fastly-runtime.js
66+
loggerPromise = getLogger().then((Logger) => {
67+
if (!Logger) {
68+
// getLogger() returns null when import fails
69+
// eslint-disable-next-line no-console
70+
console.error('Failed to import fastly:logger: module not available');
71+
}
72+
LoggerClass = Logger;
6873
loggersReady = true;
6974
loggerPromise = null;
7075
}).catch((err) => {
@@ -88,7 +93,7 @@ export function createFastlyLogger(context) {
8893
loggerNames.forEach((name) => {
8994
if (!loggers[name]) {
9095
try {
91-
loggers[name] = new loggerModule.Logger(name);
96+
loggers[name] = new LoggerClass(name);
9297
} catch (err) {
9398
// eslint-disable-next-line no-console
9499
console.error(`Failed to create Fastly logger "${name}": ${err.message}`);

src/template/fastly-runtime.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 Adobe. All rights reserved.
2+
* Copyright 2025 Adobe. All rights reserved.
33
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License. You may obtain a copy
55
* of the License at http://www.apache.org/licenses/LICENSE-2.0

test/edge-integration.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 Adobe. All rights reserved.
2+
* Copyright 2025 Adobe. All rights reserved.
33
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License. You may obtain a copy
55
* of the License at http://www.apache.org/licenses/LICENSE-2.0

test/fixtures/esbuild-action/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 Adobe. All rights reserved.
2+
* Copyright 2025 Adobe. All rights reserved.
33
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License. You may obtain a copy
55
* of the License at http://www.apache.org/licenses/LICENSE-2.0

0 commit comments

Comments
 (0)