Skip to content

Commit

Permalink
feat: add article on how I'm funded (#1359)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielroe authored Jan 28, 2024
1 parent ba7973c commit d4ce395
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 35 deletions.
13 changes: 8 additions & 5 deletions src/components/TheHome.server.vue
Original file line number Diff line number Diff line change
Expand Up @@ -440,11 +440,14 @@ const { data: talks } = await useAsyncData(
</header>
<!-- TODO: use randomised sponsor list -->
<TheSponsors />
<!-- <p class="mt-4">
<NuxtLink to="/blog/funding" class="underlined-link text-sm">
more about how I'm funded &raquo;
</NuxtLink>
</p> -->
<p class="mt-4">
<NuxtLink
to="/blog/funding"
class="underlined-link text-sm"
>
more about how I'm funded &raquo;
</NuxtLink>
</p>
</section>
</template>

Expand Down
55 changes: 55 additions & 0 deletions src/content/blog/funding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
title: How I'm funded
date: '2024-01-28T09:00:00.000Z'
tags:
- open source
- funding
description: "Being a full-time open-source maintainer is a rare privilege. In the interests of transparency, let me explain a little more about how I am funded."
---

Being a full-time open-source maintainer is a rare privilege. In the interests of transparency, let me explain a little more about how I am funded.

## My story

I had been increasingly involved in open source - and particularly in contributing to the [Nuxt](https://nuxt.com/) ecosystem - whilst running first a creative agency and then a SaaS startup.

But when I decided (with my co-founder) to shut down the startup, [Sébastien Chopin](https://atinux.com/) asked if he could sponsor me to work on Nuxt. I was already committed to the core team - so it didn't take me long to accept.

<h2 id="nuxtlabs" class="mb-1"><img src="/img/work/nuxtlabs.svg" alt="NuxtLabs" width="90"></h2>

The majority of my funding comes from a retainer with NuxtLabs.

Sébastien Chopin, who created Nuxt and founded NuxtLabs, receives donations via the Nuxt GitHub Sponsors account (and other income streams) and in turn funnels that back into the community, sponsoring [a number of open-source developers](https://github.com/orgs/nuxtlabs/sponsoring) and enabling open-source work.

I prize my independence highly and deeply appreciate Sébastien's trust.

## Sponsorship

While I don't receive any direct funding from Nuxt via GitHub Sponsors, I do have [a number of individual and corporate sponsors](https://github.com/sponsors/danielroe) that I value very highly.

I see [open source as about 'mutual giving'](http://localhost:3000/blog/contributing-to-nuxt#what-open-source-is-to-me) and I appreciate these givers.

<!-- TODO: sponsor carousel -->

Their kindness enables me to devote additional time to open source, and to ensure it remains sustainable for me. I am looking for opportunities to thank my sponsors for their generosity, and would welcome ideas 🙏

## Workshops and conferences

I am sometimes asked to give paid-for workshops at conferences, and I receive a share of the revenue of these workshops.

In addition, conferences cover the costs of my flights and hotel and (sometimes) a speaker's fee.

If cost is ever a factor, **please ask**. I do not charge for community events, nor do I speak at conferences for financial reasons.

## Consultancy

The time I have to work on projects outside of open source is limited. However, real-world projects help keep me relevant and grounded.

If you think your company would value a consultancy arrangement with me, please reach out. I am looking for:

- recurring duration (such as a monthly retainer)
- scheduled and measurable contributions

It is also possible to book a single hour's consultation with me.

:CalSchedule{meeting=consult message="Schedule a consultation"}
2 changes: 1 addition & 1 deletion src/middleware/cal.global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const styleConfig = {
}

export default defineNuxtRouteMiddleware(to => {
if (to.path === '/blog/open-invitation') {
if (to.path === '/blog/open-invitation' || to.path === '/blog/funding') {
useHead({
script: [
{
Expand Down
54 changes: 26 additions & 28 deletions src/modules/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default defineNuxtModule({
meta: {
name: 'custom-router',
},
setup() {
setup () {
const nuxt = useNuxt()
const resolver = createResolver(import.meta.url)
nuxt.options.pages = false
Expand Down Expand Up @@ -87,44 +87,42 @@ export default defineNuxtModule({

addTemplate({
filename: 'routes.mjs',
async getContents() {
async getContents () {
const files = await readRecursive(resolver.resolve('../pages'))
const componentNames = Object.fromEntries(
files.map(f => [f, genSafeVariableName(f)])
)
const routes = files.map(f => {
const path = withLeadingSlash(
relative(resolver.resolve('../pages'), f).replace(
/(\/?index)?\.vue$/,
''
)
)
return {
path: path.includes('[')
? `/${path
.replace(/\[(.*)\]/g, '(?<$1>.+)')
.replace(/\//g, '\\/')}/`
: genString(path),
// component: `defineAsyncComponent(${genDynamicImport(f, {
// interopDefault: true,
// })})`,
component: componentNames[f],
meta: JSON.stringify(routeMeta[path] || {}),
}
})

return `
// import { defineAsyncComponent } from 'vue';
${Object.entries(componentNames)
.map(([path, name]) => genImport(path, { name }))
.join('\n')}
export default ${genArrayFromRaw(
files.map(f => {
const path = withLeadingSlash(
relative(resolver.resolve('../pages'), f).replace(
/(\/?index)?\.vue$/,
''
)
)
return {
path: path.includes('[')
? `/${path
.replace(/\[(.*)\]/g, '(?<$1>.+)')
.replace(/\//g, '\\/')}/`
: genString(path),
// component: `defineAsyncComponent(${genDynamicImport(f, {
// interopDefault: true,
// })})`,
component: componentNames[f],
meta: JSON.stringify(routeMeta[path] || {}),
}
})
)}`
${Object.entries(componentNames).map(([path, name]) => genImport(path, { name })).join('\n')}
export default ${genArrayFromRaw(routes)}`
},
})
},
})

async function readRecursive(dir: string) {
async function readRecursive (dir: string) {
const files = await fsp.readdir(dir)
const result: string[] = []
for (const file of files) {
Expand Down
Binary file modified test/e2e/ssr.spec.ts-snapshots/pages-renders-1-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/unit/bundle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ describe('project sizes', () => {
stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect
.soft(roundToKilobytes(stats.server.totalBytes))
.toMatchInlineSnapshot(`"422k"`)
.toMatchInlineSnapshot(`"425k"`)

const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect
Expand Down

1 comment on commit d4ce395

@vercel
Copy link

@vercel vercel bot commented on d4ce395 Jan 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.