From 4b1730b2e344b839af7f9f75c76395309b24fe6f Mon Sep 17 00:00:00 2001
From: hemengke1997 <23536175@qq.com>
Date: Thu, 21 Sep 2023 17:16:11 +0800
Subject: [PATCH] refactor: decouple
---
README-en.md | 125 ------------------
__test__/utils.spec.ts | 4 +-
migrate-1.3.x-1.5.x.md | 20 +--
.../GlobalConfigBuilder.ts | 28 ++--
src/global-config/index.ts | 6 +
src/helper/AbsCacheProcessor.ts | 73 ----------
src/helper/FileCacheProcessor.ts | 81 ------------
src/helper/MemoryCacheProcessor.ts | 19 ---
src/helper/build.ts | 53 +++++---
src/helper/processor.ts | 17 ---
src/helper/utils.ts | 21 +--
src/index.ts | 88 ++++++------
.../ManifestCache.ts | 49 ++++---
src/manifest-cache/index.ts | 12 ++
src/processor/BaseCacheProcessor.ts | 41 ++++++
src/processor/FileCacheProcessor.ts | 82 ++++++++++++
src/processor/ManifestCacheProcessor.ts | 56 ++++++++
src/processor/MemoryCacheProcessor.ts | 20 +++
src/processor/processor.ts | 17 +++
19 files changed, 370 insertions(+), 442 deletions(-)
delete mode 100644 README-en.md
rename src/{helper => global-config}/GlobalConfigBuilder.ts (51%)
create mode 100644 src/global-config/index.ts
delete mode 100644 src/helper/AbsCacheProcessor.ts
delete mode 100644 src/helper/FileCacheProcessor.ts
delete mode 100644 src/helper/MemoryCacheProcessor.ts
delete mode 100644 src/helper/processor.ts
rename src/{helper => manifest-cache}/ManifestCache.ts (72%)
create mode 100644 src/manifest-cache/index.ts
create mode 100644 src/processor/BaseCacheProcessor.ts
create mode 100644 src/processor/FileCacheProcessor.ts
create mode 100644 src/processor/ManifestCacheProcessor.ts
create mode 100644 src/processor/MemoryCacheProcessor.ts
create mode 100644 src/processor/processor.ts
diff --git a/README-en.md b/README-en.md
deleted file mode 100644
index 5adad4e..0000000
--- a/README-en.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# vite-plugin-public-typescript
-
-![npm][npm-img]
-
-
-**English** | [中文](./README-zh.md)
-
-## Features
-
-- Transform typescript to javascript at runtime and build time
-- Support HMR
-- Output js with hash, no worry about cache
-- Customize esbuild build options, specify target browser ranges
-
-## Install
-
-```bash
-pnpm add vite-plugin-public-typescript -D
-```
-
-
-## Preview
-
-
-
-## Usage
-
-```typescript
-import { defineConfig } from 'vite'
-import { publicTypescript } from 'vite-plugin-public-typescript'
-
-export default defineConfig({
- plugins: [publicTypescript()],
-})
-```
-
-### SPA
-
-For `SPA`, you can inject script in vite `transformIndexHtml` hook.
-Or you can use [`vite-plugin-html`](https://github.com/vbenjs/vite-plugin-html) that make injecting easy
-
-For full example, please see [spa playground](./playground/spa/vite.config.ts)
-
-#### vite config
-
-```typescript
-import type { HtmlTagDescriptor } from 'vite'
-import { defineConfig } from 'vite'
-import { publicTypescript } from 'vite-plugin-public-typescript'
-import manifest from './publicTypescript/manifest.json'
-
-export default defineConfig({
- plugins: [
- publicTypescript(),
- {
- name: 'add-script',
- async transformIndexHtml(html) {
- const tags: HtmlTagDescriptor[] = [
- {
- tag: 'script',
- attrs: {
- src: manifest.spa,
- },
- injectTo: 'head-prepend',
- },
- ]
- return {
- html,
- tags,
- }
- },
- },
- ],
-})
-```
-
-### SSR
-
-We can easily change the html in SSR mode, because `html` is just a string template
-
-For full example, please see [ssr playground](./playground/ssr/index.html)
-
-#### vite config
-
-```typescript
-import { HtmlTagDescriptor, defineConfig } from 'vite'
-import { publicTypescript } from 'vite-plugin-public-typescript'
-
-// https://vitejs.dev/config/
-export default defineConfig({
- plugins: [
- publicTypescript({
- manifestName: 'custom-manifest',
- }),
- ],
-})
-```
-
-#### server.js
-
-```js
-import manifest from './publicTypescript/custom-manifest.json' assert { type: 'json' }
-
-const html = template
- // inject js
- .replace('', ``)
-```
-
-## Options
-
-| Parameter | Types | Default | Description |
-| -------------- | -------------- | ------------------ | ----------------------------------------------------- |
-| ssrBuild | `boolean` | `true` | whether is ssrBuild |
-| inputDir | `string` | `publicTypescript` | input public typescript dir |
-| outputDir | `string` | `/` | output public javascript dir, relative to `publicDir` |
-| manifestName | `string` | `manifest` | js manifest fileName |
-| hash | `boolean` | `true` | whether generate js fileName with hash |
-| esbuildOptions | `BuildOptions` | `{}` | esbuild BuildOptions |
-
-## License
-
-MIT
-
-
-[npm-img]: https://img.shields.io/npm/v/vite-plugin-public-typescript.svg
diff --git a/__test__/utils.spec.ts b/__test__/utils.spec.ts
index 4e4ae96..7ababec 100644
--- a/__test__/utils.spec.ts
+++ b/__test__/utils.spec.ts
@@ -9,7 +9,7 @@ import {
setEol,
validateOptions,
} from '../src/helper/utils'
-import { globalConfigBuilder } from '../src/helper/GlobalConfigBuilder'
+import { globalConfig } from '../src/global-config'
describe('vite-plugin-public-typescript', () => {
it('should return true when filePath is a public typescript file', () => {
@@ -71,7 +71,7 @@ describe('vite-plugin-public-typescript', () => {
})
test('should get globalConfig', () => {
- expect(() => globalConfigBuilder.get()).not.toThrowError()
+ expect(() => globalConfig.get()).not.toThrowError()
})
test('should extract hash', () => {
diff --git a/migrate-1.3.x-1.5.x.md b/migrate-1.3.x-1.5.x.md
index bc0379f..4f67bf3 100644
--- a/migrate-1.3.x-1.5.x.md
+++ b/migrate-1.3.x-1.5.x.md
@@ -4,23 +4,15 @@
**更新点:**
-- vite环境下,支持内存编译模式,默认不会在 `publicDir` 下生成 `js` 文件了
+- vite环境下,支持内存编译模式( `destination` 配置项),不会在 `publicDir` 下生成 `js` 文件了
- 导出了 `injectScripts` 插件,用于插入脚本(尽量使用这个,不要再使用 `vite-plugin-html` 插脚本了)
- 修复了一些奇怪的bug
-## 使用 `@minko-fe/vite-config` ?
-
-为了方便,以下称为 `vite-config`
-
-此情况下:
-1. 升级 `vite-config` 至最新版本
-2. 从 `vite-config` 中引入 `injectScripts` 替换 `vite-plugin-html`
-3. 注意 `publicTypescript` 的配置项。新版本默认 `inputDir: 'public-typescript'`(旧版本是 `publicTypescript`)。如果已经设置 `inputDir`,则不需要修改
-
## 直接使用?
-跟上述操作一样,除了第一条
+1. 从 `vite-config` 中引入 `injectScripts` 替换 `vite-plugin-html`
+2. 注意 `publicTypescript` 的配置项。新版本默认 `inputDir: 'public-typescript'`(旧版本是 `publicTypescript`)。如果已经设置 `inputDir`,则不需要修改
## 与 `modern-flexible` 一起使用?
@@ -28,9 +20,5 @@
## 参考
-### with vite-config
-[playground]([./playground/spa/vite.config.ts](https://github.com/hemengke1997/util/blob/master/playground/spa/vite.config.ts))
-
-
-### only with vite
+### with vite
[playground](./playground/spa/vite.config.ts)
diff --git a/src/helper/GlobalConfigBuilder.ts b/src/global-config/GlobalConfigBuilder.ts
similarity index 51%
rename from src/helper/GlobalConfigBuilder.ts
rename to src/global-config/GlobalConfigBuilder.ts
index 48fefd4..ce1896c 100644
--- a/src/helper/GlobalConfigBuilder.ts
+++ b/src/global-config/GlobalConfigBuilder.ts
@@ -1,30 +1,30 @@
import path from 'path'
import type { ResolvedConfig } from 'vite'
import type { VPPTPluginOptions } from '..'
-import type { AbsCacheProcessor } from './AbsCacheProcessor'
-import type { ManifestCache } from './ManifestCache'
+import type { BaseCacheProcessor } from '../processor/BaseCacheProcessor'
+import type { CacheValue, ManifestCache } from '../manifest-cache/ManifestCache'
-export type UserConfig =
+export type UserConfig =
| {
- cache: ManifestCache
- tsFilesGlob: string[]
+ manifestCache: ManifestCache
+ originFilesGlob: string[]
viteConfig: ResolvedConfig
- cacheProcessor: AbsCacheProcessor
+ cacheProcessor: BaseCacheProcessor
} & Required
-export type TGlobalConfig = UserConfig & {
+export type GlobalConfig = UserConfig & {
absOutputDir: string
absInputDir: string
}
-class GlobalConfigBuilder {
- private globalConfig: TGlobalConfig
+export class GlobalConfigBuilder {
+ private globalConfig: GlobalConfig
constructor() {
- this.globalConfig = {} as TGlobalConfig
+ this.globalConfig = {} as GlobalConfig
}
- init(c: UserConfig) {
+ init(c: UserConfig) {
const root = c.viteConfig.root || process.cwd()
const absOutputDir = path.join(root, c.outputDir)
const absInputDir = path.join(root, c.inputDir)
@@ -41,7 +41,7 @@ class GlobalConfigBuilder {
return this.globalConfig
}
- set(c: UserConfig) {
+ set(c: UserConfig) {
this.globalConfig = {
...this.get(),
...c,
@@ -49,7 +49,3 @@ class GlobalConfigBuilder {
return this
}
}
-
-const globalConfigBuilder = new GlobalConfigBuilder()
-
-export { globalConfigBuilder }
diff --git a/src/global-config/index.ts b/src/global-config/index.ts
new file mode 100644
index 0000000..34bb600
--- /dev/null
+++ b/src/global-config/index.ts
@@ -0,0 +1,6 @@
+import type { CacheValueEx } from '../manifest-cache'
+import { GlobalConfigBuilder } from './GlobalConfigBuilder'
+
+const globalConfig = new GlobalConfigBuilder()
+
+export { globalConfig }
diff --git a/src/helper/AbsCacheProcessor.ts b/src/helper/AbsCacheProcessor.ts
deleted file mode 100644
index eaff5f5..0000000
--- a/src/helper/AbsCacheProcessor.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { normalizePath } from 'vite'
-import createDebug from 'debug'
-import type { ManifestCache } from './ManifestCache'
-import type { TGlobalConfig } from './GlobalConfigBuilder'
-
-const debug = createDebug('vite-plugin-public-typescript:AbsCacheProcessor ===> ')
-
-export type BuildEndArgs = {
- tsFileName: string
- jsFileNameWithHash: string
- code: string
- contentHash: string
-}
-
-export interface IDeleteFile {
- tsFileName: string
- jsFileName?: string
- /**
- * if true, will not write file to disk
- */
- silent?: boolean
-}
-
-export interface IAddFile {
- code?: string
- tsFileName: string
- contentHash: string
-}
-
-export abstract class AbsCacheProcessor {
- cache: ManifestCache
- abstract deleteOldJs(args: IDeleteFile): Promise
- abstract addNewJs(args: IAddFile): Promise
-
- constructor(cache: ManifestCache) {
- this.cache = cache
- }
-
- async onTsBuildEnd(args: BuildEndArgs) {
- const { tsFileName, jsFileNameWithHash, code, contentHash } = args
-
- debug('onTsBuildEnd:', args)
-
- await this.deleteOldJs({ tsFileName, jsFileName: jsFileNameWithHash, silent: true })
-
- await this.addNewJs({ code, tsFileName, contentHash })
- }
-
- setCache(args: IAddFile, config: TGlobalConfig): string {
- const { contentHash, code = '', tsFileName } = args
- const {
- outputDir,
- viteConfig: { base },
- } = config
-
- function getOutputPath(p: string, hash?: string) {
- hash = hash ? `.${hash}` : ''
- return normalizePath(`${p}/${tsFileName}${hash}.js`)
- }
-
- const path = getOutputPath(base + outputDir, contentHash)
-
- this.cache.set({
- [tsFileName]: {
- path,
- _code: code,
- _hash: contentHash,
- },
- })
-
- return this.cache.get()[tsFileName]._pathToDisk || ''
- }
-}
diff --git a/src/helper/FileCacheProcessor.ts b/src/helper/FileCacheProcessor.ts
deleted file mode 100644
index 4b45e66..0000000
--- a/src/helper/FileCacheProcessor.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import path from 'path'
-import fs from 'fs-extra'
-import { normalizePath } from 'vite'
-import createDebug from 'debug'
-import { assert } from './assert'
-import { globalConfigBuilder } from './GlobalConfigBuilder'
-import { AbsCacheProcessor } from './AbsCacheProcessor'
-import type { IAddFile, IDeleteFile } from './AbsCacheProcessor'
-import { findAllOldJsFile, writeFile } from './utils'
-import type { ManifestCache } from './ManifestCache'
-
-const debug = createDebug('FileCacheProcessor ===> ')
-
-// file-based processor
-// the final output dir is base on `publicDir`
-export class FileCacheProcessor extends AbsCacheProcessor {
- constructor(cache: ManifestCache) {
- super(cache)
- }
-
- async deleteOldJs(args: IDeleteFile): Promise {
- const { tsFileName, jsFileName = '' } = args
-
- const {
- outputDir,
- viteConfig: { publicDir },
- } = globalConfigBuilder.get()
-
- let oldFiles: string[] = []
- try {
- fs.ensureDirSync(path.join(publicDir, outputDir))
- oldFiles = await findAllOldJsFile({
- outputDir,
- publicDir,
- tsFileNames: [tsFileName],
- })
- } catch (e) {
- console.error(e)
- }
-
- debug('deleteOldJsFile - oldFiles:', oldFiles)
-
- assert(Array.isArray(oldFiles))
-
- debug('cache:', this.cache.get())
-
- if (oldFiles.length) {
- for (const f of oldFiles) {
- if (path.parse(f).name === jsFileName) {
- debug('deleteOldJsFile - skip file:', jsFileName)
- continue
- } // skip repeat js file
- if (fs.existsSync(f)) {
- debug('deleteOldJsFile - file exists:', f, tsFileName)
- this.cache.remove(tsFileName)
- debug('deleteOldJsFile - cache removed:', tsFileName)
- fs.remove(f)
- debug('deleteOldJsFile -file removed:', f)
- }
- }
- } else {
- this.cache.remove(tsFileName)
- debug('cache removed:', tsFileName)
- }
- }
-
- async addNewJs(args: IAddFile): Promise {
- const { code = '' } = args
- const {
- viteConfig: { publicDir },
- } = globalConfigBuilder.get()
-
- const pathToDisk = this.setCache(args, globalConfigBuilder.get())
-
- const jsFilePath = normalizePath(path.join(publicDir, pathToDisk))
-
- fs.ensureDirSync(path.dirname(jsFilePath))
-
- writeFile(jsFilePath, code)
- }
-}
diff --git a/src/helper/MemoryCacheProcessor.ts b/src/helper/MemoryCacheProcessor.ts
deleted file mode 100644
index fa5416b..0000000
--- a/src/helper/MemoryCacheProcessor.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { AbsCacheProcessor } from './AbsCacheProcessor'
-import type { IAddFile, IDeleteFile } from './AbsCacheProcessor'
-import { globalConfigBuilder } from './GlobalConfigBuilder'
-import type { ManifestCache } from './ManifestCache'
-
-export class MemoryCacheProcessor extends AbsCacheProcessor {
- constructor(cache: ManifestCache) {
- super(cache)
- }
-
- async deleteOldJs(args: IDeleteFile): Promise {
- const { tsFileName } = args
- this.cache.remove(tsFileName)
- }
-
- async addNewJs(args: IAddFile): Promise {
- this.setCache(args, globalConfigBuilder.get())
- }
-}
diff --git a/src/helper/build.ts b/src/helper/build.ts
index 4e386bb..721683e 100644
--- a/src/helper/build.ts
+++ b/src/helper/build.ts
@@ -5,9 +5,9 @@ import { build as esbuild } from 'esbuild'
import createDebug from 'debug'
import type { VPPTPluginOptions } from '..'
import { name } from '../../package.json'
-import { globalConfigBuilder } from './GlobalConfigBuilder'
+import type { BaseCacheProcessor } from '../processor/BaseCacheProcessor'
+import { globalConfig } from '../global-config'
import { getContentHash } from './utils'
-import type { BuildEndArgs } from './AbsCacheProcessor'
const debug = createDebug('vite-plugin-public-typescript:build ===> ')
@@ -70,7 +70,7 @@ export async function esbuildTypescript(buildOptions: IBuildOptions) {
const define = transformEnvToDefine(viteConfig)
- debug('esbuild define:', define)
+ debug('tsFile:', filePath, 'esbuild define:', define)
let res: BuildResult
try {
@@ -101,38 +101,49 @@ export async function esbuildTypescript(buildOptions: IBuildOptions) {
return code
}
-export async function build(options: { filePath: string }, onBuildEnd?: (args: BuildEndArgs) => Promise) {
+export async function build(options: { filePath: string }, onBuildEnd?: BaseCacheProcessor['onTsBuildEnd']) {
const { filePath } = options
- const globalConfig = globalConfigBuilder.get()
+ const getGlobalConfig = globalConfig.get()
const originFileName = path.basename(filePath, path.extname(filePath))
let contentHash = ''
- let fileNameWithHash = originFileName
+ let compiledFileName = originFileName
- const code = (await esbuildTypescript({ filePath, ...globalConfig })) || ''
+ const code = (await esbuildTypescript({ filePath, ...getGlobalConfig })) || ''
- if (globalConfig.hash) {
- contentHash = getContentHash(code, globalConfig.hash)
- fileNameWithHash = `${originFileName}.${contentHash}`
+ if (getGlobalConfig.hash) {
+ contentHash = getContentHash(code, getGlobalConfig.hash)
+ compiledFileName = `${originFileName}.${contentHash}`
}
- debug('before onBuildEnd cache:', globalConfig.cache.get())
+ debug('before onBuildEnd manifest-cache:', getGlobalConfig.manifestCache.get())
- await onBuildEnd?.({
- tsFileName: originFileName,
- jsFileNameWithHash: fileNameWithHash,
- code,
- contentHash,
- })
+ await onBuildEnd?.(
+ {
+ compiledFileName,
+ originFileName,
+ silent: true,
+ },
+ { contentHash, code, silent: false, originFileName },
+ )
- debug('after onBuildEnd cache:', globalConfig.cache.get())
+ debug('after onBuildEnd manifest-cache:', getGlobalConfig.manifestCache.get())
}
-export async function buildAll(tsFilesGlob: string[]) {
- const { cacheProcessor } = globalConfigBuilder.get()
+export async function buildAllOnce(tsFilesGlob: string[]) {
+ const { cacheProcessor } = globalConfig.get()
+
+ const toBuildList: (() => Promise)[] = []
for (const file of tsFilesGlob) {
- await build({ filePath: file }, (args) => cacheProcessor.onTsBuildEnd(args))
+ toBuildList.push(() =>
+ build({ filePath: file }, (deleteArgs, addArgs) =>
+ cacheProcessor.onTsBuildEnd({ ...deleteArgs, silent: true }, { ...addArgs, silent: true }),
+ ),
+ )
}
+
+ await Promise.all(toBuildList.map((fn) => fn()))
+ cacheProcessor.manifestCache.writeManifestJSON()
}
diff --git a/src/helper/processor.ts b/src/helper/processor.ts
deleted file mode 100644
index 3e28274..0000000
--- a/src/helper/processor.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import type { VPPTPluginOptions } from '..'
-import type { AbsCacheProcessor } from './AbsCacheProcessor'
-import { FileCacheProcessor } from './FileCacheProcessor'
-import type { ManifestCache } from './ManifestCache'
-import { MemoryCacheProcessor } from './MemoryCacheProcessor'
-
-export function initCacheProcessor(options: Required, cache: ManifestCache): AbsCacheProcessor {
- const { destination } = options
- switch (destination) {
- case 'file':
- return new FileCacheProcessor(cache)
- case 'memory':
- return new MemoryCacheProcessor(cache)
- default:
- return new MemoryCacheProcessor(cache)
- }
-}
diff --git a/src/helper/utils.ts b/src/helper/utils.ts
index c29db41..79f268e 100644
--- a/src/helper/utils.ts
+++ b/src/helper/utils.ts
@@ -6,7 +6,7 @@ import fs from 'fs-extra'
import createDebug from 'debug'
import glob from 'tiny-glob'
import type { VPPTPluginOptions } from '..'
-import { globalConfigBuilder } from './GlobalConfigBuilder'
+import { globalConfig } from '../global-config'
import { assert } from './assert'
const debug = createDebug('vite-plugin-public-typescript:util ===> ')
@@ -28,9 +28,12 @@ export function isPublicTypescript(args: { filePath: string; inputDir: string; r
}
export function _isPublicTypescript(filePath: string) {
- const globalConfig = globalConfigBuilder.get()
- assert(!!globalConfig)
- return isPublicTypescript({ filePath, inputDir: globalConfig.inputDir, root: globalConfig.viteConfig.root })
+ assert(!!globalConfig.get())
+ return isPublicTypescript({
+ filePath,
+ inputDir: globalConfig.get().inputDir,
+ root: globalConfig.get().viteConfig.root,
+ })
}
export function isWindows() {
@@ -95,7 +98,7 @@ export function writeFile(filename: string, content: string): void {
const newContent = setEol(content)
if (fs.existsSync(filename)) {
- const { hash } = globalConfigBuilder.get()
+ const { hash } = globalConfig.get()
if (extractHashFromFileName(filename, hash)) {
// if filename has hash, skip write file
debug('skip writeFile, filename has hash')
@@ -173,13 +176,13 @@ export function getInputDir(resolvedRoot: string, originInputDir: string, suffix
return normalizePath(path.resolve(resolvedRoot, `${originInputDir}${suffix}`))
}
-export async function findAllOldJsFile(args: { publicDir: string; outputDir: string; tsFileNames: string[] }) {
- const { publicDir, outputDir, tsFileNames } = args
+export async function findAllOldJsFile(args: { publicDir: string; outputDir: string; originFilesName: string[] }) {
+ const { publicDir, outputDir, originFilesName } = args
const dir = path.join(publicDir, outputDir)
const oldFiles: string[] = []
if (fs.existsSync(dir)) {
- for (const tsFileName of tsFileNames) {
- const old = await glob(normalizePath(path.join(publicDir, `${outputDir}/${tsFileName}.?(*.)js`)))
+ for (const originFileName of originFilesName) {
+ const old = await glob(normalizePath(path.join(publicDir, `${outputDir}/${originFileName}.?(*.)js`)))
if (old.length) {
oldFiles.push(...old)
}
diff --git a/src/index.ts b/src/index.ts
index afb26ad..4274ecb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -21,12 +21,12 @@ import {
removeOldJsFiles,
validateOptions,
} from './helper/utils'
-import { build, buildAll, esbuildTypescript } from './helper/build'
+import { build, buildAllOnce, esbuildTypescript } from './helper/build'
import { assert } from './helper/assert'
-import { globalConfigBuilder } from './helper/GlobalConfigBuilder'
-import { initCacheProcessor } from './helper/processor'
-import { ManifestCache } from './helper/ManifestCache'
import { getScriptInfo, nodeIsElement, traverseHtml } from './helper/html'
+import { initCacheProcessor } from './processor/processor'
+import { globalConfig } from './global-config'
+import { manifestCache } from './manifest-cache'
const debug = createDebug('vite-plugin-public-typescript:index ===> ')
@@ -93,15 +93,6 @@ export const DEFAULT_OPTIONS: Required = {
let previousOpts: VPPTPluginOptions
-type CacheItemType = {
- path: string
- _code?: string
- _hash?: string
- _pathToDisk?: string
-}
-
-const cache = new ManifestCache()
-
export default function publicTypescript(options: VPPTPluginOptions = {}) {
const opts = {
...DEFAULT_OPTIONS,
@@ -125,36 +116,36 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
fs.ensureDirSync(getInputDir(resolvedRoot, opts.inputDir))
- const tsFilesGlob = await glob(getInputDir(resolvedRoot, opts.inputDir, `/*.ts`), {
+ const originFilesGlob = await glob(getInputDir(resolvedRoot, opts.inputDir, `/*.ts`), {
cwd: resolvedRoot,
absolute: true,
})
- const cacheProcessor = initCacheProcessor(opts, cache)
+ const cacheProcessor = initCacheProcessor(opts, manifestCache)
- globalConfigBuilder.init({
- cache,
- tsFilesGlob,
+ globalConfig.init({
+ manifestCache,
+ originFilesGlob,
viteConfig,
cacheProcessor,
...opts,
})
- cache.setManifestPath(normalizePath(`${globalConfigBuilder.get().absInputDir}/${opts.manifestName}.json`))
+ manifestCache.setManifestPath(normalizePath(`${globalConfig.get().absInputDir}/${opts.manifestName}.json`))
- cache.beforeChange = (value) => {
+ // no need to set `_pathToDisk` manually anymore
+ manifestCache.setBeforeSet((value) => {
if (value?.path) {
value._pathToDisk = removeBase(value.path, viteConfig.base)
}
- }
-
- disableManifestHmr(c, cache.getManifestPath())
+ return value
+ })
- debug('cache manifestPath:', cache.getManifestPath())
+ disableManifestHmr(c, manifestCache.getManifestPath())
- debug('cache:', cache.get())
+ debug('manifestCache manifestPath:', manifestCache.getManifestPath())
- assert(cache.getManifestPath().includes('.json'))
+ assert(manifestCache.getManifestPath().includes('.json'))
},
configureServer(server) {
@@ -165,7 +156,7 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
const { ws } = server
try {
- const watcher = new Watcher(globalConfigBuilder.get().absInputDir, {
+ const watcher = new Watcher(globalConfig.get().absInputDir, {
ignoreInitial: true,
recursive: true,
renameDetection: true,
@@ -177,7 +168,7 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
if (_isPublicTypescript(filePath)) {
const fileName = path.parse(filePath).name
debug('unlink:', fileName)
- await globalConfigBuilder.get().cacheProcessor.deleteOldJs({ tsFileName: fileName })
+ await globalConfig.get().cacheProcessor.deleteOldJs({ originFileName: fileName })
reloadPage(ws)
}
}
@@ -185,7 +176,7 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
async function handleFileAdded(filePath: string) {
if (_isPublicTypescript(filePath)) {
debug('file added:', filePath)
- await build({ filePath }, (args) => globalConfigBuilder.get().cacheProcessor.onTsBuildEnd(args))
+ await build({ filePath }, (...args) => globalConfig.get().cacheProcessor.onTsBuildEnd(...args))
reloadPage(ws)
}
}
@@ -217,40 +208,49 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
previousOpts = opts
- const manifestPath = cache.getManifestPath()
+ const manifestPath = manifestCache.getManifestPath()
fs.ensureFileSync(manifestPath)
- const parsedCacheJson = cache.readManifestFile()
+ const parsedCacheJson = manifestCache.readManifestFile()
debug('buildStart - parsedCacheJson:', parsedCacheJson)
if (isEmptyObject(parsedCacheJson)) {
// write empty json object to manifest.json
- cache.writeManifestJSON()
+ manifestCache.writeManifestJSON()
}
- const { tsFilesGlob } = globalConfigBuilder.get()
+ const { originFilesGlob } = globalConfig.get()
- const tsFileNames = tsFilesGlob.map((file) => path.parse(file).name)
+ const originFilesName = originFilesGlob.map((file) => path.parse(file).name)
- debug('buildStart - tsFilesGlob:', tsFilesGlob)
- debug('buildStart - tsFileNames:', tsFileNames)
+ debug('buildStart - originFilesGlob:', originFilesGlob)
+ debug('buildStart - originFilesName:', originFilesName)
if (opts.destination === 'memory') {
const oldFiles = await findAllOldJsFile({
outputDir: opts.outputDir,
publicDir: viteConfig.publicDir,
- tsFileNames,
+ originFilesName,
})
removeOldJsFiles(oldFiles)
+
+ // if dir is empty, delete it
+ const dir = path.join(viteConfig.publicDir, opts.outputDir)
+ if (fs.existsSync(dir) && opts.outputDir !== '/') {
+ const files = fs.readdirSync(dir)
+ if (!files.length) {
+ fs.removeSync(dir)
+ }
+ }
}
- await buildAll(tsFilesGlob)
+ buildAllOnce(originFilesGlob)
},
generateBundle() {
if (opts.destination === 'memory') {
- const c = cache.get()
+ const c = manifestCache.get()
Object.keys(c).forEach((key) => {
this.emitFile({
type: 'asset',
@@ -274,8 +274,8 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
const { src, vppt } = getScriptInfo(node)
if (vppt?.name && src?.value) {
- const c = cache.get()
- let cacheItem = cache.findCacheItemByPath(src.value)
+ const c = manifestCache.get()
+ let cacheItem = manifestCache.findCacheItemByPath(src.value)
if (!cacheItem) {
const fileName = path.basename(src.value).split('.')[0]
@@ -314,7 +314,7 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
if (_isPublicTypescript(file)) {
debug('hmr:', file)
- await build({ filePath: file }, (args) => globalConfigBuilder.get().cacheProcessor.onTsBuildEnd(args))
+ await build({ filePath: file }, (...args) => globalConfig.get().cacheProcessor.onTsBuildEnd(...args))
reloadPage(server.ws)
@@ -327,7 +327,7 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
apply: 'serve',
enforce: 'post',
load(id) {
- const cacheItem = cache.findCacheItemByPath(id)
+ const cacheItem = manifestCache.findCacheItemByPath(id)
if (cacheItem) {
return {
code: '',
@@ -339,7 +339,7 @@ export default function publicTypescript(options: VPPTPluginOptions = {}) {
server.middlewares.use((req, res, next) => {
try {
if (req?.url?.startsWith('/') && req?.url?.endsWith('.js')) {
- const cacheItem = cache.findCacheItemByPath(req.url)
+ const cacheItem = manifestCache.findCacheItemByPath(req.url)
if (cacheItem) {
return send(req, res, addCodeHeader(cacheItem._code || ''), 'js', {
cacheControl: 'max-age=31536000,immutable',
diff --git a/src/helper/ManifestCache.ts b/src/manifest-cache/ManifestCache.ts
similarity index 72%
rename from src/helper/ManifestCache.ts
rename to src/manifest-cache/ManifestCache.ts
index 3776b80..0921170 100644
--- a/src/helper/ManifestCache.ts
+++ b/src/manifest-cache/ManifestCache.ts
@@ -1,17 +1,14 @@
import path from 'path'
import fs from 'fs-extra'
-import type { ApplyData } from 'on-change'
import onChange from 'on-change'
import createDebug from 'debug'
-import { writeFile } from './utils'
+import { writeFile } from '../helper/utils'
const debug = createDebug('vite-plugin-public-typescript:ManifestCache ===> ')
type PathOnlyCache = Record
-type _OnChangeType = (path: string, value: ValueType, previousValue: ValueType, applyData: ApplyData) => void
-
-export interface IManifestConstructor {
+export interface ManifestConstructor {
write?: boolean
}
@@ -20,40 +17,38 @@ export interface IManifestConstructor {
* {
* fileName: {
* path: '/some-path',
- * _code: 'compiled code'
* // and more
* }
* }
*/
-export type TCacheValue = {
+export type CacheValue = {
path: string
} & Partial<{ [_key: string]: string }>
-export type TDefaultCache = {
+export type CacheObject = {
[fileName in string]: V
}
-const DEFAULT_OPTIONS: IManifestConstructor = {
+const DEFAULT_OPTIONS: ManifestConstructor = {
write: true,
}
-export class ManifestCache = TDefaultCache> {
+export class ManifestCache = CacheObject> {
private cache: U
private manifestPath = ''
+ private beforeSet = (value: T | undefined) => {
+ return value
+ }
- beforeChange: (value: T | undefined) => void = () => {}
-
- constructor(options?: IManifestConstructor) {
+ constructor(options?: ManifestConstructor) {
options = {
...DEFAULT_OPTIONS,
...options,
}
this.cache = onChange({} as U, (...args) => {
- debug('cache changed:', this.cache)
-
- this.beforeChange(args[1] as T)
+ debug('cache changed:', this.cache, 'onChange args:', args)
if (options!.write) {
this.writeManifestJSON()
@@ -65,6 +60,11 @@ export class ManifestCache {
+ sortedCache[k] = c[k]
+ })
+ return sortedCache
+ }
+
writeManifestJSON() {
const targetPath = this.getManifestPath()
const cacheObj = this.getManifestJson()
- const orderdCache = Object.assign({}, cacheObj)
+ const orderdCache = this.sortObjectByKey(cacheObj)
writeFile(targetPath, JSON.stringify(orderdCache || {}, null, 2))
diff --git a/src/manifest-cache/index.ts b/src/manifest-cache/index.ts
new file mode 100644
index 0000000..b0c1060
--- /dev/null
+++ b/src/manifest-cache/index.ts
@@ -0,0 +1,12 @@
+import type { CacheValue } from './ManifestCache'
+import { ManifestCache } from './ManifestCache'
+
+export type CacheValueEx = {
+ _code?: string
+ _hash?: string
+ _pathToDisk?: string
+} & CacheValue
+
+const manifestCache = new ManifestCache()
+
+export { manifestCache }
diff --git a/src/processor/BaseCacheProcessor.ts b/src/processor/BaseCacheProcessor.ts
new file mode 100644
index 0000000..772ba2d
--- /dev/null
+++ b/src/processor/BaseCacheProcessor.ts
@@ -0,0 +1,41 @@
+import createDebug from 'debug'
+import type { CacheValue, ManifestCache } from '../manifest-cache/ManifestCache'
+
+const debug = createDebug('vite-plugin-public-typescript:BaseCacheProcessor ===> ')
+
+export interface DeleteFileArgs {
+ originFileName: string
+ /**
+ * if true, will not write file to disk
+ */
+ silent?: boolean
+ compiledFileName?: string
+}
+
+export interface AddFileArgs {
+ originFileName: string
+ contentHash: string
+ silent?: boolean
+ code?: string
+}
+
+export abstract class BaseCacheProcessor<
+ T extends CacheValue = CacheValue,
+ U extends ManifestCache = ManifestCache,
+> {
+ manifestCache: U
+ abstract deleteOldJs(args: DeleteFileArgs): Promise
+ abstract addNewJs(args: AddFileArgs): Promise
+
+ constructor(manifestCache: U) {
+ this.manifestCache = manifestCache
+ }
+
+ async onTsBuildEnd(deleteArgs: DeleteFileArgs, addArgs: AddFileArgs) {
+ debug('onTsBuildEnd deleteArgs:', deleteArgs)
+ debug('onTsBuildEnd addArgs:', addArgs)
+
+ await this.deleteOldJs(deleteArgs)
+ await this.addNewJs(addArgs)
+ }
+}
diff --git a/src/processor/FileCacheProcessor.ts b/src/processor/FileCacheProcessor.ts
new file mode 100644
index 0000000..cb4a9e7
--- /dev/null
+++ b/src/processor/FileCacheProcessor.ts
@@ -0,0 +1,82 @@
+import path from 'path'
+import fs from 'fs-extra'
+import { normalizePath } from 'vite'
+import createDebug from 'debug'
+import { findAllOldJsFile, writeFile } from '../helper/utils'
+import { assert } from '../helper/assert'
+import type { ManifestCache } from '../manifest-cache/ManifestCache'
+import type { CacheValueEx } from '../manifest-cache'
+import { globalConfig } from '../global-config'
+import type { AddFileArgs, DeleteFileArgs } from './ManifestCacheProcessor'
+import { ManifestCacheProcessor } from './ManifestCacheProcessor'
+
+const debug = createDebug('FileCacheProcessor ===> ')
+
+// file-based processor
+// the final output dir is base on `publicDir`
+export class FileCacheProcessor extends ManifestCacheProcessor {
+ constructor(manifestCache: ManifestCache) {
+ super(manifestCache)
+ }
+
+ async deleteOldJs(args: DeleteFileArgs): Promise {
+ const { originFileName, compiledFileName = '', silent } = args
+
+ const {
+ outputDir,
+ viteConfig: { publicDir },
+ } = globalConfig.get()
+
+ let oldFiles: string[] = []
+ try {
+ fs.ensureDirSync(path.join(publicDir, outputDir))
+ oldFiles = await findAllOldJsFile({
+ outputDir,
+ publicDir,
+ originFilesName: [originFileName],
+ })
+ } catch (e) {
+ console.error(e)
+ }
+
+ debug('deleteOldJsFile - oldFiles:', oldFiles)
+
+ assert(Array.isArray(oldFiles))
+
+ debug('manifestCache:', this.manifestCache.get())
+
+ if (oldFiles.length) {
+ for (const f of oldFiles) {
+ if (path.parse(f).name === compiledFileName) {
+ debug('deleteOldJsFile - skip file:', compiledFileName)
+ continue
+ } // skip repeat js file
+ if (fs.existsSync(f)) {
+ debug('deleteOldJsFile - file exists:', f, originFileName)
+ this.manifestCache.remove(originFileName, { silent })
+ debug('deleteOldJsFile - manifestCache removed:', originFileName)
+ fs.remove(f)
+ debug('deleteOldJsFile -file removed:', f)
+ }
+ }
+ } else {
+ this.manifestCache.remove(originFileName, { silent })
+ debug('manifestCache removed:', originFileName)
+ }
+ }
+
+ async addNewJs(args: AddFileArgs): Promise {
+ const { code = '' } = args
+ const {
+ viteConfig: { publicDir },
+ } = globalConfig.get()
+
+ const pathToDisk = this.setCache(args, globalConfig.get())
+
+ const jsFilePath = normalizePath(path.join(publicDir, pathToDisk))
+
+ fs.ensureDirSync(path.dirname(jsFilePath))
+
+ writeFile(jsFilePath, code)
+ }
+}
diff --git a/src/processor/ManifestCacheProcessor.ts b/src/processor/ManifestCacheProcessor.ts
new file mode 100644
index 0000000..4ccfbbe
--- /dev/null
+++ b/src/processor/ManifestCacheProcessor.ts
@@ -0,0 +1,56 @@
+import { normalizePath } from 'vite'
+// import createDebug from 'debug'
+import type { ManifestCache } from '../manifest-cache/ManifestCache'
+import type { CacheValueEx } from '../manifest-cache'
+import type { GlobalConfig } from '../global-config/GlobalConfigBuilder'
+import { BaseCacheProcessor } from './BaseCacheProcessor'
+
+// const debug = createDebug('vite-plugin-public-typescript:ManifestCacheProcessor ===> ')
+
+export interface DeleteFileArgs {
+ originFileName: string
+ /**
+ * if true, will not write file to disk
+ */
+ silent?: boolean
+ compiledFileName?: string
+}
+
+export interface AddFileArgs {
+ originFileName: string
+ contentHash: string
+ silent?: boolean
+ code?: string
+}
+
+export abstract class ManifestCacheProcessor extends BaseCacheProcessor {
+ constructor(manifestCache: ManifestCache) {
+ super(manifestCache)
+ this.manifestCache = manifestCache
+ }
+
+ genCacheItemPath(args: { contentHash: string; originFileName: string; outputDir: string; base: string }) {
+ const { contentHash, originFileName, outputDir, base } = args
+ const hash = contentHash ? `.${contentHash}` : ''
+ return normalizePath(`${base + outputDir}/${originFileName}${hash}.js`)
+ }
+
+ setCache(args: AddFileArgs, config: GlobalConfig) {
+ const { contentHash, originFileName, code } = args
+ const {
+ outputDir,
+ viteConfig: { base },
+ } = config
+
+ const pathWithBase = this.genCacheItemPath({ base, contentHash, originFileName, outputDir })
+
+ this.manifestCache.set({
+ [originFileName]: {
+ path: pathWithBase,
+ _code: code || '',
+ _hash: contentHash,
+ },
+ })
+ return this.manifestCache.get()[originFileName]._pathToDisk || ''
+ }
+}
diff --git a/src/processor/MemoryCacheProcessor.ts b/src/processor/MemoryCacheProcessor.ts
new file mode 100644
index 0000000..1cc0935
--- /dev/null
+++ b/src/processor/MemoryCacheProcessor.ts
@@ -0,0 +1,20 @@
+import { globalConfig } from '../global-config'
+import type { CacheValueEx } from '../manifest-cache'
+import type { ManifestCache } from '../manifest-cache//ManifestCache'
+import { ManifestCacheProcessor } from './ManifestCacheProcessor'
+import type { AddFileArgs, DeleteFileArgs } from './ManifestCacheProcessor'
+
+export class MemoryCacheProcessor extends ManifestCacheProcessor {
+ constructor(manifestCache: ManifestCache) {
+ super(manifestCache)
+ }
+
+ async deleteOldJs(args: DeleteFileArgs): Promise {
+ const { originFileName, silent } = args
+ this.manifestCache.remove(originFileName, { silent })
+ }
+
+ async addNewJs(args: AddFileArgs): Promise {
+ this.setCache(args, globalConfig.get())
+ }
+}
diff --git a/src/processor/processor.ts b/src/processor/processor.ts
new file mode 100644
index 0000000..afdc54c
--- /dev/null
+++ b/src/processor/processor.ts
@@ -0,0 +1,17 @@
+import type { VPPTPluginOptions } from '..'
+import type { CacheValueEx } from '../manifest-cache'
+import type { ManifestCache } from '../manifest-cache/ManifestCache'
+import type { ManifestCacheProcessor } from './ManifestCacheProcessor'
+import { FileCacheProcessor } from './FileCacheProcessor'
+import { MemoryCacheProcessor } from './MemoryCacheProcessor'
+
+export function initCacheProcessor(options: Required, manifestCache: ManifestCache) {
+ const { destination } = options
+
+ const processorContainer: Record = {
+ file: new FileCacheProcessor(manifestCache),
+ memory: new MemoryCacheProcessor(manifestCache),
+ }
+
+ return processorContainer[destination]
+}