vercel / next.js

The React Framework
https://nextjs.org
MIT License
122.93k stars 26.28k forks source link

Be able to create service-worker in typescript #33863

Open kristijorgji opened 2 years ago

kristijorgji commented 2 years ago

Describe the feature you'd like to request

There is no example on how to create a serivce-worker.ts, that gets compiled at specified output (example public/service-worker.js)

We want to have this option and service worker for the app

Describe the solution you'd like

One official example, probably with some typescript config on how to achieve this. Or even better a way for nextjs to extend its webpack tsconfig to also other files like service-worker, server etc

Describe alternatives you've considered

I am trying to create new tsconfig.sw.json right now but without success. I need to build a single bundle .js service-worker butr when I import other ts functions into it cannot create single bundle get tsc error

eashish93 commented 2 years ago

You can setup typescript for service-worker using solution described in example custom-server-typescript. Just copy the config and include your service worker typescript file path in custom tsconfig.

SukkaW commented 2 years ago

You can setup typescript for service-worker using solution described in example custom-server-typescript. Just copy the config and include your service worker typescript file path in custom tsconfig.

How do we leverage Next.js built-in features (and Vercel platform) with the example then? Do you mean Service Worker is incompatible with the Vercel platform?

gallyamb commented 2 years ago

Is there any update? We'd like to create typescript service worker too, but couldn't find how to do that

HaNdTriX commented 2 years ago

There is an example called examples/progressive-web-app that uses next-pwa.

For more detailed examples check out next-pwa/examples.

SukkaW commented 2 years ago

There is an example called examples/progressive-web-app that uses next-pwa.

For more detailed examples check out next-pwa/examples.

Does next-pwa allow me to write my own Service Worker logic, beyond caching and offline? E.g. How to implement Service Worker Notification using next-pwa and TypeScript?

HaNdTriX commented 2 years ago

Check out the following example: https://github.com/shadowwalker/next-pwa/tree/master/examples/custom-ts-worker

zdila commented 2 years ago

I am using this hacky solution:

In /next.config.js:

const { InjectManifest } = require("workbox-webpack-plugin");

module.exports = {
  // ... other configs
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    if (!isServer) {
      config.plugins.push(
        new InjectManifest({
          swSrc: "./sw.ts",
          swDest: "../public/sw.js",
          include: ["__nothing__"],
        })
      );
    }

    return config;
  }
};

and in /sw.ts:

/// <reference lib="webworker" />

declare const self: ServiceWorkerGlobalScope;

const resources = self.__WB_MANIFEST; // this is just to satisfy workbox

// ... your SW code

Generated sw.js is placed to /public/sw.js so you should add it to your .gitignore.

Sowed commented 1 year ago

Can also confirm, "next-pwa": "5.5.4" works just fine.

Yrobot commented 1 year ago

I am finding the esaiest way to add the service worker to Next.js project too, the answers i found are all about next-pwa or workbox.

In my opinion, the problem is same as how to add files which needs compile to output public folder.

But when i try to add entry and ouput to webpack config in next.config.js, things not go as i expected. For example, the output file path is under build/_next/static/chunks, and the output file name is within a hash code, etc.

So i opened a discussion on this, hoping for a god.

nitinTJ commented 1 year ago

Does next-pwa works fine with the next 13 app directory. Because I am facing an issue where the service worker is not getting registered.

matallui commented 8 months ago

I'm looking for an answer to this issue as well. Ideally one that doesn't require next-pwa as I just need a very simple service worker file. Any other ideas will be much appreciated!

Yovach commented 8 months ago

Hi, I've created a webpack plugin for this use case (writing Service worker in TypeScript) because I needed too and plugins like next-pwa add too much stuff (like workbox).

But you can also use this plugin for files that you need to compile from TypeScript to .js in the public folder.

To use it:

npm install --save-dev next-public

Then, create a sw.ts file at [root]/app/+public/sw.ts:


/// <reference lib="WebWorker" />
export type {};
declare let self: ServiceWorkerGlobalScope;

