Coder Social home page Coder Social logo

Comments (42)

remorses avatar remorses commented on April 28, 2024 10

For anyone trying to use _middleware.js without next i am going to list some findings that may be useful:

  • you must have a package.json file on root too or it won't work.
  • Another cool thing to know is that you can also use _middleware.ts (using typescript) without any configuration because vercel bundles the _middleware file with esbuild on deployment
  • if you are trying to use NextResponse.rewrite from nextjs, you can use the following function for the same result
function rewrite(destination) {
    return new Response(null, {
        headers: {
            'x-middleware-rewrite':
                typeof destination === 'string'
                    ? destination
                    : destination.toString(),
        },
    })
}
  • For other cases just replace NextResponse with Response
  • To get req.nextUrl.pathname you can do new URL(req.url).pathname

from examples.

leerob avatar leerob commented on April 28, 2024 6

We're still working on it - apologies for the delay.

from examples.

edcrampin avatar edcrampin commented on April 28, 2024 6

A bit of progress in the last half an hour from digging around in next/server at the NextResponse class - this is just an extension of the Response class in the same way NextRequest extends the Request class.

NextResponse.next() which is used to pass control to the next middleware function in the examples in this repo (or will serve your content if there is no more middleware in place) can be replicated by returning the below. Vercel must pick this header up and know to pass this to the next middleware.

return new Response(null, {
  headers: {
    'x-middleware-next': '1',
  },
});

You can do rewrites in a similar fashion, using a x-middleware-rewrite header and passing a URL as the value. For more info take a look at the NextRequest class in the Next.js repo.

One major issue I'm currently having is that if you write a blank middleware such as below, the middleware successfully runs and your app is 'served', however any assets (.css, .js) seem to throw a 404 when requested by your app. I'm not sure if this is something I've misconfigured, but this makes my setup essentially unusable. I can seem to access the file directly and the Vercel cache header reports a 'HIT', so not sure why I'm getting a 404 for these...

Another thing I'm having issues with is that even though Vercel's middleware are run through ESBuild, I cannot seem to use any ES6 functionality and have to write much more primitive JS. I can't use things such as Array.get or the Buffer class.

I've managed to convert the basic-auth-password middleware and get it sort of working despite the above, but I hit the issue with CSS/JS assets throwing 404s meaning I can't take it any further at the mo. My demo can be found here and the code for the _middleware.ts file I used is below.

export default function middleware(req: Request) {
  const basicAuth = req.headers['authorization'];

  if (basicAuth) {
    const auth = basicAuth.split(' ')[1]
    const decodedAuth = atob(auth).split(':');
    const user = decodedAuth[0];
    const pwd = decodedAuth[1];

    if (user === '4dmin' && pwd === 'testpwd123') {
      return new Response(null, {
        headers: {
          'x-middleware-next': '1',
        },
      })
    }
  }

  return new Response('Auth required', {
    status: 401,
    headers: {
      'WWW-Authenticate': 'Basic realm="Secure Area"',
    },
  })
}

from examples.

dapptain avatar dapptain commented on April 28, 2024 5

Any update on documentation for non-nextjs projects? All the above is helpful, but something a bit more formal would be much appreciated.

from examples.

leerob avatar leerob commented on April 28, 2024 4

Hey! We’re working on adding some examples for this. Middleware does indeed work with any framework, or just vanilla HTML, by placing the _middleware file in your root directly (or for framework authors, using the File System API).

from examples.

edcrampin avatar edcrampin commented on April 28, 2024 4

@brycewray agreed, I've been planning to raise a PR to add something like this for a few basic examples using both the file system API and potentially also fully vanilla (single middleware file?) but struggling to get the time to look at this for now. The main nuisance to work around is how to organise middleware examples in this repo, and then also re-working the plop scripts to support this new structure.

I'd propose edge-functions would consist of three subdirectories, something like:

  • nextjs
  • vanilla
  • filesystem-api

...and moving all existing examples to the nextjs dir and starting to recreate some of the existing Next.js examples in the other subdirectories.

from examples.

edcrampin avatar edcrampin commented on April 28, 2024 4

@brycewray sounds completely sensible - I'll see what I can do.

from examples.

edcrampin avatar edcrampin commented on April 28, 2024 4

