Repository: gatsbyjs/gatsby
File: packages/gatsby/src/utils/gatsby-webpack-virtual-modules.ts (TypeScript)

Code before:
 * Using virtual modules allow us to avoid unnecessary I/O to write/read those modules,
 * but more importantly using virtual modules give us immediate invalidation events
 * in webpack watching mode (as opposed to debounced/delayed events when filesystem is used).
 * Instant invalidation events make it much easier to work with various state transitions
 * in response to external events that are happening while `gatsby develop` is running.
 */

interface IGatsbyWebpackVirtualModulesContext {
  writeModule: VirtualModulesPlugin["writeModule"]
}

const fileContentLookup: Record<string, string> = {}
const instances: IGatsbyWebpackVirtualModulesContext[] = []

export class GatsbyWebpackVirtualModules {
  apply(compiler): void {
    const virtualModules = new VirtualModulesPlugin(fileContentLookup)
    virtualModules.apply(compiler)
    instances.push({
      writeModule: virtualModules.writeModule.bind(virtualModules),
    })
  }
}

export function getAbsolutePathForVirtualModule(filePath: string): string {
  return path.join(process.cwd(), `_this_is_virtual_fs_path_`, filePath)
}

export function writeModule(filePath: string, fileContents: string): void {
  const adjustedFilePath = getAbsolutePathForVirtualModule(filePath)

  if (fileContentLookup[adjustedFilePath] === fileContents) {
    // we already have this, no need to cause invalidation
    return
  }

  fileContentLookup[adjustedFilePath] = fileContents

  instances.forEach(instance => {
    instance.writeModule(adjustedFilePath, fileContents)
  })
}


Review comment (bug):
The `_this_is_virtual_fs_path_` here is mostly to help with any future debugging (makes it easier to grep those keywords), it's not needed to make it work (tho it's still good to group all of those under unlikely name, because modules - be it fs or virtual share same path namespace so this also should prevent collisions - unless someone names their directory like that)

Code after:
 * Using virtual modules allow us to avoid unnecessary I/O to write/read those modules,
 * but more importantly using virtual modules give us immediate invalidation events
 * in webpack watching mode (as opposed to debounced/delayed events when filesystem is used).
 * Instant invalidation events make it much easier to work with various state transitions
 * in response to external events that are happening while `gatsby develop` is running.
 */

interface IGatsbyWebpackVirtualModulesContext {
  writeModule: VirtualModulesPlugin["writeModule"]
}

const fileContentLookup: Record<string, string> = {}
const instances: IGatsbyWebpackVirtualModulesContext[] = []

export const VIRTUAL_MODULES_BASE_PATH = `_this_is_virtual_fs_path_`

export class GatsbyWebpackVirtualModules {
  apply(compiler): void {
    const virtualModules = new VirtualModulesPlugin(fileContentLookup)
    virtualModules.apply(compiler)
    instances.push({
      writeModule: virtualModules.writeModule.bind(virtualModules),
    })
  }
}

export function getAbsolutePathForVirtualModule(filePath: string): string {
  return path.join(process.cwd(), VIRTUAL_MODULES_BASE_PATH, filePath)
}

export function writeModule(filePath: string, fileContents: string): void {
  const adjustedFilePath = getAbsolutePathForVirtualModule(filePath)

  if (fileContentLookup[adjustedFilePath] === fileContents) {
    // we already have this, no need to cause invalidation
    return
  }

  fileContentLookup[adjustedFilePath] = fileContents

  instances.forEach(instance => {
    instance.writeModule(adjustedFilePath, fileContents)
  })
}