From bbd98fc8bdc17fcbffb456a5ffe772bc184f22e4 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 18 Apr 2023 22:25:26 +0800 Subject: [PATCH] feat: support 3.3 imported types hmr --- src/pluginWebpack4.ts | 16 ++++++---------- src/pluginWebpack5.ts | 41 +++++++++++++++++++++++++++++++++++++++++ src/util.ts | 14 +++++++++++++- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/pluginWebpack4.ts b/src/pluginWebpack4.ts index 0952fad9..fb066987 100644 --- a/src/pluginWebpack4.ts +++ b/src/pluginWebpack4.ts @@ -5,6 +5,7 @@ import { clientCache, typeDepToSFCMap } from './resolveScript' import fs = require('fs') import { compiler as vueCompiler } from './compiler' import { descriptorCache } from './descriptorCache' +import { needHMR } from './util' const RuleSet = require('webpack/lib/RuleSet') @@ -117,16 +118,11 @@ class VueLoaderPlugin { ...rules, ] - // 3.3 HMR support - const isServer = - vueLoaderOptions.isServerBuild ?? compiler.options.target === 'node' - const isProduction = - compiler.options.mode === 'production' || - process.env.NODE_ENV === 'production' - const needsHotReload = - !isServer && !isProduction && vueLoaderOptions.hotReload !== false - - if (needsHotReload && vueCompiler.invalidateTypeCache) { + // 3.3 HMR support for imported types + if ( + needHMR(vueLoaderOptions, compiler.options) && + vueCompiler.invalidateTypeCache + ) { let watcher: any const WatchPack = require('watchpack') diff --git a/src/pluginWebpack5.ts b/src/pluginWebpack5.ts index 2d3d84c9..66fe48fa 100644 --- a/src/pluginWebpack5.ts +++ b/src/pluginWebpack5.ts @@ -1,6 +1,10 @@ import * as qs from 'querystring' import type { VueLoaderOptions } from './' import type { RuleSetRule, Compiler } from 'webpack' +import { needHMR } from './util' +import { clientCache, typeDepToSFCMap } from './resolveScript' +import { compiler as vueCompiler } from './compiler' +import { descriptorCache } from './descriptorCache' const id = 'vue-loader-plugin' const NS = 'vue-loader' @@ -225,6 +229,43 @@ class VueLoaderPlugin { ...clonedRules, ...rules, ] + + // 3.3 HMR support for imported types + if ( + needHMR(vueLoaderOptions, compiler.options) && + vueCompiler.invalidateTypeCache + ) { + compiler.hooks.afterCompile.tap(id, (compilation) => { + if (compilation.compiler === compiler) { + for (const file of typeDepToSFCMap.keys()) { + compilation.fileDependencies.add(file) + } + } + }) + compiler.hooks.watchRun.tap(id, () => { + if (!compiler.modifiedFiles) return + for (const file of compiler.modifiedFiles) { + vueCompiler.invalidateTypeCache(file) + const affectedSFCs = typeDepToSFCMap.get(file) + if (affectedSFCs) { + for (const sfc of affectedSFCs) { + // bust script resolve cache + const desc = descriptorCache.get(sfc) + if (desc) clientCache.delete(desc) + // force update importing SFC + // @ts-ignore + compiler.fileTimestamps.set(sfc, { + safeTime: Date.now(), + timestamp: Date.now(), + }) + } + } + } + for (const file of compiler.removedFiles) { + vueCompiler.invalidateTypeCache(file) + } + }) + } } } diff --git a/src/util.ts b/src/util.ts index c9ade145..1a2718fa 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,8 +1,20 @@ -import type { LoaderContext } from 'webpack' +import type { Compiler, LoaderContext } from 'webpack' import type { SFCDescriptor, CompilerOptions } from 'vue/compiler-sfc' import type { VueLoaderOptions } from '.' import * as path from 'path' +export function needHMR( + vueLoaderOptions: VueLoaderOptions, + compilerOptions: Compiler['options'] +) { + const isServer = + vueLoaderOptions.isServerBuild ?? compilerOptions.target === 'node' + const isProduction = + compilerOptions.mode === 'production' || + process.env.NODE_ENV === 'production' + return !isServer && !isProduction && vueLoaderOptions.hotReload !== false +} + export function resolveTemplateTSOptions( descriptor: SFCDescriptor, options: VueLoaderOptions