Skip to content

Commit

Permalink
feat(nuxt): add node-cron module (#60)
Browse files Browse the repository at this point in the history
* feat(nuxt): add node-cron module

* feat: add docs
  • Loading branch information
productdevbook authored Dec 12, 2023
1 parent ec241a1 commit d4b8172
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .docs/content/pergel/3.nuxt/1.index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Nuxt is a framework for creating Vue applications. Pergel is a full stack Nuxt a
S3 is a simple storage service that offers an extremely durable, highly available, and ...
::

::card{icon="i-ph-cube-duotone" title="NodeCron - Soon" to="#"}
::card{icon="i-ph-cube-duotone" title="NodeCron" to="/pergel/nuxt/nodecron/installation"}
NodeCron is a simple cron-like job scheduler for Node.js.
::

Expand Down
80 changes: 80 additions & 0 deletions .docs/content/pergel/3.nuxt/nodeCron/1.installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: Installation
description: 'Pergel Node Cron Module Installation'
---

1. Add it to your `modules` section of `nuxt.config`:

::code-group
```ts [nuxt.config.ts]
export default defineNuxtConfig({
modules: ['@pergel/nuxt'],
pergel: {
projects: {
myproject: {
nodeCron: true,
},
// bookList: {
// nodeCron: false
// },
},
},
})
```
::

::callout{color="amber" icon="i-ph-warning-duotone"}
Node >= 20.8.0 is required.
Nuxt >= 3.9.0 is required.
::


2. Auto install dependencies:

::code-group
```sh [pnpm]
pergel install
```
::

:read-more{title="Install Pergel CLI" to="/pergel/cli"}

3. Create 'server/plugins/pluginName.ts' file:

Note: You can change the plugin name.

::code-group
```ts [server/plugins/pluginName.ts]
export default pergelMyproject().nodeCron().nitroPlugin({
setup: async (cron, nitroApp) => {
cron.every.seconds(3, () => {
console.warn('running a task every 3 seconds')
})
// cron.every.minutes(5, () => {
// console.warn('running a task every 5 minutes')
// })
// cron.every.thirtyMinutes(() => {
// console.warn('running a task every 30 minutes')
// })
// cron.schedule('*/5 * * * * *', () => {
// console.warn('running a task every 5 seconds')
// })
},
onError: async (error: any) => {
console.warn(error.message)
},
config: {
log: true,
},
})
```

```ts [composables]
pergelMyproject().nodeCron().nitroComposable({})
```

::

::callout{icon="i-ph-check-circle-duotone" color="green"}
Well done! You have successfully Node Cron Module installed.
::
2 changes: 2 additions & 0 deletions .docs/content/pergel/3.nuxt/nodeCron/_dir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
title: Node Cron
icon: i-ph-timer
2 changes: 2 additions & 0 deletions packages/nuxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@
"@nuxt/test-utils": "^3.8.1",
"@pergel/module-s3": "workspace:^",
"@types/node": "^20.9.3",
"@types/node-cron": "^3.0.11",
"esbuild-plugin-file-path-extensions": "^2.0.0",
"node-cron": "^3.0.3",
"nuxt": "^3.8.2",
"vitest": "^0.33.0"
},
Expand Down
1 change: 1 addition & 0 deletions packages/nuxt/playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default defineNuxtConfig({
projects: {
test: {
S3: true,
nodeCron: true,
},
test2: {
S3: true,
Expand Down
5 changes: 5 additions & 0 deletions packages/nuxt/playground/pergel/README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ pergel:
# This file is generated by pergel. Do not edit it manually.
# Version: 0.0.1
test:
nodeCron:
# If pergel cli is installed, you can run `pergel install` automatically to install
packageJson:
dependencies: "node-cron@^3.0.3"
devDependencies: "@types/node-cron@^3.0.11"
S3:
env:
NUXT_TEST_S3_REGION: auto
Expand Down
22 changes: 22 additions & 0 deletions packages/nuxt/playground/server/plugins/cron1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default pergelTest().nodeCron().nitroPlugin({
setup: async (_cron) => {
// cron.every.seconds(3, () => {
// console.warn('running a task every 3 seconds')
// })
// cron.every.minutes(5, () => {
// console.warn('running a task every 5 minutes')
// })
// cron.every.thirtyMinutes(() => {
// console.warn('running a task every 30 minutes')
// })
// cron.schedule('*/5 * * * * *', () => {
// console.warn('running a task every 5 seconds')
// })
},
onError: async (error: any) => {
console.warn(error.message)
},
config: {
log: true,
},
})
1 change: 1 addition & 0 deletions packages/nuxt/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default defineNuxtModule<PergelOptions>({
},
modules: [
'S3',
'nodeCron',
],
resolver: _resolver,
devServerHandler: [],
Expand Down
1 change: 1 addition & 0 deletions packages/nuxt/src/runtime/core/types/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Nuxt } from '@nuxt/schema'

export interface Modules {
S3?: true
nodeCron?: true
}

export interface PergelOptions {
Expand Down
106 changes: 106 additions & 0 deletions packages/nuxt/src/runtime/modules/nodeCron/composables/nitroPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import consola from 'consola'
import cron from 'node-cron'
import type { getTasks, schedule, validate } from 'node-cron'
import type { NitroApp } from 'nitropack'
import { defineNitroPlugin } from 'nitropack/dist/runtime/plugin'

interface EveryCronTime {
seconds: (number: number, handleDate: (result: string) => void) => void
minutes: (number: number, handleDate: (result: string) => void) => void
hours: (number: number, handleDate: (result: string) => void) => void
days: (number: number, handleDate: (result: string) => void) => void
weeks: (number: number, handleDate: (result: string) => void) => void
months: (number: number, handleDate: (result: string) => void) => void
thirtyMinutes: (handleDate: (result: string) => void) => void
}

interface CronType {
schedule: typeof schedule
getTasks: typeof getTasks
validate: typeof validate
every: EveryCronTime
}

interface NodeCronConfig {
setup: (cron: CronType, nitroApp: Promise<NitroApp> | NitroApp) => void | Promise<void>
onError?: (err: Error | undefined) => void | Promise<void>
config?: {
log: boolean
}
}

export function defineNitroPergelNodeCronPlugin(
{ setup, onError, config }: NodeCronConfig,
) {
return defineNitroPlugin(async (_nitro) => {
try {
if (import.meta.prerender) {
if (config?.log)
consola.info('[server/plugins/node-cron.ts] Skipping node-cron, don\'t run in build context')
return
}

if (config?.log)
consola.info('[server/plugins/node-cron.ts] Starting node-cron and running once now...')

await setup({
schedule: cron.schedule,
getTasks: cron.getTasks,
validate: cron.validate,
every: {
seconds: everySeconds,
minutes: everyMinutes,
hours: everyHours,
days: everyDays,
weeks: everyWeeks,
months: everyMonths,
thirtyMinutes: everyThirtyMinutes,

},
}, _nitro)
}
catch (error: any) {
if (onError)
await onError(error)
}
})
}

// # ┌────────────── second (optional)
// # │ ┌──────────── minute
// # │ │ ┌────────── hour
// # │ │ │ ┌──────── day of month
// # │ │ │ │ ┌────── month
// # │ │ │ │ │ ┌──── day of week
// # │ │ │ │ │ │
// # │ │ │ │ │ │
// # * * * * * *

function everySeconds(seconds: number = 1, handleDate: (result: string) => void) {
cron.schedule(`*/${seconds} * * * * *`, () => handleDate(new Date().toISOString()))
}

function everyMinutes(minutes: number, handleDate: (result: string) => void) {
cron.schedule(`*/${minutes} * * * *`, () => handleDate(new Date().toISOString()))
}

function everyThirtyMinutes(handleDate: (result: string) => void) {
cron.schedule(`*/30 * * * *`, () => handleDate(new Date().toISOString()))
}

function everyHours(hours: number, handleDate: (result: string) => void) {
cron.schedule(`0 */${hours} * * *`, () => handleDate(new Date().toISOString()))
}

function everyDays(days: number, handleDate: (result: string) => void) {
cron.schedule(`0 0 */${days} * *`, () => handleDate(new Date().toISOString()))
}

function everyMonths(number: number, handleDate: (result: string) => void) {
cron.schedule(`*/${number} *`, () => handleDate(new Date().toISOString()))
}

function everyWeeks(number: number, handleDate: (result: string) => void) {
const _day = 7 * number
cron.schedule(`*/${_day} * *`, () => handleDate(new Date().toISOString()))
}
37 changes: 37 additions & 0 deletions packages/nuxt/src/runtime/modules/nodeCron/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { addServerImportsDir, createResolver } from '@nuxt/kit'
import { definePergelModule } from '../../core/definePergel'

export default definePergelModule({
meta: {
name: 'nodeCron',
version: '0.0.1',
dependencies: {
'node-cron': '^3.0.3',
},
devDependencies: {
'@types/node-cron': '^3.0.11',
},
},
defaults: {},
async setup(options) {
const resolver = createResolver(import.meta.url)
const projectName = options.resolvedModule.projectName

addServerImportsDir(resolver.resolve('./composables'))

options._contents.push({
moduleName: 'nodeCron',
projectName,
content: /* ts */`
function nodeCron() {
return {
nitroPlugin: defineNitroPergelNodeCronPlugin
}
}
`,
resolve: /* ts */`
nodeCron: nodeCron,
`,
})
},
})
18 changes: 17 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d4b8172

Please sign in to comment.