saltyshiomix / nextron

⚡ Next.js + Electron ⚡
https://npm.im/nextron
MIT License
3.87k stars 223 forks source link

Support for Nextjs 13.3 Static export #296

Closed Brandontam29 closed 2 months ago

Brandontam29 commented 1 year ago

Can we upgrade to Nextjs13 without breaking the application?

Update May 2023:

Next export is deprecated in favor of Static export read more here: https://nextjs.org/docs/app/building-your-application/deploying/static-exports#next-export-deprecated

vxxvvxxv commented 1 year ago

You can use official cli tool from the next team.

Upgrade images:

npx @next/codemod next-image-to-legacy-image ./renderer/pages

Upgrade links:

npx @next/codemod new-link ./renderer/pages
dohomi commented 1 year ago

Is the NextJS 13 pages folder structure working out of the box?

vxxvvxxv commented 1 year ago

Is the NextJS 13 pages folder structure working out of the box?

Unfortunately, no

dbredvick commented 1 year ago

This will be supported in the next release of Next on 13.3 https://beta.nextjs.org/docs/configuring/static-export, so we should be able to add it.

ealeksandrov7 commented 1 year ago

Hey, I'm totally new to nextron/next, but am looking to start a project on it. Do you have any hints on how to make the new app folder structure work? I guess just adding the static-export configuration won't be enough? 😅

andirsun commented 1 year ago

Next 13.4 was launched with stable release of app folder, is time to go ahead with the support. https://nextjs.org/blog/next-13-4

castroCrea commented 1 year ago

Hey, I tried to update electron to the last version 25.1.0 and then I wasn't able to use client component (all my useEffect wasn't triggered).

I also try to update Next.JS -> same problem But If I downgrade electron to 21 and up next is works

It seems related to this issue with static pages

// packages.json
 "devDependencies": {
    "@types/node": "^20.3.0",
    "@types/react": "^18.2.11",
    "electron": "^21.3.3",
    "electron-builder": "^23.6.0",
    "next": "^12.3.4",
    "nextron": "^8.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "typescript": "^5.1.3"
  }
jonstelly commented 1 year ago

I've started some next13 support work at /jonstelly/nextron/tree/feature/next13.

For next 13 with App Router, I think the recommended way to generate the equivalent of the deprecated next export is to just set output: export in the next.config.js, at which point next build will spit out a static bundle/build.

I wonder about doing the following:

  1. Modify next.config.js and add output: export (this is now like next build && next export)
  2. Modify nextron-build to not call "next export", instead copy the exported-output from step 1 to appdir
  3. If the goal of nextron is to support next 13 but retain support for previous versions of next, either:
    • auto-detect if we're on next 13 or not and still call next export if on <=12?
    • add a --next13 flag to nextron build <- I started with this for simplicity
    • add to the nextron config

It also feels like with nextjs app router, appdir should probably be something other than app? I'm not an electron expert but I think we could change the appdir in nextron and the files filter in electron-builder.yaml to include a different directory than 'app'?

Any feedback on what's there so far? I'm going to create a new example on that branch to scaffold an empty next13 app.

I've got the above branch building and bundling to electron, launching that bundle gives an error:

A JavaScript error occurred in the main process
Uncaught Exception:
Error: ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: 908
    at Object.set [as exports] (/.../app/dist/linux-unpacked/resources/app.asar/app/background.js:2:121398)

so I'm tracking that down now.

jonstelly commented 1 year ago

I've got this working:

nextron fork - https://github.com/jonstelly/nextron/tree/feature/next13 Example Repo/App - https://github.com/jonstelly/nextron13

A couple remaining problems:

Aside: In my project I've added capacitor so I can also create android and ios builds. It might be another good nextron example/template to add. If I get everything working reasonably I'll generate an example for that too.

Nice work on nextron, it makes nice work of bringing next and electron together.

castroCrea commented 1 year ago

Hey,

I just tried your nextron13 branch, with next@13.4.7 and electron@21 and everything seems to run. I also try to update Electron to the last version, `25.2.0, ' which runs too.

  1. Note that after yarn install on the first yarn dev I got this error

    image
     At second `yarn dev` works well
  2. For the useState and useEffect are not working when adding 'use client' It should be working according to the next doc

    image

https://github.com/saltyshiomix/nextron/assets/20707343/205616a4-3c3e-4ab7-982a-e67640fc8215

I added a PR with my tried that doesn't work https://github.com/jonstelly/nextron13/pull/1/files

castroCrea commented 1 year ago

I also tried to build on mac OS without signing and got this errors

image

I check it is there

image

I also tried with you original cmd but --next13 doesn't seems to be an option

image image
SimonFrank14 commented 1 year ago

Hi everyone,

in my repo I was also able to run it with a few adoptions. I will create a small summary for everyone searching for quick & dirty solution until the official Nextron Update is there:

My setup: Next 13.4.9 & Electron 21.3.3 & Nextron 8.5.0

1. Adoptions to next.config.js

const config = {
    webpack: (config, { isServer }) => {
        if (!isServer) {
            config.target = 'electron-renderer'
        }
        return config
    },
}

if (process.env.NODE_ENV === 'production') {
    config.output = 'export'
    config.distDir = '../app'
    config.images = {
        loader: 'custom',
        loaderFile: './image-loader.js',
    }
}

module.exports = config

2. New file image-loader.js

'use client';

// External loader because Electron does not support the default loader in production mode.
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default function myImageLoader({ src, width, quality }) {
    return `app://./${src}?w=${width}&q=${quality || 75}`;
}

