Skip to content

Commit

Permalink
feat(planner/nodejs): Implement multi-layer build for Node.js
Browse files Browse the repository at this point in the history
  • Loading branch information
pan93412 committed Jan 21, 2025
1 parent 6b343ca commit 4c59e19
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 25 deletions.
26 changes: 15 additions & 11 deletions internal/nodejs/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ type TemplateContext struct {

AppDir string

InstallCmd string
BuildCmd string
StartCmd string
InstallCmd string
BuildCmd string
BuildRuntimeCmd string // currently only used by Medusa
StartCmd string
RuntimeBaseDir string // currently only used by Medusa

Framework string
Serverless bool
Expand Down Expand Up @@ -51,14 +53,16 @@ func (c TemplateContext) Execute() (string, error) {

func getContextBasedOnMeta(meta types.PlanMeta) TemplateContext {
context := TemplateContext{
NodeVersion: meta["nodeVersion"],
AppDir: meta["appDir"],
InstallCmd: meta["installCmd"],
BuildCmd: meta["buildCmd"],
StartCmd: meta["startCmd"],
Framework: meta["framework"],
Serverless: meta["serverless"] == "true",
OutputDir: meta["outputDir"],
NodeVersion: meta["nodeVersion"],
AppDir: meta["appDir"],
InstallCmd: meta["installCmd"],
BuildCmd: meta["buildCmd"],
BuildRuntimeCmd: meta["buildRuntimeCmd"],
StartCmd: meta["startCmd"],
RuntimeBaseDir: meta["runtimeBaseDir"],
Framework: meta["framework"],
Serverless: meta["serverless"] == "true",
OutputDir: meta["outputDir"],

// The flag specific to planner/bun.
Bun: meta["bun"] == "true" || meta["packageManager"] == "bun",
Expand Down
20 changes: 20 additions & 0 deletions internal/nodejs/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,23 @@ func TestGetContextBasedOnMeta_WithOutputdirAndMPAFramework(t *testing.T) {
OutputDir: "dist",
})
}

func TestGetContextBasedOnMeta_RuntimeEnvironment(t *testing.T) {
meta := getContextBasedOnMeta(types.PlanMeta{
"nodeVersion": "16",
"installCmd": "RUN npm install",
"buildCmd": "npm run build",
"buildRuntimeCmd": "npm run build-runtime",
"startCmd": "npm run start",
"runtimeBaseDir": "/src/.output",
})

assert.Equal(t, meta, TemplateContext{
NodeVersion: "16",
InstallCmd: "RUN npm install",
BuildCmd: "npm run build",
BuildRuntimeCmd: "npm run build-runtime",
StartCmd: "npm run start",
RuntimeBaseDir: "/src/.output",
})
}
50 changes: 36 additions & 14 deletions internal/nodejs/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,27 +677,42 @@ func GetBuildCmd(ctx *nodePlanContext) string {
}
}

*cmd = optional.Some(buildCmd)
return cmd.Unwrap()
}

// GetRuntimeBaseDir gets the base directory of the runtime environment of the Node.js app.
func GetRuntimeBaseDir(ctx *nodePlanContext) string {
framework := DetermineAppFramework(ctx)

if framework == types.NodeProjectFrameworkMedusa {
return "/src/.medusa/server"
}

return ""
}

// GetBuildRuntimeCmd gets the build command to build the runtime environment of the Node.js app.
func GetBuildRuntimeCmd(ctx *nodePlanContext) string {
pkgManager := DeterminePackageManager(ctx)
framework := DetermineAppFramework(ctx)

if framework == types.NodeProjectFrameworkMedusa {
var installCmd string
switch pkgManager {
case types.NodePackageManagerNpm:
installCmd = "npm install"
return "npm install"
case types.NodePackageManagerPnpm:
installCmd = "pnpm install"
return "pnpm install"
case types.NodePackageManagerYarn:
installCmd = "yarn install"
return "yarn install"
case types.NodePackageManagerBun:
installCmd = "bun install"
return "bun install"
default:
installCmd = "yarn install"
return "yarn install"
}

// Install the dependencies in ".medusa/server" directory.
buildCmd += " && " + "cd .medusa/server" + " && " + installCmd
}

*cmd = optional.Some(buildCmd)
return cmd.Unwrap()
return ""
}

// GetMonorepoAppRoot gets the app root of the monorepo project in the Node.js project.
Expand Down Expand Up @@ -837,9 +852,6 @@ func GetStartCmd(ctx *nodePlanContext) string {
if predeployScript != "" {
startCmd = GetScriptCommand(ctx, predeployScript) + " && " + startCmd
}
if framework == types.NodeProjectFrameworkMedusa {
startCmd = "cd .medusa/server" + " && " + startCmd
}

*cmd = optional.Some(startCmd)
return cmd.Unwrap()
Expand Down Expand Up @@ -1082,6 +1094,16 @@ func GetMeta(opt GetMetaOptions) types.PlanMeta {
startCmd := GetStartCmd(ctx)
meta["startCmd"] = startCmd

runtimeBaseDir := GetRuntimeBaseDir(ctx)
if runtimeBaseDir != "" {
meta["runtimeBaseDir"] = runtimeBaseDir
}

buildRuntimeCmd := GetBuildRuntimeCmd(ctx)
if buildRuntimeCmd != "" {
meta["buildRuntimeCmd"] = buildRuntimeCmd
}

// only set outputDir if there is no start command
// (because if there is, it shouldn't be a static project)
if startCmd == "" {
Expand Down
8 changes: 8 additions & 0 deletions internal/nodejs/templates/template.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ COPY --from=build /src/{{ .AppDir }}/{{ .OutputDir }} /
FROM zeabur/caddy-static AS runtime
COPY --from=output / /usr/share/caddy
{{ end }}
{{ else if ne .RuntimeBaseDir "" }}
FROM build AS prod
COPY --from=build {{ .RuntimeBaseDir }} /app/
WORKDIR /app

EXPOSE 8080
RUN {{ .BuildRuntimeCmd }}
CMD {{ .StartCmd }}
{{ else }}
EXPOSE 8080
CMD {{ .StartCmd }}{{ end }}

0 comments on commit 4c59e19

Please sign in to comment.