fix: switch from tsc watch to chokidar (#11110)
This commit is contained in:
1 parent
31384855af
commit
0deffe7b9b
5 files changed
+133
-77
No files matched your search
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"@medusajs/framework": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: switch from tsc watch to chokidar
|
||||||
@@ -82,6 +82,7 @@
|
|||||||
"@medusajs/workflows-sdk": "~2.3.1",
|
"@medusajs/workflows-sdk": "~2.3.1",
|
||||||
"@opentelemetry/api": "^1.9.0",
|
"@opentelemetry/api": "^1.9.0",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
|
"chokidar": "^3.4.2",
|
||||||
"compression": "1.7.4",
|
"compression": "1.7.4",
|
||||||
"connect-redis": "5.2.0",
|
"connect-redis": "5.2.0",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import { getConfigFile } from "@medusajs/utils"
|
import chokidar from "chokidar"
|
||||||
import type { AdminOptions, ConfigModule, Logger } from "@medusajs/types"
|
|
||||||
import { rm, access, constants, copyFile, writeFile, mkdir } from "fs/promises"
|
|
||||||
import type tsStatic from "typescript"
|
import type tsStatic from "typescript"
|
||||||
|
import { FileSystem, getConfigFile } from "@medusajs/utils"
|
||||||
|
import { rm, access, constants, copyFile } from "fs/promises"
|
||||||
|
import type { AdminOptions, ConfigModule, Logger } from "@medusajs/types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The compiler exposes the opinionated APIs for compiling Medusa
|
* The compiler exposes the opinionated APIs for compiling Medusa
|
||||||
@@ -27,7 +28,6 @@ export class Compiler {
|
|||||||
#adminSourceFolder: string
|
#adminSourceFolder: string
|
||||||
#pluginsDistFolder: string
|
#pluginsDistFolder: string
|
||||||
#backendIgnoreFiles: string[]
|
#backendIgnoreFiles: string[]
|
||||||
#pluginOptionsPath: string
|
|
||||||
#adminOnlyDistFolder: string
|
#adminOnlyDistFolder: string
|
||||||
#tsCompiler?: typeof tsStatic
|
#tsCompiler?: typeof tsStatic
|
||||||
|
|
||||||
@@ -38,10 +38,6 @@ export class Compiler {
|
|||||||
this.#adminSourceFolder = path.join(this.#projectRoot, "src/admin")
|
this.#adminSourceFolder = path.join(this.#projectRoot, "src/admin")
|
||||||
this.#adminOnlyDistFolder = path.join(this.#projectRoot, ".medusa/admin")
|
this.#adminOnlyDistFolder = path.join(this.#projectRoot, ".medusa/admin")
|
||||||
this.#pluginsDistFolder = path.join(this.#projectRoot, ".medusa/server")
|
this.#pluginsDistFolder = path.join(this.#projectRoot, ".medusa/server")
|
||||||
this.#pluginOptionsPath = path.join(
|
|
||||||
this.#projectRoot,
|
|
||||||
".medusa/server/medusa-plugin-options.json"
|
|
||||||
)
|
|
||||||
this.#backendIgnoreFiles = [
|
this.#backendIgnoreFiles = [
|
||||||
"integration-tests",
|
"integration-tests",
|
||||||
"test",
|
"test",
|
||||||
@@ -141,13 +137,14 @@ export class Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures a directory exists
|
* Returns a boolean indicating if a file extension belongs
|
||||||
|
* to a JavaScript or TypeScript file
|
||||||
*/
|
*/
|
||||||
async #ensureDir(path: string, clean?: boolean) {
|
#isScriptFile(filePath: string) {
|
||||||
if (clean) {
|
if (filePath.endsWith(".ts") && !filePath.endsWith(".d.ts")) {
|
||||||
await this.#clean(path)
|
return true
|
||||||
}
|
}
|
||||||
await mkdir(path, { recursive: true })
|
return filePath.endsWith(".js")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,24 +164,6 @@ export class Compiler {
|
|||||||
return { configFilePath, configModule }
|
return { configFilePath, configModule }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates medusa-plugin-options.json file that contains some
|
|
||||||
* metadata related to the plugin, which could be helpful
|
|
||||||
* for MedusaJS loaders during development
|
|
||||||
*/
|
|
||||||
async #createPluginOptionsFile() {
|
|
||||||
await writeFile(
|
|
||||||
this.#pluginOptionsPath,
|
|
||||||
JSON.stringify(
|
|
||||||
{
|
|
||||||
srcDir: path.join(this.#projectRoot, "src"),
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints typescript diagnostic messages
|
* Prints typescript diagnostic messages
|
||||||
*/
|
*/
|
||||||
@@ -437,7 +416,7 @@ export class Compiler {
|
|||||||
*/
|
*/
|
||||||
const { emitResult, diagnostics } = await this.#emitBuildOutput(
|
const { emitResult, diagnostics } = await this.#emitBuildOutput(
|
||||||
tsConfig,
|
tsConfig,
|
||||||
["integration-tests", "test", "unit-tests", "src/admin"],
|
this.#backendIgnoreFiles,
|
||||||
dist
|
dist
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -472,54 +451,71 @@ export class Compiler {
|
|||||||
* The "onFileChange" argument can be used to get notified when
|
* The "onFileChange" argument can be used to get notified when
|
||||||
* a file has changed.
|
* a file has changed.
|
||||||
*/
|
*/
|
||||||
async developPluginBackend(onFileChange?: () => void) {
|
async developPluginBackend(
|
||||||
await this.#ensureDir(this.#pluginsDistFolder, true)
|
transformer: (filePath: string) => Promise<string>,
|
||||||
await this.#createPluginOptionsFile()
|
onFileChange?: (
|
||||||
const ts = await this.#loadTSCompiler()
|
filePath: string,
|
||||||
|
action: "add" | "change" | "unlink"
|
||||||
|
) => void
|
||||||
|
) {
|
||||||
|
const fs = new FileSystem(this.#pluginsDistFolder)
|
||||||
|
await fs.createJson("medusa-plugin-options.json", {
|
||||||
|
srcDir: path.join(this.#projectRoot, "src"),
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
const watcher = chokidar.watch(["."], {
|
||||||
* Format host is needed to print diagnostic messages
|
ignoreInitial: true,
|
||||||
*/
|
cwd: this.#projectRoot,
|
||||||
const formatHost: tsStatic.FormatDiagnosticsHost = {
|
ignored: [
|
||||||
getCanonicalFileName: (path) => path,
|
/(^|[\\/\\])\../,
|
||||||
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
"node_modules",
|
||||||
getNewLine: () => ts.sys.newLine,
|
"dist",
|
||||||
}
|
"static",
|
||||||
|
"private",
|
||||||
|
".medusa/**/*",
|
||||||
|
...this.#backendIgnoreFiles,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
watcher.on("add", async (file) => {
|
||||||
* Creating a watcher compiler host to watch files and recompile
|
if (!this.#isScriptFile(file)) {
|
||||||
* them as they are changed
|
return
|
||||||
*/
|
|
||||||
const host = ts.createWatchCompilerHost(
|
|
||||||
this.#tsConfigPath,
|
|
||||||
{
|
|
||||||
outDir: this.#pluginsDistFolder,
|
|
||||||
noCheck: true,
|
|
||||||
},
|
|
||||||
ts.sys,
|
|
||||||
ts.createEmitAndSemanticDiagnosticsBuilderProgram,
|
|
||||||
(diagnostic) => this.#printDiagnostics(ts, [diagnostic]),
|
|
||||||
(diagnostic) => {
|
|
||||||
if (typeof diagnostic.messageText === "string") {
|
|
||||||
this.#logger.info(diagnostic.messageText)
|
|
||||||
} else {
|
|
||||||
this.#logger.info(
|
|
||||||
ts.formatDiagnosticsWithColorAndContext([diagnostic], formatHost)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
excludeDirectories: this.#backendIgnoreFiles,
|
|
||||||
}
|
}
|
||||||
)
|
const relativePath = path.relative(this.#projectRoot, file)
|
||||||
|
const outputPath = relativePath.replace(/\.ts$/, ".js")
|
||||||
|
|
||||||
const origPostProgramCreate = host.afterProgramCreate
|
this.#logger.info(`${relativePath} updated: Republishing changes`)
|
||||||
host.afterProgramCreate = (program) => {
|
await fs.create(outputPath, await transformer(file))
|
||||||
origPostProgramCreate!(program)
|
|
||||||
onFileChange?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
ts.createWatchProgram(host)
|
onFileChange?.(file, "add")
|
||||||
|
})
|
||||||
|
watcher.on("change", async (file) => {
|
||||||
|
if (!this.#isScriptFile(file)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const relativePath = path.relative(this.#projectRoot, file)
|
||||||
|
const outputPath = relativePath.replace(/\.ts$/, ".js")
|
||||||
|
|
||||||
|
this.#logger.info(`${relativePath} updated: Republishing changes`)
|
||||||
|
await fs.create(outputPath, await transformer(file))
|
||||||
|
|
||||||
|
onFileChange?.(file, "change")
|
||||||
|
})
|
||||||
|
watcher.on("unlink", async (file) => {
|
||||||
|
if (!this.#isScriptFile(file)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const relativePath = path.relative(this.#projectRoot, file)
|
||||||
|
const outputPath = relativePath.replace(/\.ts$/, ".js")
|
||||||
|
|
||||||
|
this.#logger.info(`${relativePath} removed: Republishing changes`)
|
||||||
|
await fs.remove(outputPath)
|
||||||
|
onFileChange?.(file, "unlink")
|
||||||
|
})
|
||||||
|
|
||||||
|
watcher.on("ready", () => {
|
||||||
|
this.#logger.info("watching for file changes")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildPluginAdminExtensions(bundler: {
|
async buildPluginAdminExtensions(bundler: {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
|
import * as swcCore from "@swc/core"
|
||||||
import { execFile } from "child_process"
|
import { execFile } from "child_process"
|
||||||
import { logger } from "@medusajs/framework/logger"
|
import { logger } from "@medusajs/framework/logger"
|
||||||
import { Compiler } from "@medusajs/framework/build-tools"
|
import { Compiler } from "@medusajs/framework/build-tools"
|
||||||
@@ -10,9 +11,18 @@ export default async function developPlugin({
|
|||||||
}) {
|
}) {
|
||||||
let isBusy = false
|
let isBusy = false
|
||||||
const compiler = new Compiler(directory, logger)
|
const compiler = new Compiler(directory, logger)
|
||||||
|
const parsedConfig = await compiler.loadTSConfigFile()
|
||||||
|
if (!parsedConfig) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const yalcBin = path.join(path.dirname(require.resolve("yalc")), "yalc.js")
|
const yalcBin = path.join(path.dirname(require.resolve("yalc")), "yalc.js")
|
||||||
|
|
||||||
await compiler.developPluginBackend(async () => {
|
/**
|
||||||
|
* Publishes the build output to the registry and updates
|
||||||
|
* installations
|
||||||
|
*/
|
||||||
|
function publishChanges() {
|
||||||
/**
|
/**
|
||||||
* Here we avoid multiple publish calls when the filesystem is
|
* Here we avoid multiple publish calls when the filesystem is
|
||||||
* changed too quickly. This might result in stale content in
|
* changed too quickly. This might result in stale content in
|
||||||
@@ -46,5 +56,47 @@ export default async function developPlugin({
|
|||||||
console.error(stderr)
|
console.error(stderr)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a given file using @swc/core
|
||||||
|
*/
|
||||||
|
async function transformFile(filePath: string) {
|
||||||
|
const output = await swcCore.transformFile(filePath, {
|
||||||
|
sourceMaps: "inline",
|
||||||
|
module: {
|
||||||
|
type: "commonjs",
|
||||||
|
strictMode: true,
|
||||||
|
noInterop: false,
|
||||||
|
},
|
||||||
|
jsc: {
|
||||||
|
externalHelpers: false,
|
||||||
|
target: "es2021",
|
||||||
|
parser: {
|
||||||
|
syntax: "typescript",
|
||||||
|
tsx: true,
|
||||||
|
decorators: true,
|
||||||
|
dynamicImport: true,
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
legacyDecorator: true,
|
||||||
|
decoratorMetadata: true,
|
||||||
|
react: {
|
||||||
|
throwIfNamespace: false,
|
||||||
|
useBuiltins: false,
|
||||||
|
pragma: "React.createElement",
|
||||||
|
pragmaFrag: "React.Fragment",
|
||||||
|
importSource: "react",
|
||||||
|
runtime: "automatic",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
keepClassNames: true,
|
||||||
|
baseUrl: directory,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return output.code
|
||||||
|
}
|
||||||
|
|
||||||
|
await compiler.buildPluginBackend(parsedConfig)
|
||||||
|
await compiler.developPluginBackend(transformFile, publishChanges)
|
||||||
}
|
}
|
||||||
@@ -5766,6 +5766,7 @@ __metadata:
|
|||||||
"@types/express": ^4.17.17
|
"@types/express": ^4.17.17
|
||||||
"@types/jsonwebtoken": ^8.5.9
|
"@types/jsonwebtoken": ^8.5.9
|
||||||
awilix: ^8.0.1
|
awilix: ^8.0.1
|
||||||
|
chokidar: ^3.4.2
|
||||||
compression: 1.7.4
|
compression: 1.7.4
|
||||||
connect-redis: 5.2.0
|
connect-redis: 5.2.0
|
||||||
cookie-parser: ^1.4.6
|
cookie-parser: ^1.4.6
|
||||||
|
|||||||
Reference in new issue
Block a user