Skip to content

Commit d2be37e

Browse files
matthewrobertsoncopybara-github
authored andcommitted
Add support for idiomatic SvelteKit applications
This commit bolsters our node.js entry point logic to detect SvelteKit applications. Fixes #381 PiperOrigin-RevId: 617978159 Change-Id: I00cff183205228969add445eba491bc03b020266
1 parent cd36902 commit d2be37e

File tree

6 files changed

+186
-2
lines changed

6 files changed

+186
-2
lines changed

cmd/nodejs/npm/main.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,12 @@ func buildFn(ctx *gcp.Context) error {
144144
// If there are multiple build scripts to run, run them one-by-one so the logs are
145145
// easier to understand.
146146
for _, cmd := range buildCmds {
147+
execOpts := []gcp.ExecOption{gcp.WithUserAttribution}
148+
if nodejs.DetectSvelteKitAutoAdapter(pjs) {
149+
execOpts = append(execOpts, gcp.WithEnv(nodejs.SvelteAdapterEnv))
150+
}
147151
split := strings.Split(cmd, " ")
148-
if _, err := ctx.Exec(split, gcp.WithUserAttribution); err != nil {
152+
if _, err := ctx.Exec(split, execOpts...); err != nil {
149153
if !isCustomBuild {
150154
return fmt.Errorf(`%w
151155
NOTE: Running the default build script can be skipped by passing the empty environment variable "%s=" to the build`, err, nodejs.GoogleNodeRunScriptsEnv)

pkg/nodejs/BUILD.bazel

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ go_library(
1212
"nuxt.go",
1313
"pnpm.go",
1414
"registry.go",
15+
"sveltekit.go",
1516
"yarn.go",
1617
],
1718
importpath = "github.com/GoogleCloudPlatform/buildpacks/" + package_name(),
@@ -44,6 +45,7 @@ go_test(
4445
"nuxt_test.go",
4546
"pnpm_test.go",
4647
"registry_test.go",
48+
"sveltekit_test.go",
4749
"yarn_test.go",
4850
],
4951
data = glob(["testdata/**"]),

pkg/nodejs/npm.go

+3
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ func DefaultStartCommand(ctx *gcp.Context, pjs *PackageJSON) ([]string, error) {
218218
if nuxt, err := NuxtStartCommand(ctx); err != nil || nuxt != nil {
219219
return nuxt, err
220220
}
221+
if svelteKit, err := SvelteKitStartCommand(ctx); err != nil || svelteKit != nil {
222+
return svelteKit, err
223+
}
221224
exists, err := ctx.FileExists(ctx.ApplicationRoot(), "server.js")
222225
if err != nil {
223226
return nil, err

pkg/nodejs/nuxt_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func TestNuxtStartCommand(t *testing.T) {
5454
}
5555
_, err := safeopen.CreateBeneath(dir, "index.mjs")
5656
if err != nil {
57-
t.Fatalf("failed to create server.js: %v", err)
57+
t.Fatalf("failed to create index.mjs: %v", err)
5858
}
5959
}
6060
ctx := gcpbuildpack.NewContext(gcpbuildpack.WithApplicationRoot(home))

pkg/nodejs/sveltekit.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package nodejs
2+
3+
import (
4+
"strings"
5+
6+
gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
7+
)
8+
9+
// SvelteAdapterEnv is an env var that enables SvelteKit to detect
10+
// Google Cloud Buildpacks and use adapter-node when adapter-auto is detected
11+
// https://github.com/sveltejs/kit/blob/main/packages/adapter-auto/adapters.js
12+
const SvelteAdapterEnv = "GCP_BUILDPACKS=TRUE"
13+
14+
// DetectSvelteKitAutoAdapter returns true if the given package.json file
15+
// contains the @sveltejs/adapter-auto dependency and no others.
16+
func DetectSvelteKitAutoAdapter(p *PackageJSON) bool {
17+
// Check and reject if the package contains an adapter that is
18+
// not the @sveltejs/adapter-auto dependency.
19+
for k := range p.DevDependencies {
20+
if strings.HasPrefix(k, "@sveltejs/adapter-") && k != "@sveltejs/adapter-auto" {
21+
return false
22+
}
23+
}
24+
_, ok := p.DevDependencies["@sveltejs/adapter-auto"]
25+
return ok
26+
}
27+
28+
// SvelteKitStartCommand determines if this is a SvelteKit application and returns the command to start the
29+
// SvelteKit server. If not it is not a SvelteKit application it returns nil.
30+
func SvelteKitStartCommand(ctx *gcp.Context) ([]string, error) {
31+
configExists, err := ctx.FileExists(ctx.ApplicationRoot(), "svelte.config.js")
32+
if err != nil {
33+
return nil, err
34+
}
35+
serverExists, err := ctx.FileExists(ctx.ApplicationRoot(), "build/index.js")
36+
if err != nil {
37+
return nil, err
38+
}
39+
if configExists && serverExists {
40+
return []string{"node", "build/index.js"}, nil
41+
}
42+
return nil, nil
43+
}

pkg/nodejs/sveltekit_test.go

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package nodejs
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"google3/security/safeopen/safeopen"
10+
"github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
11+
"github.com/google/go-cmp/cmp"
12+
)
13+
14+
func TestSvelteKitStartCommand(t *testing.T) {
15+
testsCases := []struct {
16+
name string
17+
configExists bool
18+
buildExists bool
19+
want []string
20+
}{
21+
{
22+
name: "no config or build",
23+
want: nil,
24+
},
25+
{
26+
name: "no config",
27+
buildExists: true,
28+
want: nil,
29+
},
30+
{
31+
name: "no build",
32+
configExists: true,
33+
want: nil,
34+
},
35+
{
36+
name: "sveltekit app",
37+
buildExists: true,
38+
configExists: true,
39+
want: []string{"node", "build/index.js"},
40+
},
41+
}
42+
for _, tc := range testsCases {
43+
t.Run(tc.name, func(t *testing.T) {
44+
home := t.TempDir()
45+
if tc.configExists {
46+
_, err := safeopen.CreateBeneath(home, "svelte.config.js")
47+
if err != nil {
48+
t.Fatalf("failed to create server.js: %v", err)
49+
}
50+
}
51+
if tc.buildExists {
52+
dir := filepath.Join(home, "build")
53+
if err := os.MkdirAll(dir, 0755); err != nil {
54+
t.Fatalf("failed to create build directory: %v", err)
55+
}
56+
_, err := safeopen.CreateBeneath(dir, "index.js")
57+
if err != nil {
58+
t.Fatalf("failed to create index.js: %v", err)
59+
}
60+
}
61+
ctx := gcpbuildpack.NewContext(gcpbuildpack.WithApplicationRoot(home))
62+
63+
got, err := SvelteKitStartCommand(ctx)
64+
if err != nil {
65+
t.Fatalf("SvelteKitStartCommand() got error: %v", err)
66+
}
67+
if diff := cmp.Diff(tc.want, got); diff != "" {
68+
t.Errorf("SvelteKitStartCommand() mismatch (-want +got):\n%s", diff)
69+
}
70+
})
71+
}
72+
}
73+
74+
func TestDetectSvelteKitAutoAdapter(t *testing.T) {
75+
testsCases := []struct {
76+
name string
77+
pjs string
78+
want bool
79+
}{
80+
{
81+
name: "with sveltekit auto adapter",
82+
pjs: `{
83+
"devDependencies": {
84+
"@sveltejs/adapter-auto": "^3.0.0"
85+
}
86+
}`,
87+
want: true,
88+
},
89+
{
90+
name: "with two sveltekit adapters",
91+
pjs: `{
92+
"devDependencies": {
93+
"@sveltejs/adapter-auto": "^3.0.0",
94+
"@sveltejs/adapter-node": "^5.0.1"
95+
}
96+
}`,
97+
want: false,
98+
},
99+
{
100+
name: "with no sveltekit adapters",
101+
pjs: `{
102+
"scripts": {
103+
"dev": "vite dev",
104+
"build": "vite build",
105+
"preview": "vite preview",
106+
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
107+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch"
108+
}
109+
}`,
110+
want: false,
111+
},
112+
{
113+
name: "no scripts",
114+
pjs: `{}`,
115+
want: false,
116+
},
117+
}
118+
for _, tc := range testsCases {
119+
t.Run(tc.name, func(t *testing.T) {
120+
var pjs *PackageJSON = nil
121+
if tc.pjs != "" {
122+
if err := json.Unmarshal([]byte(tc.pjs), &pjs); err != nil {
123+
t.Fatalf("failed to unmarshal package.json: %s, error: %v", tc.pjs, err)
124+
}
125+
}
126+
127+
if got := DetectSvelteKitAutoAdapter(pjs); got != tc.want {
128+
t.Errorf("DetectSvelteKitAutoAdapter() = %v, want %v", got, tc.want)
129+
}
130+
})
131+
}
132+
}

0 commit comments

Comments
 (0)