Skip to content

Commit a3bb13f

Browse files
authored
fix: use webpack loader context to implement addWatchFile (#359)
1 parent 3b05d44 commit a3bb13f

File tree

4 files changed

+50
-17
lines changed

4 files changed

+50
-17
lines changed

src/webpack/context.ts

+19-11
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,23 @@ import type { Compilation } from 'webpack'
66
import { Parser } from 'acorn'
77
import type { UnpluginBuildContext } from '../types'
88

9-
export function createContext(compilation?: Compilation): UnpluginBuildContext {
9+
interface ContextOptions {
10+
addWatchFile(file: string): void
11+
getWatchFiles(): string[]
12+
}
13+
14+
export function contextOptionsFromCompilation(compilation: Compilation): ContextOptions {
15+
return {
16+
addWatchFile(file) {
17+
(compilation.fileDependencies ?? compilation.compilationDependencies).add(file)
18+
},
19+
getWatchFiles() {
20+
return Array.from(compilation.fileDependencies ?? compilation.compilationDependencies)
21+
},
22+
}
23+
}
24+
25+
export function createContext(options: ContextOptions, compilation?: Compilation): UnpluginBuildContext {
1026
return {
1127
parse(code: string, opts: any = {}) {
1228
return Parser.parse(code, {
@@ -17,11 +33,7 @@ export function createContext(compilation?: Compilation): UnpluginBuildContext {
1733
})
1834
},
1935
addWatchFile(id) {
20-
if (!compilation)
21-
throw new Error('unplugin/webpack: addWatchFile outside supported hooks (buildStart, buildEnd, load, transform, watchChange)');
22-
(compilation.fileDependencies ?? compilation.compilationDependencies).add(
23-
resolve(process.cwd(), id),
24-
)
36+
options.addWatchFile(resolve(process.cwd(), id))
2537
},
2638
emitFile(emittedFile) {
2739
const outFileName = emittedFile.fileName || emittedFile.name
@@ -45,11 +57,7 @@ export function createContext(compilation?: Compilation): UnpluginBuildContext {
4557
}
4658
},
4759
getWatchFiles() {
48-
if (!compilation)
49-
throw new Error('unplugin/webpack: getWatchFiles outside supported hooks (buildStart, buildEnd, load, transform, watchChange)')
50-
return Array.from(
51-
compilation.fileDependencies ?? compilation.compilationDependencies,
52-
)
60+
return options.getWatchFiles()
5361
},
5462
}
5563
}

src/webpack/index.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import VirtualModulesPlugin from 'webpack-virtual-modules'
55
import type { ResolvePluginInstance, Resolver } from 'webpack'
66
import type { ResolvedUnpluginOptions, UnpluginContext, UnpluginContextMeta, UnpluginFactory, UnpluginInstance, WebpackCompiler } from '../types'
77
import { normalizeAbsolutePath, shouldLoad, toArray, transformUse } from '../utils'
8-
import { createContext } from './context'
8+
import { contextOptionsFromCompilation, createContext } from './context'
99

1010
const TRANSFORM_LOADER = resolve(
1111
__dirname,
@@ -89,7 +89,18 @@ export function getWebpackPlugin<UserOptions = Record<string, never>>(
8989
const isEntry = requestContext.issuer === ''
9090

9191
// call hook
92-
const context = createContext()
92+
// resolveContext.fileDependencies is typed as a WriteOnlySet, so make our own copy here
93+
// so we can return it from getWatchFiles.
94+
const fileDependencies = new Set<string>()
95+
const context = createContext({
96+
addWatchFile(file) {
97+
fileDependencies.add(file)
98+
resolveContext.fileDependencies?.add(file)
99+
},
100+
getWatchFiles() {
101+
return Array.from(fileDependencies)
102+
},
103+
})
93104
let error: Error | undefined
94105
const pluginContext: UnpluginContext = {
95106
error(msg: string | Error) {
@@ -178,7 +189,7 @@ export function getWebpackPlugin<UserOptions = Record<string, never>>(
178189

179190
if (plugin.watchChange || plugin.buildStart) {
180191
compiler.hooks.make.tapPromise(plugin.name, async (compilation) => {
181-
const context = createContext(compilation)
192+
const context = createContext(contextOptionsFromCompilation(compilation), compilation)
182193
if (plugin.watchChange && (compiler.modifiedFiles || compiler.removedFiles)) {
183194
const promises: Promise<void>[] = []
184195
if (compiler.modifiedFiles) {
@@ -201,7 +212,7 @@ export function getWebpackPlugin<UserOptions = Record<string, never>>(
201212

202213
if (plugin.buildEnd) {
203214
compiler.hooks.emit.tapPromise(plugin.name, async (compilation) => {
204-
await plugin.buildEnd!.call(createContext(compilation))
215+
await plugin.buildEnd!.call(createContext(contextOptionsFromCompilation(compilation), compilation))
205216
})
206217
}
207218

src/webpack/loaders/load.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ export default async function load(this: LoaderContext<any>, source: string, map
2121
id = decodeURIComponent(id.slice(plugin.__virtualModulePrefix.length))
2222

2323
const res = await plugin.load.call(
24-
{ ...this._compilation && createContext(this._compilation) as any, ...context },
24+
{ ...createContext({
25+
addWatchFile: (file) => {
26+
this.addDependency(file)
27+
},
28+
getWatchFiles: () => {
29+
return this.getDependencies()
30+
},
31+
}, this._compilation), ...context },
2532
normalizeAbsolutePath(id),
2633
)
2734

src/webpack/loaders/transform.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ export default async function transform(this: LoaderContext<{ unpluginName: stri
2424
warn: error => this.emitWarning(typeof error === 'string' ? new Error(error) : error),
2525
}
2626
const res = await plugin.transform.call(
27-
{ ...this._compilation && createContext(this._compilation) as any, ...context },
27+
{ ...createContext({
28+
addWatchFile: (file) => {
29+
this.addDependency(file)
30+
},
31+
getWatchFiles: () => {
32+
return this.getDependencies()
33+
},
34+
}, this._compilation), ...context },
2835
source,
2936
this.resource,
3037
)

0 commit comments

Comments
 (0)