I needed an external image loader because my images did not loaded with the default engine from NextJS with the static exports. So I built my own.

3. Changes in NPM Package of nextron

Now it gets dirty:

I changed a small line in the delivered NPM package of nextron so that the following error disappeared during built process error "next export -o <dir>" cannot be used when "output: export" is configured in next.config.js. Instead add "distDir" in next.config.js https://nextjs.org/docs/advanced-features/static-html-export

We have to remove the command next export from nextron's built process.

New /bin/nextron-build.js

#!/usr/bin/env node
"use strict";var e=require("fs-extra"),n=require("path"),o=require("arg"),i=require("chalk"),r=require("execa"),a=require("fs");require("webpack-merge"),require("webpack");const l=process.cwd();require(n.join(l,"package.json")).dependencies;const s=process.cwd();a.existsSync(n.join(s,"tsconfig.json"));function c(e){console.log(i`{cyan [nextron]} ${e}`)}const t=o({"--help":Boolean,"--version":Boolean,"--all":Boolean,"--win":Boolean,"--mac":Boolean,"--linux":Boolean,"--x64":Boolean,"--ia32":Boolean,"--armv7l":Boolean,"--arm64":Boolean,"--universal":Boolean,"--config":String,"--publish":String,"--no-pack":Boolean,"-h":"--help","-v":"--version","-w":"--win","-m":"--mac","-l":"--linux","-c":"--config","-p":"--publish"});t["--help"]&&(console.log(i`
    {bold.cyan nextron build} - Build and export the application for production deployment

    {bold USAGE}

      {bold $} {cyan nextron build} --help
      {bold $} {cyan nextron build} [options]

    {bold OPTIONS}

      --help,    -h  show this help message
      --version, -v  display the current version of nextron
      --all          build for Windows, macOS and Linux
      --win,     -w  build for Windows, accepts target list (see https://goo.gl/jYsTEJ)
      --mac,     -m  build for macOS, accepts target list (see https://goo.gl/5uHuzj)
      --linux,   -l  build for Linux, accepts target list (see https://goo.gl/4vwQad) 
      --x64          build for x64
      --ia32         build for ia32
      --armv7l       build for armv7l
      --arm64        build for arm64
      --universal    build for mac universal binary
      --no-pack      skip electron-builder pack command
      --publish, -p  publish artifacts (see https://goo.gl/tSFycD)
                     [choices: "onTag", "onTagOrDraft", "always", "never", undefined]

  `),process.exit(0));const u=process.cwd(),p={cwd:u,stdio:"inherit"};function d(){let e=[];return t["--x64"]&&e.push("--x64"),t["--ia32"]&&e.push("--ia32"),t["--armv7l"]&&e.push("--armv7l"),t["--arm64"]&&e.push("--arm64"),t["--universal"]&&e.push("--universal"),e}!async function(){process.env.ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES="true";const o=n.join(u,"app"),l=n.join(u,"dist"),h=(()=>{const e=n.join(s,"nextron.config.js");return a.existsSync(e)?require(e):{}})().rendererSrcDir||"renderer";try{c("Clearing previous builds"),e.removeSync(o),e.removeSync(l),c("Building renderer process"),await r("next",["build",n.join(u,h)],p),await r("node",[n.join(__dirname,"webpack.config.js")],p),t["--no-pack"]?c("Skip Packaging..."):(c("Packaging - please wait a moment"),await r("electron-builder",function(){let e=[];t["--config"]&&(e.push("--config"),e.push(t["--config"]||"electron-builder.yml"));t["--publish"]&&(e.push("--publish"),e.push(t["--publish"]));t["--all"]?(e.push("-wml"),e.push(...d())):(t["--win"]&&e.push("--win"),t["--mac"]&&e.push("--mac"),t["--linux"]&&e.push("--linux"),e.push(...d()));return e}(),p)),c("See `dist` directory")}catch(e){console.log(i`

{bold.red Cannot build electron packages:}
{bold.yellow ${e}}
`),process.exit(1)}}();

Alternatively you can use one of the forks from above to build your process. Only there!!! the --next-13 command line switch will work.

I hope this helpful :)

saltyshiomix commented 3 months ago

@Brandontam29 @vxxvvxxv @dohomi @dbredvick @ealeksandrov7 @andirsun @castroCrea @jonstelly @SimonFrank14

Sorry for late reply and inconvenience.

I just released nextron v9.0.0, which supports next.js v13 and v14. If you have time, please try it :)


NOTE:

Please update renderer/next.config.js as belows:

module.exports = {
  output: 'export',
  // we want to change distDir to "app" so as nextron can build the app in production mode!
  distDir: process.env.NODE_ENV === 'production' ? '../app' : '.next',
  trailingSlash: true,
  images: {
    unoptimized: true,
  },
}
saltyshiomix commented 2 months ago

I'll close this issue, but feel free to reopen it if any updates :)