@brycewray here's an example of an add-header and basic-auth middleware using create-react-app. The _middleware.ts file is compiled by ESBuild at build time within Vercel so having TypeScript does not matter despite being a non-TS project. These two examples are currently deployed here:

These mostly work but I'm coming across the same issue as I mentioned previously where certain assets return a 404 which I believe to be a bug within Vercel somewhere as certain assets load fine whilst others don't. Here's an example from the add-header example I included, you can see the custom headers in the response headers but the main.XXXX.js/css files are returning 404 so the React app does not load. @leerob is this something you're aware of at all?

image

from examples.

frandiox avatar frandiox commented on April 28, 2024 3

For anyone interested, I've made an example on how to deploy to Vercel Edge without Next.js: https://github.com/frandiox/hydrogen-vercel-edge
Demo: https://hydrogen-vercel-edge-frandiox.vercel.app/

As mentioned before, the key was using middleware-manifest.json instead of functions-manifest.json.
cc @leerob Perhaps this could be updated in the docs?

from examples.

leerob avatar leerob commented on April 28, 2024 3

I see you mentioned Hydrogen - what other frameworks are y'all wanting to use Middleware with? P.S. I'm still following along here 😄

from examples.

ptrhck avatar ptrhck commented on April 28, 2024 3

I was also trying to deploy the example and now I am even getting the following:
MicrosoftTeams-image
So, I am really wondering what the current status is here?

from examples.

red2678 avatar red2678 commented on April 28, 2024 3

I feel like you guys putting examples of middleware implementations on your site, saying you work with all frameworks, only to not, is blatantly false advertising.

image

image

Nowhere on these pages does it say that middleware is only supported by Next.js apps.

https://vercel.com/features/edge-functions

https://vercel.com/docs/concepts/functions/edge-functions

Riiiiiiiight......

image

from examples.

frandiox avatar frandiox commented on April 28, 2024 2