self.addEventListener("install", async () => {
  console.log("Service worker installed (cjs)");
});

self.addEventListener("fetch", (evt: FetchEvent) => {
  // Do your magic here. E.g. if you want to cache third party resources:
});

self.addEventListener("error", (err) => {
  console.error("Service worker error", err);
});
// next.config.mjs
import path from "node:path";
import { NextPublicTsPlugin } from "next-public";

const __dirname = new URL(".", import.meta.url).pathname;

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  webpack(config, context) {
    config.plugins.push(
      new NextPublicTsPlugin({
        inputDir: path.join(__dirname, "app", "+public"),
        outputDir: path.join(__dirname, "public"),
      })
    );
    return config;
  },
};

export default nextConfig;

Obviously, you need to adapt the above code to your situation.

mrdomino commented 8 months ago

@Yovach Wow, fortuitous timing, doing this the day before I find myself wanting to write a service worker for Next in TypeScript... thanks, about to try it out.

Yovach commented 8 months ago

Wow, fortuitous timing, doing this the day before I find myself wanting to write a service worker for Next in TypeScript... thanks, about to try it out.

I've wanted to do this for so long and I'm glad it can help other people.

mrdomino commented 8 months ago

Hmm, somehow my sw.js file (generated from something like the ts you showed) is ending up with an export statement in it at the end that is tripping up my browser. Investigating... any ideas?

EDIT: Ah, type: 'module' in serviceWorker.register is probably it.

Yovach commented 8 months ago

Hmm, somehow my sw.js file (generated from something like the ts you showed) is ending up with an export statement in it at the end that is tripping up my browser. Investigating... any ideas?

EDIT: Ah, type: 'module' in serviceWorker.register is probably it.

I'll fix the issue because sometimes, you don't need that and it includes unnecessary code

mrdomino commented 8 months ago

Hmm, next thing is that process.env.NEXT_PUBLIC_* is not getting substituted.

mrdomino commented 8 months ago

And now I'm getting very strange TypeScript behavior — the <reference lib="WebWorker" /> in app/+public/sw.ts seems to be getting applied to the rest of my components, so TypeScript is saying e.g. "Property 'serviceWorker' does not exist on type 'WorkerNavigator'" in App.tsx. If I take the line out of sw.ts, the errors go away elsewhere.

Yovach commented 8 months ago

And now I'm getting very strange TypeScript behavior — the <reference lib="WebWorker" /> in app/+public/sw.ts seems to be getting applied to the rest of my components, so TypeScript is saying e.g. "Property 'serviceWorker' does not exist on type 'WorkerNavigator'" in App.tsx. If I take the line out of sw.ts, the errors go away elsewhere.

Where did you add the sw.ts file ? (we should go on issues page related to the lib and not this issue)

genzzo commented 8 months ago

Here are two solutions that might help

1 - sw.js file with typesciprt capabilities

Create a sw.js file in your public directory and add the following to the top:

/// <reference lib="webworker" /> // 
// @ts-check
/** @type {ServiceWorkerGlobalScope} */
// @ts-ignore
const sw = self;

Explanation:

The drawbacks of this is that it's not quite a typescript file and so any explicit typings will need to be in the form of a jsdoc comment, so if you really want to have a typescript file here's solution 2:

2 - Manually handle a sw.ts file

Create a sw.ts file and add the following to the top:

/// <reference lib="webworker" />
const sw = self as unknown as ServiceWorkerGlobalScope; // we still need to override the "self" variable

Now run this command

npx tsc path/to/your/sw.ts --lib "WebWorker" --outDir public --watch

This will watch whenever your service worker changes and compile it again into the public directory, next will handle the rest You can also use something like concurrently to run "next dev" with this command to watch everything at once

rjwignar commented 1 month ago

I'm trying to make a custom service-worker to implement the Share Target API but I'm confused. The app I'm working on is written in TypeScript, Should I write my service worker in sw.js (JavaScript) or sw.ts (TypeScript)?