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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed

- Watch local dependency source files in dev/watch mode — changes now trigger webpack rebuilds ([#70](https://github.com/studiometa/playground/pull/70), [0c08ef0](https://github.com/studiometa/playground/commit/0c08ef0))

## v0.3.7 - 2026.04.01

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ describe('PlaygroundDependenciesPlugin', () => {

// Trigger the compilation hook with a minimal fake compilation
compilationCallback?.({
fileDependencies: new Set(),
hooks: {
processAssets: { tapAsync() {} },
},
Expand Down Expand Up @@ -203,6 +204,7 @@ describe('PlaygroundDependenciesPlugin', () => {

// Should not throw
compilationCallback?.({
fileDependencies: new Set(),
hooks: {
processAssets: { tapAsync() {} },
},
Expand All @@ -211,4 +213,78 @@ describe('PlaygroundDependenciesPlugin', () => {
expect(p.importMap).toBeUndefined();
});
});

describe('file watching for local sources', () => {
function applyAndGetFileDependencies(
deps: ResolvedDependency[],
configDir: string,
): Set<string> {
const p = new PlaygroundDependenciesPlugin(deps, configDir);
let compilationCallback: ((compilation: unknown) => void) | undefined;
const fakeCompiler = {
options: { output: { publicPath: 'auto' } },
webpack: { Compilation: { PROCESS_ASSETS_STAGE_ADDITIONAL: 0 } },
hooks: {
thisCompilation: {
tap(_name: string, cb: (compilation: unknown) => void) {
compilationCallback = cb;
},
},
},
};

p.apply(fakeCompiler as any);

const fileDependencies = new Set<string>();
compilationCallback?.({
fileDependencies,
hooks: {
processAssets: { tapAsync() {} },
},
});

return fileDependencies;
}

it('adds local source files to compilation fileDependencies', () => {
const deps: ResolvedDependency[] = [
{
specifier: 'my-lib',
importMapValue: '/static/deps/my-lib/index.js',
type: 'bundle',
source: './src/index.ts',
},
];

const fileDeps = applyAndGetFileDependencies(deps, '/project');
expect(fileDeps.size).toBe(1);
expect([...fileDeps][0]).toContain('src/index.ts');
});

it('does not add esm-sh dependencies to fileDependencies', () => {
const deps: ResolvedDependency[] = [
{
specifier: 'deepmerge',
importMapValue: 'https://esm.sh/deepmerge',
type: 'esm-sh',
},
];

const fileDeps = applyAndGetFileDependencies(deps, '/project');
expect(fileDeps.size).toBe(0);
});

it('does not add bundle deps without source to fileDependencies', () => {
const deps: ResolvedDependency[] = [
{
specifier: 'my-lib',
importMapValue: '/static/deps/my-lib/index.js',
type: 'bundle',
},
];

const fileDeps = applyAndGetFileDependencies(deps, '/project');
expect(fileDeps.size).toBe(0);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ export class PlaygroundDependenciesPlugin {
}
}

// Watch local source files so webpack rebuilds when they change
for (const dep of this.dependencies) {
if (dep.type === 'bundle' && dep.source && this.isLocalSource(dep.source)) {
const resolvedPattern = resolve(this.configDir, dep.source);
const isGlob = dep.source.includes('*');
const sourceFiles = isGlob ? glob.globSync(resolvedPattern) : [resolvedPattern];
for (const file of sourceFiles) {
compilation.fileDependencies.add(file);
}
}
}

compilation.hooks.processAssets.tapAsync(
{
name: pluginName,
Expand Down
Loading