Alright, looks like it works when using middleware-manifest.json instead of functions-manifest.json, which is what `next build creates.

Now my problem is... To use the new ReadableStream() constructor, enable the streams_enable_constructors feature flag.. How does one enable this in an Edge Function without Wrangler? 🤯

from examples.

edcrampin avatar edcrampin commented on April 28, 2024 2

Really would appreciate seeing some official docs detailing how to build middleware for a non-Next.js app. Managed to get a basic middleware working adapting @brycewray's snippet above to not use Next.js imports and saving this in my repo as ./_middleware.ts (copied below), but this prevents the actual app from rendering - I'd like to see an example of a middleware where I can run functionality (such as adding a custom header) but still serving my app, like the examples we have for Next.js apps.

export default function middleware(req: Request) {
  // You can add and append headers in multiple ways,
  // below we'll explore some common patterns

  // 1. Add a header to the `Headers` interface
  // https://developer.mozilla.org/en-US/docs/Web/API/Headers
  const headers = new Headers({ 'x-custom-1': 'value-1' })
  headers.set('x-custom-2', 'value-2')

  // 2. Add existing headers to a new `Response`
  const res = new Response(null, { headers })

  // 3. Add a header to an existing response
  res.headers.set('x-custom-3', 'value-3')

  // 4. Merge existing headers with new ones in a response
  return new Response(
    'Open the network tab in devtools to see the response headers',
    {
      headers: {
        ...Object.fromEntries(res.headers),
        'x-custom-4': 'value-4',
      },
    }
  )
}

from examples.

edcrampin avatar edcrampin commented on April 28, 2024 2

For anyone interested, I've made an example on how to deploy to Vercel Edge without Next.js: https://github.com/frandiox/hydrogen-vercel-edge Demo: https://hydrogen-vercel-edge-frandiox.vercel.app/

As mentioned before, the key was using middleware-manifest.json instead of functions-manifest.json. cc @leerob Perhaps this could be updated in the docs?

Thanks @frandiox, nice example using the File System API - that raises a good point that there are really two parts to this issue, I think what we need in this repo is an example of both:

  • Middleware using the File System API
  • Middleware with just a simple _middleware.js, with no need to play with the File System API

It seems like the second point is supported in Vercel, but perhaps not fully working/documented yet. As @brycewray mentions, I think this is what most people would be seeking so that the overhead of setting up Vercel middleware for a non-Nextjs project is as simple as possible.

from examples.

brycewray avatar brycewray commented on April 28, 2024 2

I see you mentioned Hydrogen - what other frameworks are y'all wanting to use Middleware with? P.S. I'm still following along here 😄

Can’t answer for others, @leerob, but I just want as plain-vanilla JS as possible, for converting an existing CF Worker to work on Vercel. Since Edge already uses CF Workers, seems it wouldn’t be that hard, although I readily confess that I’m only guessing about that.

from examples.

brycewray avatar brycewray commented on April 28, 2024 2

@edcrampin That all sounds great! It’ll be tremendously appreciated — but I humbly re-suggest :) that, in the meantime and in view of the team’s absolutely understandable time limitations, the starting effort be something utterly simple, quick, and dirty, even if it’s only a vanilla version of _middleware.js for a given example but with everything else in that example left as-is.

from examples.

remorses avatar remorses commented on April 28, 2024 1

Instead of NextRequest you have to use Request, which is a javascript built in

To migrate to a simple request, you can see how NextRequest is implemented here

from examples.

david-morris avatar david-morris commented on April 28, 2024 1

@leerob I'm using docusaurus, so I think that means static HTML.

from examples.

david-morris avatar david-morris commented on April 28, 2024 1

I'm encountering the following error on deployment with a _middleware.ts in the root of my docusaurus, and I'm wondering if anyone else has figured this one out:

TypeError: Unexpected MODIFIER at 1, expected END
    at f (/vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:468718)
    at parse (/vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:469358)
    at stringToRegexp (/vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:471777)
    at Object.pathToRegexp (/vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:472955)
    at sourceToRegex (/vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:175287)
    at /vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:173592
    at Array.map (<anonymous>)
    at convertRedirects (/vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:173560)
    at Object.build (/vercel/b5af1ed6dff7b1bc/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:31:195137)
    at async kot (/var/task/sandbox.js:197:12022)

from examples.

brycewray avatar brycewray commented on April 28, 2024

Am I correct in assuming this is unlikely to be addressed until 1Q 2022 due to the upcoming year-end holidays? Just curious. TIA for any such info.

from examples.

ptrhck avatar ptrhck commented on April 28, 2024

Any news on this topic?

from examples.

brycewray avatar brycewray commented on April 28, 2024

@remorses Although this doesn't eliminate the need for non-Next documentation from Vercel, it nonetheless is interesting and useful. Thanks!

from examples.

brycewray avatar brycewray commented on April 28, 2024

@remorses Just as a starter for those of us not all that into Next 😄 , how would you adjust the following _middleware.ts code from the fairly simple example, https://github.com/vercel/examples/tree/main/edge-functions/add-header ? In particular, the part of each of the examples that throws me is always the import statement in the top part, since that statement and the subsequent use of NextRequest both obviously depend on Next. To a Next-savvy person, a non-Next substitution probably seems super-easy, but a non-Next-savvy guy like me wouldn't have a clue where to go from there. Thanks in advance for any related thoughts you might have.

import type { NextRequest } from 'next/server'

export function middleware(req: NextRequest) {
  // You can add and append headers in multiple ways,
  // below we'll explore some common patterns

  // 1. Add a header to the `Headers` interface
  // https://developer.mozilla.org/en-US/docs/Web/API/Headers
  const headers = new Headers({ 'x-custom-1': 'value-1' })
  headers.set('x-custom-2', 'value-2')

  // 2. Add existing headers to a new `Response`
  const res = new Response(null, { headers })

  // 3. Add a header to an existing response
  res.headers.set('x-custom-3', 'value-3')

  // 4. Merge existing headers with new ones in a response
  return new Response(
    'Open the network tab in devtools to see the response headers',
    {
      headers: {
        ...Object.fromEntries(res.headers),
        'x-custom-4': 'value-4',
      },
    }
  )
}

from examples.

ptrhck avatar ptrhck commented on April 28, 2024

@brycewray Would be great if you can share your code once implemented!

from examples.

brycewray avatar brycewray commented on April 28, 2024

@ptrhck I haven't yet been able to make anything (i.e., that works). While @remorses provided valuable info, there are just too many other items that I'm not savvy enough to "translate" from Next to non-Next. Sorry!

from examples.

frandiox avatar frandiox commented on April 28, 2024

I'm always getting an error like:

TypeError: Cannot read property 'files' of undefined
--
21:41:41.309 | at /vercel/f053a0b194458027/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:26:255215

If I try to put _middleware.js at the root and run vercel, it shows that error. If I use the Filesytem API directly and create .output/functions-manifest.json and .output/server/pages/_middleware.js instead like you have in your source code and tests, it still throws.

The only way to bypass the error is moving .output/functions-manifest.json to .output/server/functions-manifest.json. This deploys but then nothing its returned from the function (404).

The code of the middleware is something like this:

"use strict";

const middleware = {
  default: function (request) {
    return new Response("hi from the edge!");
  },
};

_ENTRIES = typeof _ENTRIES === "undefined" ? {} : _ENTRIES;
_ENTRIES["middleware_pages/_middleware"] = {
  default: async function (ev) {
    const result = await middleware.default(ev.request, ev);
    return {
      promise: Promise.resolve(),
      waitUntil: Promise.resolve(),
      response:
        result ||
        new Response(null, {
          headers: {
            "x-middleware-next": 1,
          },
        }),
    };
  },
};

I've also added a ENABLE_FILE_SYSTEM_API=1 environment variable to the deployment but no luck.

Any quick pointer, @leerob ? Thanks.

from examples.

brycewray avatar brycewray commented on April 28, 2024

For anyone interested, I've made an example on how to deploy to Vercel Edge without Next.js: https://github.com/frandiox/hydrogen-vercel-edge

Nice!

(But requires Shopify, right? I think what most of us are seeking are examples that require no specific platform but, rather, are as vanilla as possible.)

from examples.

david-morris avatar david-morris commented on April 28, 2024

@edcrampin could you share the repo you have for converting the basic password auth? That would be a great example to work from. I'm having trouble understanding the various roots in the project, i.e., where the middleware should go.

from examples.

dapptain avatar dapptain commented on April 28, 2024

HELP! WE NEED DOCUMENTATION. ffs.....

from examples.

brycewray avatar brycewray commented on April 28, 2024

With the understanding that there may not be bandwidth at Vercel to reproduce all the examples in non-Next form, maybe @leerob et al. could take just one of the simpler examples — such as add-header or geolocation — and produce a non-Next form of it. It would be like a Rosetta Stone, showing that “Thing A gets done in Next projects like this (existing example) but in plain-vanilla JS it gets done like this (proposed example).” That could be really helpful and, perhaps, wouldn’t take too much time to convert from whichever Next project you select.

Just a thought. 🙂

from examples.

brycewray avatar brycewray commented on April 28, 2024

@edcrampin Thanks very much! Will stand by for @leerob to weigh in on your question before trying.

from examples.

david-morris avatar david-morris commented on April 28, 2024

Thanks for the example, @edcrampin ! I feel that I've been able to rule out issues with the _middleware file and package.json thanks to that repo.

However, there appears to be some remaining issue, and I don't understand where to start analyzing this issue. It appears that moving the _middleware file will switch this error between being a simple middleware and a filesystem API issue, but there's something that the edge function deployer just doesn't like about ...something? My repo? My framework? My account?

As an aside, it would be nice to be able to test these things without waiting for a remote deployment and committing.

I'd love to hear input on what could be related to this issue, and I'm interested in helping to make sure that the documentation can help people who are using whatever new technology, and want to add middleware.

TypeError: Unexpected MODIFIER at 1, expected END
    at parse (/vercel/b8b564fa9bd13b57/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:539986)
    at stringToRegexp (/vercel/b8b564fa9bd13b57/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:542405)
    at Object.pathToRegexp (/vercel/b8b564fa9bd13b57/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:543583)
    at sourceToRegex (/vercel/b8b564fa9bd13b57/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:224129)
    at /vercel/b8b564fa9bd13b57/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:222434
    at Array.map (<anonymous>)
    at convertRedirects (/vercel/b8b564fa9bd13b57/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:1:222402)
    at Object.build (/vercel/b8b564fa9bd13b57/.build-utils/.builder/node_modules/@vercelruntimes/file-system-api/dist/index.js:31:90032)
    at async qot (/var/task/sandbox.js:197:12762)

from examples.

charlax avatar charlax commented on April 28, 2024

I'm also using the latest docusaurus and getting the same error TypeError: Unexpected MODIFIER at 1, expected END.

I tried with a noop middleware and it still fails, most probably related to docusaurus:

export default function middleware(req: Request) {
  return new Response(null, {
    headers: {
      "x-middleware-next": "1",
    },
  });
}

from examples.

david-morris avatar david-morris commented on April 28, 2024

@edcrampin , could you share more about the settings you're using to deploy your example?

I assumed that it would use either the Other or Create React App preset, with the root directory edge-functions/create-react-app/basic-auth (for the basic auth example), and no other settings changed.

I've tried deploying it and it failed:

Cloning bitbucket.org/Nefino/vercel-examples (Branch: main, Commit: 540430d)
Cloning completed: 1.921s
Installing build runtime...
Build runtime installed: 4.358s
Looking up build cache...
Build Cache not found
Detected package.json
Installing dependencies...
Detected `package-lock.json` generated by npm 7...
npm WARN deprecated [email protected]: This SVGO version is no longer supported. Upgrade to v2.x.x.
added 1369 packages in 45s
169 packages are looking for funding
  run `npm fund` for details
Running `vercel build`
Vercel CLI 23.1.3-canary.71 build (beta) — https://vercel.com/feedback
Retrieved Project Settings:
  - Framework Preset: Create React App
  - Build Command: `npm run build` or `react-scripts build`
  - Output Directory: build
Loaded 2 CLI Plugins
Running Build Command: `npm run build`
> [email protected] build
> react-scripts build && cp _middleware.ts ./build/
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
  42.77 kB  build/static/js/main.3dba3da1.js
  541 B     build/static/css/main.073c9b0a.css
The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.
The build folder is ready to be deployed.
You may serve it with a static server:
  npm install -g serve
  serve -s build
Find out more about deployment here:
  https://cra.link/deployment
Copying files from "build" to ".output/static"
Copied 14 files from "build" to ".output/static" [38ms]
Running 2 CLI Plugins after Build Command:
  > vercel-plugin-middleware.build: Compiling middleware file: "/vercel/path0/edge-functions/create-react-app/basic-auth/_middleware.ts"
Build Completed in .output [12s]
Uploading build outputs...
An unexpected internal error occurred

from examples.

charlax avatar charlax commented on April 28, 2024

Btw, I got the following response from Vercel support:

Edge Functions (beta) are not ready outside of Next.js at the moment. We are working on making this possible!

So I guess we just have to be patient :)

from examples.

leerob avatar leerob commented on April 28, 2024

Forgot to swing back here, but with the stable release of Middleware, it can now be used with all frameworks 😄

Will be adding more examples, as well! This is just the start.

https://vercel.com/docs/concepts/functions/edge-middleware/quickstart

from examples.

brycewray avatar brycewray commented on April 28, 2024

I did finally get it working on a Hugo repo:
https://github.com/brycewray/hugo-site/blob/main/middleware.js
https://github.com/brycewray/hugo-site/blob/main/.deprecated/middleware.js

While most of its headers-handling could’ve been done in vercel.json, the Content Security Policy needed dynamically generated nonces scattered throughout the site at appropriate places (scripts, certain links, etc.). This handles that just as its Cloudflare Worker predecessor did in Cloudflare Pages. 👍

@leerob, my compliments to your team for the content of both the Edge Functions and Middleware sections in the documentation — the info is much more comprehensive, and considerably easier to follow, than the last time I checked.

from examples.

dmarkbreiter avatar dmarkbreiter commented on April 28, 2024

@david-morris @charlax did you ever get your docusaurus sites behind authentication?

from examples.

david-morris avatar david-morris commented on April 28, 2024

@dmarkbreiter yes, I think we just crammed Docusaurus behind a Next.js shim before this was fixed though.

from examples.

Youhan avatar Youhan commented on April 28, 2024

Is there a Nuxt example out there?

from examples.

levino avatar levino commented on April 28, 2024

Here is my middleware for a docusaurus static site:

const auth = process.env.AUTH

export default function middleware(request) {
  const basicAuth = request.headers.get('Authorization')
  if (!basicAuth) {
    return new Response('Access denied', {
      status: 401,
      headers: { 'WWW-Authenticate': 'Basic' },
    })
  }
  const authValue = basicAuth.split(' ')[1]
  if (authValue !== auth) {
    return new Response('Access denied', {
      status: 401,
      headers: { 'WWW-Authenticate': 'Basic' },
    })
  }
}

Use

echo -n "username:password" | base64

to generate the AUTH string.

from examples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.