@cedarjs/cli 5.0.0-canary.2376 → 5.0.0-canary.2379

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -64,6 +64,26 @@ const addFilesTask = ({
64
64
  }
65
65
  };
66
66
  };
67
+ const verifyUDSetupTask = () => {
68
+ return {
69
+ title: "Checking if Universal Deploy is set up...",
70
+ task: () => {
71
+ const paths = getPaths();
72
+ const viteConfigTs = path.join(paths.web.base, "vite.config.ts");
73
+ const viteConfigJs = path.join(paths.web.base, "vite.config.js");
74
+ const viteConfigPath = fs.existsSync(viteConfigTs) ? viteConfigTs : viteConfigJs;
75
+ if (!fs.existsSync(viteConfigPath)) {
76
+ throw new Error("Vite config file not found");
77
+ }
78
+ const content = fs.readFileSync(viteConfigPath, "utf-8");
79
+ if (!content.includes("cedarUniversalDeployPlugin")) {
80
+ throw new Error(
81
+ "Universal Deploy is not set up. Please run `yarn cedar setup deploy universal-deploy` first."
82
+ );
83
+ }
84
+ }
85
+ };
86
+ };
67
87
  const addToGitIgnoreTask = ({ paths }) => {
68
88
  return {
69
89
  title: "Updating .gitignore...",
@@ -106,5 +126,6 @@ export {
106
126
  addToGitIgnoreTask,
107
127
  getUserApiUrl,
108
128
  preRequisiteCheckTask,
109
- updateApiURLTask
129
+ updateApiURLTask,
130
+ verifyUDSetupTask
110
131
  };
@@ -1,8 +1,14 @@
1
1
  import { createHandler } from "../helpers/helpers.js";
2
2
  const command = "netlify";
3
3
  const description = "Setup Netlify deploy";
4
+ const builder = (yargs) => yargs.option("ud", {
5
+ description: "Setup for use with Universal Deploy",
6
+ type: "boolean",
7
+ default: false
8
+ });
4
9
  const handler = createHandler("netlify");
5
10
  export {
11
+ builder,
6
12
  command,
7
13
  description,
8
14
  handler
@@ -1,31 +1,129 @@
1
+ import fs from "node:fs";
1
2
  import path from "path";
2
3
  import { Listr } from "listr2";
3
4
  import { recordTelemetryAttributes, colors as c } from "@cedarjs/cli-helpers";
4
5
  import { errorTelemetry } from "@cedarjs/telemetry";
5
- import { getPaths, printSetupNotes } from "../../../../lib/index.js";
6
- import { addFilesTask, updateApiURLTask } from "../helpers/index.js";
6
+ import {
7
+ addPackagesTask,
8
+ getPaths,
9
+ printSetupNotes
10
+ } from "../../../../lib/index.js";
11
+ import {
12
+ addFilesTask,
13
+ updateApiURLTask,
14
+ verifyUDSetupTask
15
+ } from "../helpers/index.js";
7
16
  import { NETLIFY_TOML } from "../templates/netlify.js";
17
+ import { NETLIFY_UD_TOML } from "../templates/netlifyUD.js";
8
18
  const files = [
9
19
  {
10
20
  path: path.join(getPaths().base, "netlify.toml"),
11
21
  content: NETLIFY_TOML
12
22
  }
13
23
  ];
24
+ const filesUd = [
25
+ {
26
+ path: path.join(getPaths().base, "netlify.toml"),
27
+ content: NETLIFY_UD_TOML
28
+ }
29
+ ];
14
30
  const notes = [
15
31
  "You are ready to deploy to Netlify!",
16
32
  "See: https://cedarjs.com/docs/deploy/netlify"
17
33
  ];
18
- const handler = async ({ force }) => {
34
+ const udNotes = [
35
+ "You are ready to deploy to Netlify with Universal Deploy!",
36
+ "Build with: yarn cedar build --ud",
37
+ "See: https://cedarjs.com/docs/deploy/netlify"
38
+ ];
39
+ function addNetlifyPluginsToViteConfigTask() {
40
+ return {
41
+ title: "Adding Netlify plugins to vite config...",
42
+ task: async (_ctx, task) => {
43
+ const paths = getPaths();
44
+ const viteConfigTs = path.join(paths.web.base, "vite.config.ts");
45
+ const viteConfigJs = path.join(paths.web.base, "vite.config.js");
46
+ const viteConfigPath = fs.existsSync(viteConfigTs) ? viteConfigTs : viteConfigJs;
47
+ if (!fs.existsSync(viteConfigPath)) {
48
+ task.skip(`${viteConfigPath} not found`);
49
+ return;
50
+ }
51
+ let content = fs.readFileSync(viteConfigPath, "utf-8");
52
+ const hasNetlifyPlugin = content.includes("@netlify/vite-plugin");
53
+ const hasNetlifyCompat = content.includes(
54
+ "@universal-deploy/netlify/vite"
55
+ );
56
+ if (hasNetlifyPlugin && hasNetlifyCompat && content.includes("netlifyCompat(")) {
57
+ task.skip("Netlify plugins are already configured.");
58
+ return;
59
+ }
60
+ if (!hasNetlifyPlugin || !hasNetlifyCompat) {
61
+ const newContent = content.replace(
62
+ /(import\s+\{[^}]*\}\s+from\s+['"]vite['"];?)/,
63
+ (match) => {
64
+ let result = match;
65
+ if (!hasNetlifyPlugin) {
66
+ result = `import netlify from '@netlify/vite-plugin'
67
+ ${result}`;
68
+ }
69
+ if (!hasNetlifyCompat) {
70
+ result = `import netlifyCompat from '@universal-deploy/netlify/vite'
71
+ ${result}`;
72
+ }
73
+ return result;
74
+ }
75
+ );
76
+ if (newContent === content) {
77
+ let prepend = "";
78
+ if (!hasNetlifyPlugin) {
79
+ prepend += "import netlify from '@netlify/vite-plugin'\n";
80
+ }
81
+ if (!hasNetlifyCompat) {
82
+ prepend += "import netlifyCompat from '@universal-deploy/netlify/vite'\n";
83
+ }
84
+ content = prepend + content;
85
+ } else {
86
+ content = newContent;
87
+ }
88
+ }
89
+ if (!content.includes("netlifyCompat(")) {
90
+ content = content.replace(
91
+ /(\s*)(plugins:\s*\[)([\s\S]*?)(cedar\s*\()/,
92
+ (_match, leadingWs, prefix, beforeCedar, cedarCall) => {
93
+ const indent = beforeCedar.includes("\n") ? beforeCedar.match(/\n(\s*)$/)?.[1] || leadingWs + " " : leadingWs + " ";
94
+ const before = beforeCedar.replace(/\s*$/, "");
95
+ return `${leadingWs}${prefix}
96
+ ${indent}netlify({ build: { enabled: true } }),
97
+ ${indent}netlifyCompat(),${before}
98
+ ${indent}${cedarCall}`;
99
+ }
100
+ );
101
+ }
102
+ fs.writeFileSync(viteConfigPath, content);
103
+ }
104
+ };
105
+ }
106
+ function installNetlifyPackagesTask() {
107
+ return addPackagesTask({
108
+ packages: ["@netlify/vite-plugin", "@universal-deploy/netlify"],
109
+ devDependency: true
110
+ });
111
+ }
112
+ const handler = async ({ force, ud }) => {
19
113
  recordTelemetryAttributes({
20
114
  command: "setup deploy netlify",
21
- force
115
+ force,
116
+ ud
22
117
  });
23
118
  const tasks = new Listr(
24
119
  [
25
- updateApiURLTask("/.netlify/functions"),
26
- addFilesTask({ files, force }),
27
- printSetupNotes(notes)
28
- ],
120
+ ud && verifyUDSetupTask(),
121
+ ud && await installNetlifyPackagesTask(),
122
+ ud && addNetlifyPluginsToViteConfigTask(),
123
+ !ud && updateApiURLTask("/.netlify/functions"),
124
+ addFilesTask({ files: ud ? filesUd : files, force }),
125
+ printSetupNotes(ud ? udNotes : notes)
126
+ ].filter(Boolean),
29
127
  { rendererOptions: { collapseSubtasks: false } }
30
128
  );
31
129
  try {
@@ -14,7 +14,13 @@ const notes = [
14
14
  "",
15
15
  "Next steps:",
16
16
  ` ${c.highlight("yarn cedar build --ud")} \u2014 build the Universal Deploy server entry`,
17
- ` ${c.highlight("yarn cedar serve --ud")} \u2014 serve it locally`
17
+ ` ${c.highlight("yarn cedar serve --ud")} \u2014 serve it locally`,
18
+ "",
19
+ "To deploy, pick a deployment target, for example:",
20
+ ` ${c.highlight("yarn cedar setup deploy netlify --ud")}`,
21
+ ` ${c.highlight("yarn cedar setup deploy vercel --ud")}`,
22
+ "",
23
+ "See: https://cedarjs.com/docs/deploy/universal-deploy"
18
24
  ];
19
25
  async function handler() {
20
26
  recordTelemetryAttributes({
@@ -1,8 +1,14 @@
1
1
  import { createHandler } from "../helpers/helpers.js";
2
2
  const command = "vercel";
3
3
  const description = "Setup Vercel deploy";
4
+ const builder = (yargs) => yargs.option("ud", {
5
+ description: "Setup for use with Universal Deploy",
6
+ type: "boolean",
7
+ default: false
8
+ });
4
9
  const handler = createHandler("vercel");
5
10
  export {
11
+ builder,
6
12
  command,
7
13
  description,
8
14
  handler
@@ -1,19 +1,30 @@
1
+ import fs from "node:fs";
1
2
  import path from "path";
2
3
  import { Listr } from "listr2";
3
4
  import { recordTelemetryAttributes, colors as c } from "@cedarjs/cli-helpers";
4
5
  import { errorTelemetry } from "@cedarjs/telemetry";
5
- import { getPaths, printSetupNotes, writeFile } from "../../../../lib/index.js";
6
- import { updateApiURLTask } from "../helpers/index.js";
7
- async function handler(options) {
6
+ import {
7
+ addPackagesTask,
8
+ getPaths,
9
+ printSetupNotes,
10
+ writeFile
11
+ } from "../../../../lib/index.js";
12
+ import { updateApiURLTask, verifyUDSetupTask } from "../helpers/index.js";
13
+ async function handler({ force, ud }) {
8
14
  recordTelemetryAttributes({
9
- command: "setup deploy vercel"
15
+ command: "setup deploy vercel",
16
+ force,
17
+ ud
10
18
  });
11
19
  const tasks = new Listr(
12
20
  [
13
- updateApiURLTask("/api"),
14
- writeVercelConfigTask({ overwriteExisting: options.force }),
15
- printSetupNotes(notes)
16
- ],
21
+ ud && verifyUDSetupTask(),
22
+ ud && await installVercelPackagesTask(),
23
+ ud && addVercelPluginToViteConfigTask(),
24
+ !ud && updateApiURLTask("/api"),
25
+ ud ? writeVercelUDConfigTask({ overwriteExisting: force }) : writeVercelConfigTask({ overwriteExisting: force }),
26
+ printSetupNotes(ud ? udNotes : notes)
27
+ ].filter(Boolean),
17
28
  {
18
29
  rendererOptions: { collapseSubtasks: false }
19
30
  }
@@ -26,6 +37,57 @@ async function handler(options) {
26
37
  process.exit(e?.exitCode || 1);
27
38
  }
28
39
  }
40
+ function addVercelPluginToViteConfigTask() {
41
+ return {
42
+ title: "Adding Vercel plugin to vite config...",
43
+ task: async (_ctx, task) => {
44
+ const paths = getPaths();
45
+ const viteConfigTs = path.join(paths.web.base, "vite.config.ts");
46
+ const viteConfigJs = path.join(paths.web.base, "vite.config.js");
47
+ const viteConfigPath = fs.existsSync(viteConfigTs) ? viteConfigTs : viteConfigJs;
48
+ if (!fs.existsSync(viteConfigPath)) {
49
+ task.skip(`${viteConfigPath} not found`);
50
+ return;
51
+ }
52
+ let content = fs.readFileSync(viteConfigPath, "utf-8");
53
+ const hasVercelPlugin = content.includes("vite-plugin-vercel");
54
+ if (hasVercelPlugin && content.includes("vercel(")) {
55
+ task.skip("Vercel plugin is already configured.");
56
+ return;
57
+ }
58
+ if (!hasVercelPlugin) {
59
+ const newContent = content.replace(
60
+ /(import\s+\{[^}]*\}\s+from\s+['"]vite['"];?)/,
61
+ "import { vercel } from 'vite-plugin-vercel/vite'\n$1"
62
+ );
63
+ if (newContent === content) {
64
+ content = "import { vercel } from 'vite-plugin-vercel/vite'\n" + content;
65
+ } else {
66
+ content = newContent;
67
+ }
68
+ }
69
+ if (!content.includes("vercel(")) {
70
+ content = content.replace(
71
+ /(\s*)(plugins:\s*\[)([\s\S]*?)(cedar\s*\()/,
72
+ (_match, leadingWs, prefix, beforeCedar, cedarCall) => {
73
+ const indent = beforeCedar.includes("\n") ? beforeCedar.match(/\n(\s*)$/)?.[1] || leadingWs + " " : leadingWs + " ";
74
+ const before = beforeCedar.replace(/\s*$/, "");
75
+ return `${leadingWs}${prefix}
76
+ ${indent}vercel(),${before}
77
+ ${indent}${cedarCall}`;
78
+ }
79
+ );
80
+ }
81
+ fs.writeFileSync(viteConfigPath, content);
82
+ }
83
+ };
84
+ }
85
+ function installVercelPackagesTask() {
86
+ return addPackagesTask({
87
+ packages: ["vite-plugin-vercel"],
88
+ devDependency: true
89
+ });
90
+ }
29
91
  function writeVercelConfigTask({ overwriteExisting = false } = {}) {
30
92
  return {
31
93
  title: "Writing vercel.json...",
@@ -46,10 +108,36 @@ const vercelConfig = {
46
108
  }
47
109
  }
48
110
  };
111
+ const vercelUDConfig = {
112
+ build: {
113
+ command: "yarn cedar build --ud --verbose",
114
+ env: {
115
+ ENABLE_EXPERIMENTAL_COREPACK: "1"
116
+ }
117
+ }
118
+ };
49
119
  const notes = [
50
120
  "You are ready to deploy to Vercel!",
51
121
  "See: https://cedarjs.com/docs/deploy#vercel-deploy"
52
122
  ];
123
+ const udNotes = [
124
+ "You are ready to deploy to Vercel with Universal Deploy!",
125
+ "Build with: yarn cedar build --ud",
126
+ "See: https://cedarjs.com/docs/deploy#vercel-deploy"
127
+ ];
128
+ function writeVercelUDConfigTask({ overwriteExisting = false } = {}) {
129
+ return {
130
+ title: "Writing vercel.json for Universal Deploy...",
131
+ task: (_ctx, task) => {
132
+ writeFile(
133
+ path.join(getPaths().base, "vercel.json"),
134
+ JSON.stringify(vercelUDConfig, null, 2),
135
+ { overwriteExisting },
136
+ task
137
+ );
138
+ }
139
+ };
140
+ }
53
141
  export {
54
142
  handler
55
143
  };
@@ -0,0 +1,30 @@
1
+ import { getConfig } from "../../../../lib/index.js";
2
+ const config = getConfig();
3
+ const NETLIFY_UD_TOML = `[build]
4
+ command = "yarn cedar build --ud --apiRootPath=/.api/functions && yarn cedar prisma migrate deploy && yarn cedar data-migrate up"
5
+ publish = "web/dist"
6
+
7
+ [build.environment]
8
+ NODE_VERSION = "24"
9
+
10
+ [functions]
11
+ directory = "api/dist/functions"
12
+
13
+ # To use Netlify Dev, install Netlify's CLI (\`netlify-cli\`) from NPM and use
14
+ # \`netlify link\` to connect your local project to a site on Netlify. Then run
15
+ # \`netlify dev\`.
16
+ #
17
+ # Quick links to the docs:
18
+ # - Netlify Dev https://docs.netlify.com/api-and-cli-guides/cli-guides/local-development
19
+ # - Netlify's CLI https://docs.netlify.com/api-and-cli-guides/cli-guides/get-started-with-cli/
20
+ # - \`netlify link\` https://cli.netlify.com/commands/link/
21
+ [dev]
22
+ framework = "cedarjs"
23
+ # Make sure \`targetPort\` matches \`web.port\` in your cedar.toml file
24
+ targetPort = ${config.web.port}
25
+ # Point your browser to this port to access your app
26
+ port = 8888
27
+ `;
28
+ export {
29
+ NETLIFY_UD_TOML
30
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/cli",
3
- "version": "5.0.0-canary.2376",
3
+ "version": "5.0.0-canary.2379",
4
4
  "description": "The CedarJS Command Line",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,17 +33,17 @@
33
33
  "dependencies": {
34
34
  "@babel/parser": "7.29.3",
35
35
  "@babel/preset-typescript": "7.28.5",
36
- "@cedarjs/api-server": "5.0.0-canary.2376",
37
- "@cedarjs/cli-helpers": "5.0.0-canary.2376",
38
- "@cedarjs/fastify-web": "5.0.0-canary.2376",
39
- "@cedarjs/internal": "5.0.0-canary.2376",
40
- "@cedarjs/prerender": "5.0.0-canary.2376",
41
- "@cedarjs/project-config": "5.0.0-canary.2376",
42
- "@cedarjs/structure": "5.0.0-canary.2376",
43
- "@cedarjs/telemetry": "5.0.0-canary.2376",
44
- "@cedarjs/utils": "5.0.0-canary.2376",
45
- "@cedarjs/vite": "5.0.0-canary.2376",
46
- "@cedarjs/web-server": "5.0.0-canary.2376",
36
+ "@cedarjs/api-server": "5.0.0-canary.2379",
37
+ "@cedarjs/cli-helpers": "5.0.0-canary.2379",
38
+ "@cedarjs/fastify-web": "5.0.0-canary.2379",
39
+ "@cedarjs/internal": "5.0.0-canary.2379",
40
+ "@cedarjs/prerender": "5.0.0-canary.2379",
41
+ "@cedarjs/project-config": "5.0.0-canary.2379",
42
+ "@cedarjs/structure": "5.0.0-canary.2379",
43
+ "@cedarjs/telemetry": "5.0.0-canary.2379",
44
+ "@cedarjs/utils": "5.0.0-canary.2379",
45
+ "@cedarjs/vite": "5.0.0-canary.2379",
46
+ "@cedarjs/web-server": "5.0.0-canary.2379",
47
47
  "@listr2/prompt-adapter-enquirer": "4.2.1",
48
48
  "@opentelemetry/api": "1.9.0",
49
49
  "@opentelemetry/core": "1.30.1",