saltyshiomix / nextron

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

Do parameterized routes work in nextron? #13

Closed yoDon closed 5 years ago

yoDon commented 6 years ago

Is there any way to do parameterized routing for the pages in nextron?

Zeit has next.js use a custom server for parameterized routing, either their http module or express.js or similar (like in https://github.com/zeit/next.js/tree/canary/examples/parameterized-routing) but I can't tell if there is a way to pull it off with the awesome surgery you've done around next to make nextron.

yoDon commented 6 years ago

I'm wondering if maybe there is a way to inject parameterized routing into a smarter form of your resolve component. I did a quick test to make resolve append ?foo=bar on the end of urls and the system seemed to handle the query strings the way one would hope, so perhaps even some fairly manual regexp testing to manipulate the routes and turn parameters into query strings would work (my interest is in finding ways to share as much code between an electron-hosted app and a matching conventionally hosted site)

yoDon commented 6 years ago

As a quick update, I'd still much rather be able to host zeit's http or electron.js in nextron for consistent routing experiences but in the meantime I was able to hack nextron's resolve() function to do the parameterized routing I was looking for for this test

saltyshiomix commented 6 years ago

Ah, you're right! I added an example of parameterized-routing: (but currently supports only development mode)

# install latest nextron
$ npm install --global nextron@latest

# check a parameterized-routing example
$ nextron init my-app --template parameterized-routing

I'll fix resolve as soon as possible 👍

yoDon commented 6 years ago

Wow - This would be fantastic if it could work in production mode!

saltyshiomix commented 6 years ago

Finally fix the parameterized-routing example with ipc communication 👍

# install latest nextron
$ npm install --global nextron@latest

# the example of parameterized-routing
$ nextron init my-app --template parameterized-routing

It will work both development and production mode ❤️

yoDon commented 6 years ago

How does the parameterized routing work with the list of pages in exportPathMap in next.config.js?

I'm not sure the role of exportPathMap, but I'm worried if I wanted to have a parameterized route that takes the user's first name as a parameter I might need to list all possible first names in exportPathMap, which clearly wouldn't work. Am I misunderstanding the role of exportPathMap?

saltyshiomix commented 6 years ago

The exportPathMap in the next.config.js is used when next export so that next can export static files.

Electron in production mode (that is, binary one) can handle only static files. So we need export static files before production builds.

In conlusion, it is possible to use parameterized routing as long as we define exportPathMap in the next.config.js, and it is not possible when we don't define export paths of static files because Electron in production mode can't handle local server(which is security risk).

saltyshiomix commented 6 years ago

So, in your case, if you want to have a parameterized route that takes the username as a parameter, we can't get desired result in production mode because we can't define exportPathMap in the next.config.js.

Electron in development mode, it can handle local server so we can use all of web stack like parameterized routing. But Electron in production mode, it can handle only static files so we need to think about "Is it possible when exported static files?".

saltyshiomix commented 6 years ago

BUT, if you want such a parameterized routing, the answer is single page application.

Next.js is a SSR library, and it has a rule of pages/*.js, so we don't use all features of Next.js with Electron.

An SPA project is consists of static files from the beggining to the end, so we don't need to think about production mode or not. Electron with SPA is perfect solution 👍

yoDon commented 6 years ago

I completely get the value of an SPA with Electron, but my sense is as cool as your solution is it won't actually help most of the people who need parameterized routing (need it, for example, because they are trying to embed a non-spa site that was already designed for use in non-electron contexts). Having to exhaustively list all the possible parameterized pages in a file pretty much invalidates the advantages of parameterized routing in a great many database-driven and other scenarios.

By way of conversation and In case it help others who find this thread while searching for ideas, I was able to implement more conventionally defined parameterized routing by modifying the Nextron resolve function to include a couple simple regexps for converting the parameterized route values into query string parameters. This lets the same site be hosted either conventionally or in Nextron, with only that one function needing to be changed when switching from an electron host to a conventional web host.

I can try to generalize this into an example project.

yoDon commented 6 years ago

Adding a quick note as part of this, I'm not sure if it's documented other than in this PR but exportPathMap does have support for parameterized routes (which isn't a solution to the routing question on its own but is probably part of the solution)

saltyshiomix commented 5 years ago

Hi @yoDon , long time no see!

I finally found the solution of this issue.

Using json-url, we can define only one exportPathMap without caring about any parameters:

// next.config.js

module.exports = {
  exportPathMap: async () => {
    return {
      '/home': { page: '/home' },
      '/blog': { page: '/blog' },
    };
  },
};
// pages/home.jsx

const codec = require('json-url')('lzw');

const Home = ({ blogs, blogProps }) => {
  return (
    <React.Fragment>
      <Head>
        <title>Home - Nextron (parameterized-routing)</title>
      </Head>
      <ul>
        {blogs.map((blog, i) => {
          return (
            <li key={i}>
              <Link href={`/blog?props=${blogProps[blog.id]}`}>
                <a>{blog.title}</a>
              </Link>
            </li>
          );
        })}
      </ul>
    </React.Fragment>
  );
};

Home.getInitialProps = async () => {
  // fetch blog data from the external api
  const blogs = [
    { id: 1, title: 'My first blog post' },
    { id: 2, title: 'My second blog post' },
    { id: 3, title: 'My last blog post' },
  ];
  const blogProps = {};
  for (let i = 0; i < blogs.length; i++) {
    const blog = blogs[i];
    blogProps[blog.id] = await codec.compress(blog); // serialize blog data
  }
  return {
    blogs,
    blogProps,
  };
};

export default Home;
// pages/blog.jsx

const codec = require('json-url')('lzw');

const Blog = ({ id, title }) => {
  return (
    <React.Fragment>
      <Head>
        <title>{title} - Nextron (parameterized-routing)</title>
      </Head>
      <div>
        <h1>{title} (id: {id})</h1>
      </div>
    </React.Fragment>
  );
};

Blog.getInitialProps = async ({ query }) => {
  return codec.decompress(query.props); // deserialize blog data!
};

export default Blog;

For the full implementation, please check out updated examples/parameterized-routing:

# install latest nextron ( >= v5.12.3 )
$ npm i -g nextron@latest

# test it :)
$ nextron init test-app --example parameterized-routing
$ cd test-app
$ yarn && yarn dev

Cheers,

saltyshiomix commented 5 years ago

It works even if production build :)

Because it's just a client URL!

/blog?props= woTCo29uZQHCo3R3bwLCpXRocmVlwpMBAgPCpGZvdXLCrsSOZCBwacSDYXBwbGVz