hattipjs / hattip

Like Express, but for the future
MIT License
1.22k stars 15 forks source link

Zero-config library integrations #18

Open brillout opened 1 year ago

brillout commented 1 year ago

For example:

// node_modules/some-auth-library/package.json

{
  "name": "some-auth-library",
  "exports": {
    "./hattip-auto-integration": "./dist/hattip.js"
  }
}
// node_modules/some-auth-library/hattip.ts

export default {
  addHattipMiddleware,
}

function addHattipMiddleware() {
  return (ctx) => {
    const response = await ctx.next();
    response.headers.set("Cookie", "auth-secret=...");
    return response;
  }
}

I would even go as far as to have HatTip read the pacakge.json#exports of all dependencies to see if they contain a HatTip zero-config integration.

So that all the user has to do is to npm install some-auth-library. Zero integration code needed. Works across all JS server platforms.

cyco130 commented 1 year ago

This idea is kind of growing on me. Do you know anyone else doing this?

brillout commented 1 year ago

I don't think anyone else does this, and I think we should do it :-).

brillout commented 1 year ago

A user today on Discord:

I'm considering using some other language for the backend that has batteries included framework eg Laravel. I feel like there is nothing alike in node ecosystem [...] I'm tired of stitching together packages from various developers and keeping that up to date. All of them have different release cycles too

Speaks volume of how much library zero-config integration is being craved for.

brillout commented 1 year ago

@elderapo Curious: why the downvote?

elderapo commented 1 year ago

@brillout, a few things:

if (!process.env.DISABLE_AUTH) { app.use(authMiddleware()); }

if (!process.env.DISABLE_LOGGER) { app.use(loggerMiddleware()); }

- How would you pass configurations to such middleware:
```ts
import { loggerMiddleware } from '@elderapo/hattip-middlewares';

app.use(loggerMiddleware({ level: "debug }));
brillout commented 1 year ago
// hattip.config.js

import { auth } from 'awesome-auth/hattip'
import { logger } from 'awesome-logger/hattip'

// HaTip loads `hattip.config.js` before it auto-loads npm packages. It sees that `auth()` and `logger()` are
// already installed and therefore skips auto-loading them.
export default {
  plugins: [
   auth({ strategy: 'one_time_password' }),
   logger({ disable: process.env.DISABLE_LOGGER })
  ]
}

I believe this addresses all your concern.

Thing is, it becomes cumbersome to have to add your tool's plugins to Vite, HatTip and potentially more tools.

elderapo commented 1 year ago

I don't see how that is any better than normally applying middlewares. What is wrong with the following code that needs fixing:

// handler.ts

import { compose } from "@hattip/compose";

import { auth } from 'awesome-auth/hattip'
import { logger } from 'awesome-logger/hattip'

export const handler = compose(
  authMiddleware({ strategy: 'one_time_password' }),
  logger({ disable: process.env.DISABLE_LOGGER }),

  ...
);
brillout commented 1 year ago

If it were only about adding one plugin to HatTip, then I'd agree. But it starts to become annoying when installing one tool means to 1. add a plugin to HatTip, 2. add a plugin to Vite, etc.

Reducing the installation step to a single step npm insall awesome-tool makes a non-negligible difference than having a 10-step installation guide. I'm exagerating with 10 steps, but you get the point. Two steps would be fine, I agree, but three steps starts to become enough of a justification for implementing a zero-config mechanism as described in OP.

elderapo commented 1 year ago

If it were only about adding one plugin to HatTip, then I'd agree. But it starts to become annoying when installing one tool means to 1. add a plugin to HatTip, 2. add a plugin to Vite, etc.

Hmm... why would custom hattip middleware require plugin to be added to vite? Got some real-world example in mind?

Reducing the installation step to a single step npm insall awesome-tool makes a non-negligible difference than having a 10-step installation guide. I'm exagerating with 10 steps, but you get the point. Two steps would be fine, I agree, but three steps starts to become enough of a justification for implementing a zero-config mechanism as described in OP.

I am not sure this is such a big deal tbh...

brillout commented 1 year ago

Telefunc and vite-plugin-ssr: both need integration with Vite as well as with HatTip.

brillout commented 1 year ago

Closing for now. I'll re-open it in the future when the need for this arises.

brillout commented 1 year ago

I'll re-open it in the future when the need for this arises.

Now relevant for https://github.com/hattipjs/hattip/issues/51.

Basically:

// node_modules/vite-plugin-ssr/package.json

{
  name: "vite-plugin-ssr",
  exports: {
    "./hattip-auto-integration": "./dist/entry-hattip.js"
  }
}
// node_modules/vite-plugin-ssr/dist/entry-hattip.js

export default handler;

import { renderPage } from 'vite-plugin-ssr/server'

async function handler(ctx) {
  const pageContextInit = { urlOriginal: ctx.request.url }
  const pageContext = await renderPage(pageContextInit)
  const { body, statusCode, contentType } = pageContext.httpResponse
  return new Response(body, {
    status: statusCode,
    headers: {
      "Content-Type": contentType
    }
  })
}

This means HatTip seamlessly integrates with the meta framework. No hattip.config.js needed.

To support meta frameworks that don't have a package.json.exports["./hattip-auto-integration"] yet, we can ship the glue code as e.g. @hattip/vite-plugin-ssr.