feat: add nuxt adapter (#460)
* feat: add nuxt adapter * fix link * Update FrameworkSelector.tsx * Update FrameworkSelector.tsx --------- Co-authored-by: Matt Aitken <matt@mattaitken.com>
This commit is contained in:
@@ -63,7 +63,7 @@ export function FrameworkSelector() {
|
||||
<FrameworkLink to={projectSetupAstroPath(organization, project)}>
|
||||
<AstroLogo className="w-32" />
|
||||
</FrameworkLink>
|
||||
<FrameworkLink to={projectSetupNuxtPath(organization, project)}>
|
||||
<FrameworkLink to={projectSetupNuxtPath(organization, project)} supported>
|
||||
<NuxtLogo className="w-32" />
|
||||
</FrameworkLink>
|
||||
<FrameworkLink to={projectSetupSvelteKitPath(organization, project)}>
|
||||
|
||||
+203
-11
@@ -1,21 +1,213 @@
|
||||
import { NuxtLogo } from "~/assets/logos/NuxtLogo";
|
||||
import { FrameworkComingSoon } from "~/components/frameworks/FrameworkComingSoon";
|
||||
import { ChatBubbleLeftRightIcon, Squares2X2Icon } from "@heroicons/react/20/solid";
|
||||
import { useState } from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
import { Feedback } from "~/components/Feedback";
|
||||
import { PageGradient } from "~/components/PageGradient";
|
||||
import { InitCommand, RunDevCommand, TriggerDevStep } from "~/components/SetupCommands";
|
||||
import { StepContentContainer } from "~/components/StepContentContainer";
|
||||
import { InlineCode } from "~/components/code/InlineCode";
|
||||
import { BreadcrumbLink } from "~/components/navigation/NavBar";
|
||||
import { Button, LinkButton } from "~/components/primitives/Buttons";
|
||||
import {
|
||||
ClientTabs,
|
||||
ClientTabsContent,
|
||||
ClientTabsList,
|
||||
ClientTabsTrigger,
|
||||
} from "~/components/primitives/ClientTabs";
|
||||
import { ClipboardField } from "~/components/primitives/ClipboardField";
|
||||
import { Header1 } from "~/components/primitives/Headers";
|
||||
import { NamedIcon } from "~/components/primitives/NamedIcon";
|
||||
import { Paragraph } from "~/components/primitives/Paragraph";
|
||||
import { RadioGroup, RadioGroupItem } from "~/components/primitives/RadioButton";
|
||||
import { StepNumber } from "~/components/primitives/StepNumber";
|
||||
import { useAppOrigin } from "~/hooks/useAppOrigin";
|
||||
import { useProjectSetupComplete } from "~/hooks/useProjectSetupComplete";
|
||||
import { useDevEnvironment } from "~/hooks/useEnvironments";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { useProject } from "~/hooks/useProject";
|
||||
import { Handle } from "~/utils/handle";
|
||||
import { trimTrailingSlash } from "~/utils/pathBuilder";
|
||||
import { projectSetupPath, trimTrailingSlash } from "~/utils/pathBuilder";
|
||||
import { Callout } from "~/components/primitives/Callout";
|
||||
|
||||
type SelectionChoices = "use-existing-project" | "create-new-nuxt-app";
|
||||
|
||||
export const handle: Handle = {
|
||||
breadcrumb: (match) => <BreadcrumbLink to={trimTrailingSlash(match.pathname)} title="Nuxt" />,
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
export default function SetupNuxt3() {
|
||||
const organization = useOrganization();
|
||||
const project = useProject();
|
||||
useProjectSetupComplete();
|
||||
const devEnvironment = useDevEnvironment();
|
||||
const appOrigin = useAppOrigin();
|
||||
const [selectedValue, setSelectedValue] = useState<SelectionChoices | null>(null);
|
||||
|
||||
invariant(devEnvironment, "devEnvironment is required");
|
||||
|
||||
return (
|
||||
<FrameworkComingSoon
|
||||
frameworkName="Nuxt"
|
||||
githubIssueUrl="https://github.com/triggerdotdev/trigger.dev/issues/447"
|
||||
githubIssueNumber={447}
|
||||
>
|
||||
<NuxtLogo className="w-56" />
|
||||
</FrameworkComingSoon>
|
||||
<PageGradient>
|
||||
<div className="mx-auto max-w-3xl">
|
||||
<div className="flex items-center justify-between">
|
||||
<Header1 spacing className="text-bright">
|
||||
Get setup in {selectedValue === "create-new-nuxt-app" ? "5" : "2"} minutes
|
||||
</Header1>
|
||||
<div className="flex items-center gap-2">
|
||||
<LinkButton
|
||||
to={projectSetupPath(organization, project)}
|
||||
variant="tertiary/small"
|
||||
LeadingIcon={Squares2X2Icon}
|
||||
>
|
||||
Choose a different framework
|
||||
</LinkButton>
|
||||
<Feedback
|
||||
button={
|
||||
<Button variant="tertiary/small" LeadingIcon={ChatBubbleLeftRightIcon}>
|
||||
I'm stuck!
|
||||
</Button>
|
||||
}
|
||||
defaultValue="help"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<RadioGroup
|
||||
className="mb-4 flex gap-x-2"
|
||||
onValueChange={(value) => setSelectedValue(value as SelectionChoices)}
|
||||
>
|
||||
<RadioGroupItem
|
||||
label="Use an existing Nuxt project"
|
||||
description="Use Trigger.dev in an existing Nuxt project in less than 2 mins."
|
||||
value="use-existing-project"
|
||||
checked={selectedValue === "use-existing-project"}
|
||||
variant="icon"
|
||||
data-action="use-existing-project"
|
||||
icon={<NamedIcon className="h-12 w-12 text-green-600" name={"tree"} />}
|
||||
/>
|
||||
<RadioGroupItem
|
||||
label="Create a new Nuxt project"
|
||||
description="This is the quickest way to try out Trigger.dev in a new Nuxt project and takes 5 mins."
|
||||
value="create-new-nuxt-app"
|
||||
checked={selectedValue === "create-new-nuxt-app"}
|
||||
variant="icon"
|
||||
data-action="create-new-nuxt-app"
|
||||
icon={<NamedIcon className="h-8 w-8 text-green-600" name={"sapling"} />}
|
||||
/>
|
||||
</RadioGroup>
|
||||
{selectedValue && (
|
||||
<>
|
||||
<Callout
|
||||
variant={"info"}
|
||||
to="https://github.com/triggerdotdev/trigger.dev/discussions/430"
|
||||
className="mb-8"
|
||||
>
|
||||
Trigger.dev has full support for serverless. We will be adding support for
|
||||
long-running servers soon.
|
||||
</Callout>
|
||||
{selectedValue === "create-new-nuxt-app" ? (
|
||||
<>
|
||||
<StepNumber stepNumber="1" title="Create a new Nuxt project" />
|
||||
<StepContentContainer>
|
||||
<ClientTabs defaultValue="npm">
|
||||
<ClientTabsList>
|
||||
<ClientTabsTrigger value={"npm"}>npm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"pnpm"}>pnpm</ClientTabsTrigger>
|
||||
<ClientTabsTrigger value={"yarn"}>yarn</ClientTabsTrigger>
|
||||
</ClientTabsList>
|
||||
<ClientTabsContent value={"npm"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
value={`npx nuxi@latest init <project-name>`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"pnpm"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
value={`pnpm dlx nuxi@latest init <project-name>`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
<ClientTabsContent value={"yarn"}>
|
||||
<ClipboardField
|
||||
variant="primary/medium"
|
||||
className="mb-4"
|
||||
value={`yarn create nuxt-app`}
|
||||
/>
|
||||
</ClientTabsContent>
|
||||
</ClientTabs>
|
||||
|
||||
<Paragraph spacing variant="small">
|
||||
Trigger.dev works with either the Pages or App Router configuration.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="2" title="Navigate to your new Nuxt project" />
|
||||
<StepContentContainer>
|
||||
<Paragraph spacing>
|
||||
You have now created a new Nuxt project. Let’s <InlineCode>cd</InlineCode>{" "}
|
||||
into it using the project name you just provided:
|
||||
</Paragraph>
|
||||
<ClipboardField
|
||||
value={"cd [replace with your project name]"}
|
||||
variant={"primary/medium"}
|
||||
></ClipboardField>
|
||||
</StepContentContainer>
|
||||
<StepNumber
|
||||
stepNumber="3"
|
||||
title="Run the CLI 'init' command in your new Nuxt project"
|
||||
/>
|
||||
<StepContentContainer>
|
||||
<InitCommand appOrigin={appOrigin} apiKey={devEnvironment.apiKey} />
|
||||
<Paragraph spacing variant="small">
|
||||
You’ll notice a new folder in your project called 'jobs'. We’ve added a very
|
||||
simple example Job in <InlineCode variant="extra-small">examples.ts</InlineCode>{" "}
|
||||
to help you get started.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="4" title="Run your Nuxt app" />
|
||||
<StepContentContainer>
|
||||
<RunDevCommand />
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="5" title="Run the CLI 'dev' command" />
|
||||
<StepContentContainer>
|
||||
<TriggerDevStep />
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="6" title="Wait for Jobs" displaySpinner />
|
||||
<StepContentContainer>
|
||||
<Paragraph>This page will automatically refresh.</Paragraph>
|
||||
</StepContentContainer>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<StepNumber
|
||||
stepNumber="1"
|
||||
title="Run the CLI 'init' command in an existing Nuxt project"
|
||||
/>
|
||||
<StepContentContainer>
|
||||
<InitCommand appOrigin={appOrigin} apiKey={devEnvironment.apiKey} />
|
||||
|
||||
<Paragraph spacing variant="small">
|
||||
You’ll notice a new folder in your project called 'jobs'. We’ve added a very
|
||||
simple example Job in <InlineCode variant="extra-small">examples.ts</InlineCode>{" "}
|
||||
to help you get started.
|
||||
</Paragraph>
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="2" title="Run your Nuxt app" />
|
||||
<StepContentContainer>
|
||||
<RunDevCommand />
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="3" title="Run the CLI 'dev' command" />
|
||||
<StepContentContainer>
|
||||
<TriggerDevStep />
|
||||
</StepContentContainer>
|
||||
<StepNumber stepNumber="4" title="Wait for Jobs" displaySpinner />
|
||||
<StepContentContainer>
|
||||
<Paragraph>This page will automatically refresh.</Paragraph>
|
||||
</StepContentContainer>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</PageGradient>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1 +1,219 @@
|
||||
We're in the process of building support for the Nuxt framework. You can follow along with progress or contribute via [this GitHub issue](https://github.com/triggerdotdev/trigger.dev/issues).
|
||||
<Accordion defaultOpen title="Don't have a Nuxt project yet to add Trigger.dev to? No problem, you can complete the Manual Setup using a blank Nuxt project:">
|
||||
Create a blank project by running the `nuxi@latest init <project-name>` command in your terminal:
|
||||
<CodeGroup>
|
||||
|
||||
```bash npm
|
||||
npx nuxi@latest init <project-name>
|
||||
```
|
||||
|
||||
```bash pnpm
|
||||
pnpm dlx nuxi@latest init <project-name>
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn nuxi@latest init <project-name>
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
</Accordion>
|
||||
|
||||
## Installing Required Packages
|
||||
|
||||
To begin, install the necessary packages in your Nuxt project directory. You can choose one of the following package managers:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash npm
|
||||
npm i @trigger.dev/sdk @trigger-dev/nuxtjs
|
||||
```
|
||||
|
||||
```bash pnpm
|
||||
pnpm install @trigger.dev/sdk @trigger-dev/nuxtjs
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn add @trigger.dev/sdk @trigger-dev/nuxtjs
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<br />
|
||||
|
||||
<Note>Ensure that you execute this command within a Nuxt project.</Note>
|
||||
|
||||
## Obtaining the Development API Key
|
||||
|
||||
To locate your development API key, login to the [Trigger.dev
|
||||
dashboard](https://cloud.trigger.dev) and select the Project you want to
|
||||
connect to. Then click on the Environments & API Keys tab in the left menu.
|
||||
You can copy your development API Key from the field at the top of this page.
|
||||
(Your development key will start with `tr_dev_`).
|
||||
|
||||
## Adding Environment Variables
|
||||
|
||||
Create a `.env.local` file at the root of your project and include your Trigger API key and URL like this:
|
||||
|
||||
```bash
|
||||
|
||||
TRIGGER_API_KEY=ENTER_YOUR_DEVELOPMENT_API_KEY_HERE
|
||||
TRIGGER_API_URL=https://cloud.trigger.dev
|
||||
|
||||
```
|
||||
|
||||
Replace `ENTER_YOUR_DEVELOPMENT_API_KEY_HERE` with the actual API key obtained from the previous step.
|
||||
|
||||
## Configuring the Trigger Client
|
||||
|
||||
To set up the Trigger Client for your project, follow these steps:
|
||||
|
||||
1. **Create Configuration File:**
|
||||
|
||||
In your project directory, create a configuration file named `trigger.ts`.
|
||||
|
||||
2. **Choose Directory:**
|
||||
|
||||
Depending on your project structure, choose the appropriate directory for the configuration file. If your project uses a `src` directory, create the file within it. Otherwise, create it directly in the project root.
|
||||
|
||||
3. **Add Configuration Code:**
|
||||
|
||||
Open the configuration file you created and add the following code:
|
||||
|
||||
```typescript
|
||||
import { TriggerClient } from "@trigger.dev/sdk";
|
||||
|
||||
export const client = new TriggerClient({
|
||||
id: "my-app",
|
||||
apiKey: process.env.TRIGGER_API_KEY,
|
||||
apiUrl: process.env.TRIGGER_API_URL,
|
||||
});
|
||||
```
|
||||
|
||||
Replace **"my-app"** with an appropriate identifier for your project. The **apiKey** and **apiUrl** are obtained from the environment variables you set earlier.
|
||||
|
||||
4. **File Location:**
|
||||
|
||||
Depending on your project structure, save the configuration file in the appropriate location:
|
||||
|
||||
- If your project uses a **src** directory, save the file within the **src** directory.
|
||||
- If your project does not use a **src** directory, save the file in the project root.
|
||||
|
||||
**Example Directory Structure with src:**
|
||||
|
||||
```
|
||||
project-root/
|
||||
├── src/
|
||||
├── trigger.ts
|
||||
├── other files...
|
||||
```
|
||||
|
||||
**Example Directory Structure without src:**
|
||||
|
||||
```
|
||||
project-root/
|
||||
├── trigger.ts
|
||||
├── other files...
|
||||
```
|
||||
|
||||
By following these steps, you'll configure the Trigger Client to work with your project, regardless of whether you have a separate **src** directory and whether you're using TypeScript or JavaScript files.
|
||||
|
||||
## Creating the API Route
|
||||
|
||||
To establish an API route for interacting with Trigger.dev, follow these steps.
|
||||
|
||||
1. Create a new file named `trigger.ts` within the `server/api/` directory.
|
||||
2. Add the following code to `trigger.ts`:
|
||||
|
||||
```typescript
|
||||
import { client } from "@/trigger";
|
||||
import { createNuxtRoute } from "@trigger.dev/nuxtjs";
|
||||
import { eventTrigger } from "@trigger.dev/sdk";
|
||||
|
||||
client.defineJob({
|
||||
id: "hello-world",
|
||||
name: "Hello World",
|
||||
version: "0.0.1",
|
||||
trigger: eventTrigger({
|
||||
name: "starter.hello-world",
|
||||
}),
|
||||
run: async (_payload, io, _ctx) => {
|
||||
await io.logger.info("Hello world!");
|
||||
return {
|
||||
message: "Hello world!",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Add your jobs here
|
||||
|
||||
const nuxt = createNuxtRoute(client);
|
||||
|
||||
export default defineEventHandler(nuxt);
|
||||
```
|
||||
|
||||
## Adding Configuration to `package.json`
|
||||
|
||||
Inside the `package.json` file, add the following configuration under the root object:
|
||||
|
||||
```json
|
||||
"trigger.dev": {
|
||||
"endpointId": "my-app"
|
||||
}
|
||||
```
|
||||
|
||||
Your `package.json` file might look something like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
// ... other dependencies
|
||||
},
|
||||
"trigger.dev": {
|
||||
"endpointId": "my-app"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Replace **"my-app"** with the appropriate identifier you used during the step for creating the Trigger Client.
|
||||
|
||||
## Nuxt Steps
|
||||
|
||||
Start your Nuxt project locally, and then execute the `dev` CLI command to run Trigger.dev locally. You should run this command every time you want to use Trigger.dev locally.
|
||||
|
||||

|
||||
|
||||
<Warning>
|
||||
|
||||
Make sure your Nuxt site is running locally before continuing. You must also leave this `dev`
|
||||
terminal command running while you develop.
|
||||
|
||||
</Warning>
|
||||
|
||||
In a **new terminal window or tab** run:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash npm
|
||||
npx @trigger.dev/cli@latest dev
|
||||
```
|
||||
|
||||
```bash pnpm
|
||||
pnpm dlx @trigger.dev/cli@latest dev
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn dlx @trigger.dev/cli@latest dev
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
<br />
|
||||
<Note>
|
||||
You can optionally pass the port if you're not running on 3000 by adding
|
||||
`--port 3001` to the end
|
||||
</Note>
|
||||
<Note>
|
||||
You can optionally pass the hostname if you're not running on localhost by adding
|
||||
`--hostname <host>`. Example, in case your Nuxt is running on 0.0.0.0: `--hostname 0.0.0.0`.
|
||||
</Note>
|
||||
|
||||
@@ -28,4 +28,5 @@ Each platform has one or more adaptors, see the guides below:
|
||||
| ------------------------------------------------- | -------------------- |
|
||||
| [Next.js](/documentation/guides/platforms/nextjs) | `createPagesRoute()` |
|
||||
| [Next.js](/documentation/guides/platforms/nextjs) | `createAppRoute()` |
|
||||
| [Nuxt.js](/documentation/guides/platforms/nuxt) | `createNuxtRoute()` |
|
||||
| Express | Coming soon |
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
@@ -0,0 +1 @@
|
||||
shamefully-hoist=true
|
||||
@@ -0,0 +1,63 @@
|
||||
# Nuxt 3 Minimal Starter
|
||||
|
||||
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install the dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm run dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm run build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm run preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<NuxtWelcome />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,4 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
devtools: { enabled: true }
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": " nuxi dev --dotenv .env.local --host",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trigger.dev/nextjs": "^2.1.0",
|
||||
"@trigger.dev/nuxtjs": "workspace:*",
|
||||
"@trigger.dev/sdk": "^2.1.0",
|
||||
"zod": "3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/devtools": "latest",
|
||||
"@trigger.dev/cli": "workspace:*",
|
||||
"nuxt": "^3.7.1"
|
||||
},
|
||||
"trigger.dev": {
|
||||
"endpointId": "nuxt-E9C7"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,52 @@
|
||||
|
||||
import { client } from "@/trigger";
|
||||
import { createNuxtRoute} from "@trigger.dev/nuxtjs"
|
||||
import { eventTrigger } from "@trigger.dev/sdk";
|
||||
|
||||
const QUOTES = [
|
||||
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler",
|
||||
"First, solve the problem. Then, write the code. - John Johnson",
|
||||
"Experience is the name everyone gives to their mistakes. - Oscar Wilde",
|
||||
"In order to be irreplaceable, one must always be different - Coco Chanel",
|
||||
"Knowledge is power. - Francis Bacon",
|
||||
"Sometimes it pays to stay in bed on Monday, rather than spending the rest of the week debugging Monday's code. - Dan Salomon",
|
||||
"Perfection is achieved not when there is nothing more to add, but rather when there is nothing more to take away. - Antoine de Saint-Exupery",
|
||||
"Rust is the most loved programming language. - Stack Overflow",
|
||||
"Code is like humor. When you have to explain it, it’s bad. - Cory House",
|
||||
"Fix the cause, not the symptom. - Steve Maguire",
|
||||
];
|
||||
|
||||
client.defineJob({
|
||||
id: "hello-world",
|
||||
name: "Hello World",
|
||||
version: "0.0.1",
|
||||
trigger: eventTrigger({
|
||||
name: "starter.hello-world",
|
||||
}),
|
||||
run: async (_payload, io, _ctx) => {
|
||||
await io.logger.info("Hello world!");
|
||||
|
||||
return {
|
||||
message: "Hello world!",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
client.defineJob({
|
||||
id: "quote",
|
||||
name: "Random Quote",
|
||||
version: "0.0.1",
|
||||
trigger: eventTrigger({
|
||||
name: "starter.quote",
|
||||
}),
|
||||
run: async (_payload, _io, _ctx) => {
|
||||
return {
|
||||
quote: QUOTES[Math.floor(Math.random() * QUOTES.length)],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
//this route is used to send and receive data with Trigger.dev
|
||||
const nuxt = createNuxtRoute(client);
|
||||
|
||||
export default defineEventHandler(nuxt)
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
import { TriggerClient } from "@trigger.dev/sdk";
|
||||
|
||||
export const client = new TriggerClient({
|
||||
id: "nuxt-E9C7",
|
||||
apiKey: process.env.TRIGGER_API_KEY,
|
||||
apiUrl: process.env.TRIGGER_API_URL,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { CLOUD_API_URL, CLOUD_TRIGGER_URL, COMMAND_NAME } from "../consts";
|
||||
import { TelemetryClient, telemetryClient } from "../telemetry/telemetry";
|
||||
import { addDependencies } from "../utils/addDependencies";
|
||||
import { detectNextJsProject } from "../utils/detectNextJsProject";
|
||||
import { detectNuxtJsProject } from "../utils/detectNuxtJsProject";
|
||||
import { pathExists, readJSONFile } from "../utils/fileSystem";
|
||||
import { logger } from "../utils/logger";
|
||||
import { resolvePath } from "../utils/parseNameAndPath";
|
||||
@@ -46,17 +47,20 @@ export const initCommand = async (options: InitCommandOptions) => {
|
||||
|
||||
// Detect if are are in a Next.js project
|
||||
const isNextJsProject = await detectNextJsProject(resolvedPath);
|
||||
const isNuxtJsProject = await detectNuxtJsProject(resolvedPath);
|
||||
// Add checks for other frameworks here
|
||||
|
||||
if (!isNextJsProject) {
|
||||
if (!isNextJsProject && !isNuxtJsProject) {
|
||||
logger.error(
|
||||
"We currently only support automatic setup for Next.js projects (we didn't detect one). View our manual installation guides for all frameworks: https://trigger.dev/docs/documentation/quickstarts/introduction"
|
||||
"We currently only support automatic setup for Next.js and Nuxt.js projects (we didn't detect one). View our manual installation guides for all frameworks: https://trigger.dev/docs/documentation/quickstarts/introduction"
|
||||
);
|
||||
telemetryClient.init.failed("not_nextjs_project", options);
|
||||
telemetryClient.init.failed("not_supported_project", options);
|
||||
return;
|
||||
} else {
|
||||
} else if (isNextJsProject) {
|
||||
logger.success("✅ Detected Next.js project");
|
||||
} else if (isNuxtJsProject) {
|
||||
logger.success("✅ Detected Nuxt.js project");
|
||||
}
|
||||
|
||||
const hasGitChanges = await detectGitChanges(resolvedPath);
|
||||
|
||||
if (hasGitChanges) {
|
||||
@@ -123,18 +127,32 @@ export const initCommand = async (options: InitCommandOptions) => {
|
||||
|
||||
const routeDir = pathModule.join(resolvedPath, usesSrcDir ? "src" : "");
|
||||
|
||||
if (nextJsDir === "pages") {
|
||||
telemetryClient.init.createFiles(resolvedOptions, "pages");
|
||||
await createTriggerPageRoute(
|
||||
resolvedPath,
|
||||
routeDir,
|
||||
resolvedOptions,
|
||||
isTypescriptProject,
|
||||
usesSrcDir
|
||||
);
|
||||
} else {
|
||||
telemetryClient.init.createFiles(resolvedOptions, "app");
|
||||
await createTriggerAppRoute(
|
||||
let framework = "";
|
||||
|
||||
if (isNextJsProject) {
|
||||
framework = "Next.js";
|
||||
if (nextJsDir === "pages") {
|
||||
telemetryClient.init.createFiles(resolvedOptions, "pages");
|
||||
await createTriggerPageRoute(
|
||||
resolvedPath,
|
||||
routeDir,
|
||||
resolvedOptions,
|
||||
isTypescriptProject,
|
||||
usesSrcDir
|
||||
);
|
||||
} else {
|
||||
telemetryClient.init.createFiles(resolvedOptions, "app");
|
||||
await createTriggerAppRoute(
|
||||
resolvedPath,
|
||||
routeDir,
|
||||
resolvedOptions,
|
||||
isTypescriptProject,
|
||||
usesSrcDir
|
||||
);
|
||||
}
|
||||
} else if (isNuxtJsProject) {
|
||||
framework = "Nuxt.js";
|
||||
await createTriggerNuxtRoute(
|
||||
resolvedPath,
|
||||
routeDir,
|
||||
resolvedOptions,
|
||||
@@ -144,20 +162,23 @@ export const initCommand = async (options: InitCommandOptions) => {
|
||||
}
|
||||
|
||||
await detectMiddlewareUsage(resolvedPath, usesSrcDir);
|
||||
|
||||
await addConfigurationToPackageJson(resolvedPath, resolvedOptions);
|
||||
|
||||
await printNextSteps(resolvedOptions, authorizedKey);
|
||||
await printNextSteps(resolvedOptions, authorizedKey, framework);
|
||||
telemetryClient.init.completed(resolvedOptions);
|
||||
};
|
||||
|
||||
async function printNextSteps(options: ResolvedOptions, authorizedKey: WhoamiResponse) {
|
||||
async function printNextSteps(
|
||||
options: ResolvedOptions,
|
||||
authorizedKey: WhoamiResponse,
|
||||
framework: string
|
||||
) {
|
||||
const projectUrl = `${options.triggerUrl}/orgs/${authorizedKey.organization.slug}/projects/${authorizedKey.project.slug}`;
|
||||
|
||||
logger.success(`✅ Successfully initialized Trigger.dev!`);
|
||||
|
||||
logger.info("Next steps:");
|
||||
logger.info(` 1. Run your Next.js project locally with 'npm run dev'`);
|
||||
logger.info(` 1. Run your ${framework} project locally with 'npm run dev'`);
|
||||
logger.info(
|
||||
` 2. In a separate terminal, run 'npx @trigger.dev/cli@latest dev' to watch for changes and automatically register Trigger.dev jobs`
|
||||
);
|
||||
@@ -444,6 +465,108 @@ function getPathAlias(tsconfig: any, usesSrcDir: boolean) {
|
||||
return;
|
||||
}
|
||||
|
||||
async function createTriggerNuxtRoute(
|
||||
projectPath: string,
|
||||
path: string,
|
||||
options: ResolvedOptions,
|
||||
isTypescriptProject: boolean,
|
||||
usesSrcDir = false
|
||||
) {
|
||||
const extension = isTypescriptProject ? ".ts" : ".js";
|
||||
const triggerFileName = `trigger${extension}`;
|
||||
const routeFileName = `trigger${extension}`;
|
||||
|
||||
const routeContent = `
|
||||
import { client } from "@/trigger";
|
||||
import { createNuxtRoute} from "@trigger.dev/nuxtjs"
|
||||
import { eventTrigger } from "@trigger.dev/sdk";
|
||||
|
||||
const QUOTES = [
|
||||
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler",
|
||||
"First, solve the problem. Then, write the code. - John Johnson",
|
||||
"Experience is the name everyone gives to their mistakes. - Oscar Wilde",
|
||||
"In order to be irreplaceable, one must always be different - Coco Chanel",
|
||||
"Knowledge is power. - Francis Bacon",
|
||||
"Sometimes it pays to stay in bed on Monday, rather than spending the rest of the week debugging Monday's code. - Dan Salomon",
|
||||
"Perfection is achieved not when there is nothing more to add, but rather when there is nothing more to take away. - Antoine de Saint-Exupery",
|
||||
"Rust is the most loved programming language. - Stack Overflow",
|
||||
"Code is like humor. When you have to explain it, it’s bad. - Cory House",
|
||||
"Fix the cause, not the symptom. - Steve Maguire",
|
||||
];
|
||||
|
||||
client.defineJob({
|
||||
id: "hello-world",
|
||||
name: "Hello World",
|
||||
version: "0.0.1",
|
||||
trigger: eventTrigger({
|
||||
name: "starter.hello-world",
|
||||
}),
|
||||
run: async (_payload, io, _ctx) => {
|
||||
await io.logger.info("Hello world!");
|
||||
|
||||
return {
|
||||
message: "Hello world!",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
client.defineJob({
|
||||
id: "quote",
|
||||
name: "Random Quote",
|
||||
version: "0.0.1",
|
||||
trigger: eventTrigger({
|
||||
name: "starter.quote",
|
||||
}),
|
||||
run: async (_payload, _io, _ctx) => {
|
||||
return {
|
||||
quote: QUOTES[Math.floor(Math.random() * QUOTES.length)],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
//this route is used to send and receive data with Trigger.dev
|
||||
const nuxt = createNuxtRoute(client);
|
||||
|
||||
export default defineEventHandler(nuxt)
|
||||
`;
|
||||
|
||||
const triggerContent = `
|
||||
import { TriggerClient } from "@trigger.dev/sdk";
|
||||
|
||||
export const client = new TriggerClient({
|
||||
id: "${options.endpointSlug}",
|
||||
apiKey: process.env.TRIGGER_API_KEY,
|
||||
apiUrl: process.env.TRIGGER_API_URL,
|
||||
});
|
||||
`;
|
||||
|
||||
const directories = pathModule.join(path, "server", "api");
|
||||
await fs.mkdir(directories, { recursive: true });
|
||||
|
||||
const fileExists = await pathExists(pathModule.join(directories, routeFileName));
|
||||
|
||||
if (fileExists) {
|
||||
logger.info("Skipping creation of server route because it already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
await fs.writeFile(pathModule.join(directories, routeFileName), routeContent);
|
||||
|
||||
logger.success(
|
||||
`✅ Created app route at ${usesSrcDir ? "src/" : ""}server/api/${removeFileExtension(
|
||||
triggerFileName
|
||||
)}/${routeFileName}`
|
||||
);
|
||||
|
||||
const triggerFileExists = await pathExists(pathModule.join(path, triggerFileName));
|
||||
|
||||
if (!triggerFileExists) {
|
||||
await fs.writeFile(pathModule.join(path, triggerFileName), triggerContent);
|
||||
|
||||
logger.success(`✅ Created trigger client at ${usesSrcDir ? "src/" : ""}${triggerFileName}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function createTriggerAppRoute(
|
||||
projectPath: string,
|
||||
path: string,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import fs from "fs/promises";
|
||||
import pathModule from "path";
|
||||
import { readPackageJson } from "./readPackageJson";
|
||||
|
||||
/** Detects if the project is a Nuxt.js project at path */
|
||||
export async function detectNuxtJsProject(path: string): Promise<boolean> {
|
||||
const hasNuxtConfigFile = await detectNuxtConfigFile(path);
|
||||
if (hasNuxtConfigFile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return await detectNuxtDependency(path);
|
||||
}
|
||||
|
||||
async function detectNuxtConfigFile(path: string): Promise<boolean> {
|
||||
return fs
|
||||
.access(pathModule.join(path, "nuxt.config.ts"))
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
}
|
||||
|
||||
async function detectNuxtDependency(path: string): Promise<boolean> {
|
||||
const packageJsonContent = await readPackageJson(path);
|
||||
if (!packageJsonContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return packageJsonContent.dependencies?.nuxt !== undefined;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
"emitDecoratorMetadata": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"types": ["jest"]
|
||||
"types": ["jest", "node"],
|
||||
"lib": ["DOM", "ES2016"]
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# @trigger.dev/nuxtjs
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Major Changes
|
||||
- Initial Release
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Trigger.dev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Nuxt.js and Trigger.dev
|
||||
|
||||
Trigger.dev has full support for the Nuxt.js framework.
|
||||
|
||||
For information about the using Trigger.dev in your Nuxt.js app, check out these useful docs links:
|
||||
|
||||
- [Quick start guide for getting setup with Trigger.dev in a Nuxt.js project](https://trigger.dev/docs/documentation/quickstarts/nuxt)
|
||||
- [Manually setup Nuxt.js with Trigger.dev](https://trigger.dev/docs/documentation/guides/manual/nuxt)
|
||||
- [Using Trigger.dev with Nuxt.js, handling middleware and more](https://trigger.dev/docs/documentation/guides/platforms/nuxt)
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@trigger.dev/nuxtjs",
|
||||
"version": "0.0.1",
|
||||
"description": "Trigger.dev Nuxt.js integration",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/ws": "^8.5.3",
|
||||
"nuxt": "^3.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsup": "^6.5.0",
|
||||
"tsx": "^3.12.1",
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"build": "npm run clean && npm run build:tsup",
|
||||
"build:tsup": "tsup",
|
||||
"dev": "tsup --watch"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@remix-run/web-fetch": "^4.3.5",
|
||||
"debug": "^4.3.4",
|
||||
"h3": "^1.8.1",
|
||||
"nuxt3": "3.7.2-28233838.48fb6e24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.8.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { TriggerClient } from "@trigger.dev/sdk";
|
||||
import { Request as StandardRequest, Headers as StandardHeaders } from "@remix-run/web-fetch";
|
||||
import type { EventHandlerRequest, H3Event, NodeIncomingMessage } from "h3";
|
||||
|
||||
function getRequestBody(req: NodeIncomingMessage): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let body = '';
|
||||
req.on('data', chunk => {
|
||||
body += chunk.toString();
|
||||
});
|
||||
req.on('end', () => {
|
||||
resolve(body);
|
||||
});
|
||||
req.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const createNuxtRoute = (client: TriggerClient) => {
|
||||
return async (event: H3Event<EventHandlerRequest>) => {
|
||||
if (event.node.req.method === "HEAD") {
|
||||
event.node.res.statusCode = 200;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const request = await convertToStandardRequest(event.node.req);
|
||||
const response = await client.handleRequest(request);
|
||||
|
||||
if (!response) {
|
||||
event.node.res.statusCode = 404;
|
||||
event.node.res.setHeader("Content-Type", "application/json");
|
||||
event.node.res.end(JSON.stringify({ error: "Not found" }));
|
||||
return;
|
||||
}
|
||||
|
||||
event.node.res.statusCode = response.status;
|
||||
event.node.res.setHeader("Content-Type", "application/json");
|
||||
event.node.res.end(JSON.stringify(response.body));
|
||||
} catch (error) {
|
||||
event.node.res.statusCode = 500;
|
||||
event.node.res.setHeader("Content-Type", "application/json");
|
||||
event.node.res.end(JSON.stringify({ error: (error as Error).message }));
|
||||
}
|
||||
};
|
||||
|
||||
async function convertToStandardRequest(req: NodeIncomingMessage): Promise<StandardRequest> {
|
||||
const { headers: nuxtHeaders, method } = req;
|
||||
|
||||
const headers = new StandardHeaders();
|
||||
|
||||
Object.entries(nuxtHeaders).forEach(([key, value]) => {
|
||||
headers.set(key, value as string);
|
||||
});
|
||||
const body = await getRequestBody(req)
|
||||
// Create a new Request object (hardcode the url because it doesn't really matter what it is)
|
||||
return new StandardRequest("https://nuxt.js/api/trigger", {
|
||||
headers,
|
||||
method,
|
||||
body: body,
|
||||
// @ts-ignore
|
||||
duplex: "half",
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "@trigger.dev/tsconfig/node18.json",
|
||||
"include": ["./src/**/*.ts", "tsup.config.ts"],
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"lib": ["DOM", "DOM.Iterable"],
|
||||
"paths": {
|
||||
"@trigger.dev/sdk": ["../trigger-sdk/src/index"],
|
||||
"@trigger.dev/sdk/*": ["../trigger-sdk/src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { defineConfig } from "tsup";
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
name: "main",
|
||||
entry: ["./src/index.ts"],
|
||||
outDir: "./dist",
|
||||
platform: "node",
|
||||
format: ["cjs"],
|
||||
legacyOutput: true,
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
bundle: true,
|
||||
splitting: false,
|
||||
dts: true,
|
||||
external: ["http", "https", "util", "events", "tty", "os", "timers"],
|
||||
esbuildPlugins: [],
|
||||
},
|
||||
]);
|
||||
Generated
+14525
-12436
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user