vercel / next.js

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

Add pagesDir config option #4315

Closed vladnicula closed 5 years ago

vladnicula commented 6 years ago

Relating to https://github.com/zeit/next.js/issues/875, willing to try a PR if offered guidance.

We're building a ecommerce store from scratch with next and are close to finishing the initial architecture. The only thing bugging us is the number of folders we ended up with. The src folder would be a major improvement in our structure and the way we thought it could be done is by adding a property called pagesDir in the next.config.js configuration.

With this new options set to something like:

{
   "pagesDir": './src/pages'
}

we could keep all the source code in src, including the pages.

Expected Behavior

Added description at the top of the page

Current Behavior

Pages cannot be placed within a sub folder.

Steps to Reproduce (for bugs)

Context

Your Environment

Tech Version
next 6.0.0
node 6.x
OS N/A
browser N/A
etc
brad-decker commented 6 years ago

@vladnicula if your goal is to have everything that is webpacked/babeled and part of next be in the /src folder you can just move your pages directory into src and change your path for next to /src. We actually went one step further and moved our next configuration into a specific folder and our "userland" source code into src. all that exists in our "next" folder is /pages and next.config.js.

we modified next.config.js to tell it to work its magic on the src folder.

module.exports = {
  webpack: (config, { dev, defaultLoaders }) => {
    config.module.rules.push({
      test: /\.+(js)$/,
      loader: defaultLoaders.babel,
      include: path.resolve(__dirname, '../src'),
    });
    return config;
  }
};
joao-alberto commented 6 years ago

@vladnicula take a look https://github.com/zeit/next.js/issues/819#issuecomment-273527874

ghost commented 6 years ago

@brad-decker we did something like this with next

const app = next({
   dev,
   dir: './src'
});

but the issue here that .next folder which is built by next will stay in same folder with src We are looking for a solution like put all code in src folder but .next folder is in the root

@joao-alberto your solution can be apply with next but not with the custom server

vladnicula commented 6 years ago

@joao-alberto thanks for the share. I actually did try to follow the steps from the ticket. The issue with that is that with a custom server we could not get the config to properly load and find the pages folder in development mode.

So, the suggestion from https://github.com/zeit/next.js/issues/819#issuecomment-273527874 does not work in dev mode when using a custom server.

We could come up with an isolate example to showcase the limitation if it would help this discussion.

vladnicula commented 6 years ago

@brad-decker thanks for sharing that configuration nugget. I gave it a try and it seems that the dev mode was not able to find any of the pages under pages/src. I tried telling our server to render either:

return app.render(req, res, '/')

or

return app.render(req, res, '/src')

But it seems it did not want to.

Attempting to bundle in production via yarn build also failed, so there might be more to it than you are sharing with us :).

I liked the idea anyway.

brad-decker commented 6 years ago

Our app structure:

/
|__next/
|   |__pages/
|        |__index.js //<- just imports stuff from src and exports it as default for next to pick it up as a page
|   |__next.config.js
|__src/
    |__components/
    |__pages/
        |__home.js // <- our actual code

initialize app using the next folder const app = next({ dev, dir: `${__dirname}/next` });

add the blip from my previous comment to tell webpack to compile and bundle your /src folder

brad-decker commented 6 years ago

also our .next folder gets added to the /next folder so our build stuff goes in next/.next which is so obviously next level

DullReferenceException commented 6 years ago

Any thoughts on this somewhat alternative approach?

https://github.com/zeit/next.js/pull/4406

The main purpose of that PR is to add support for multiple pages directories, but it could also be used to embed files under a different root. Sample next.config.js file:

module.exports = {
  rootPaths: ['./src']
}
timneutkens commented 5 years ago

We are not planning to allow changing the pages directory.

However a solution for #4406 should be explored. Let's track that in https://github.com/zeit/next.js/issues/3027

kachkaev commented 5 years ago

Could this issue be looked at again please? 🙏

I used to keep all my Next.js app sources inside src in order to ease search and replace within the project. It was a bit painful to set up a custom server so that all directories were configured adequately, but it still felt worth it. In version 9, with tsconfig.json and next-env.d.ts created automatically in the Next.js dir instead of the repo root, things are getting even messier and I'm leaning towards coming back to keeping Next.js root dir the same as the repos's root dir 🤔

The fact that I'll have to have pages next to src rather inside src, makes me quite sad. Now, instead of limiting my search and replace scope in VSCode to [project]/src, I'll need to search the whole project, but then remember to exclude a bunch of directories like .next, build, coverage and so on in order to get adequate results. The blacklist varies from project to project, which builds up into a prettly long and ugly comma-separated string.

Unlike CRA, which is zero-config in principle, Next.js has quite a few options, including a bunch of experimental ones. It feels like swapping the hard-coded pages dir with something more dynamic would not be too harmful overall. What is a blocker?

Relevant concerns, which were recently raised: https://github.com/zeit/next.js/pull/7798, https://github.com/zeit/next.js/issues/7782


Partially the reason why I'm asking is because our company looks into moving a few apps from bespoke webpack-dev-server configs into Next.js. Not being able to configure pagesDir will essentially result in two src folders in each project, which will sometimes require reconfiguring linting tools as well as explaining the new project structure to the devs.

gc commented 5 years ago

Pretty surprised this is not possible, and its a put-off/downside as I'm investigating migrating my CRA app to next.js.

Timer commented 5 years ago

@gc CRA doesn't allow these types of settings to be adjusted, so the experience should be familiar. 😄

e.g. you cannot customize the src/ folder

kachkaev commented 5 years ago

[in CRA] you cannot customize src/ folder

Which is great, because it means that the entry point src/index.js can be in the same subfolder as all the rest of the app code. In Next.js though the situation is very different: you cannot have a single project subfolder where all source is stored; the theoretical minimum is two (e.g. pages and src). This makes project-wide search pretty complicated. Seem details in my comment above 🙂

Timer commented 5 years ago

@kachkaev I'm well aware 😄. The above response was specifically directed at @gc, not this issue as a whole.

There's many benefits to have an application rooted within src, which is different than customizing the pages directory. This effect can be seen in Create React App by not allowing you to import files outside of src.

We'll be drawing up a proposal soon that allows users to opt-into this rooting behavior.

gc commented 5 years ago

@Timer I was referring to not being able to have all the source in src/, this is the way I structure all my projects, for obvious reasons it's neater and more manageable. I'd rather not have to look through my many dotfiles, lock/log files, etc to find source code. I'm aware CRA (and next) are restricting things as you say, but if I'm understanding correctly, next.js is hardcoded to check only the root for /pages, so I cannot include it in my src.

If I've misunderstood anything I apologize, I've only just started using next in the last few hours. @kachkaev has pretty well described my feelings too.

I'm glad to hear about the proposal, I'm guessing it will let us specify a directory in our next.config? Like pagesDir: "./src/pages".

Timer commented 5 years ago

The proposal would look more like applicationRoot: './src'.

treyhuffine commented 5 years ago

Very excited to see this being considered. Trying to build any kind of complex application with now and next using serverless functions is painful when being forced to have pages in the root.

timneutkens commented 5 years ago

Just to be clear I'm strongly against any config value for this, we've seen tons of misusage of config values like these (looking at distDir for example). The thing I'm willing to consider is adding src/pages support, where you choose either root level pages directory or src/pages, as apparently this covers the majority use-case of why people are asking for this feature.

janhesters commented 5 years ago

@timneutkens

The thing I'm willing to consider is adding src/pages support, where you choose either root level pages directory or src/pages, as apparently this covers the majority use-case of why people are asking for this feature.

This would already be a huge improvement 🙏🏻 Please make src/pages happen 😊

kachkaev commented 5 years ago

If there is no intent to make pagesDir fully customizable, how about checking both pages and src/pages on startup and picking the existing folder as pagesDir? Next can crash or warn with a meaningful message if both folders are present to avoid misuse. Problem solved, no options added.

timneutkens commented 5 years ago

@kachkaev that's exactly what I outlined 😄

chengsokdara commented 5 years ago

Please make this happens

timneutkens commented 5 years ago

Posted https://github.com/zeit/next.js/issues/8451

armenr commented 5 years ago

YES YES HELL YES FINALLY YES!

Thanks folks :)

Tenshock commented 5 years ago

I dont understand your choice @timneutkens …

You are strongly against any config value but you want to let the user have the choice between pages or src/pages. A well documented option would be perfect to avoid misusage of config value as you described. I like to think users are smart enough to read the doc and understand how the framework works. Please let the users freely pick whatever folder they want to store his pages.

The majority of the people are happy with only the possibility to put the pages folder inside the src but what about different folder structures? Per example a folder structure that tends to implement common software architectures like clean architecture or another?

Your choice to support either /pages or src/pages is almost an answer, a compromise. You want to fulfil users needs but it seems like you have some fears about letting the user be free to organise his folders.

I think the framework should be agnostic of each user project and folder structures. I think the choice to freeze the project structure breaks a common software engineering principle.

The framework realise assumptions about the project structure. It breaks the Single Responsibility Principle in object oriented programming. Or, if you prefer, one of Linux principles that suggests that a software does one thing well, but only one thing. The aim of NextJS is to server-side render React. Not to suggests how the user has to organise his project.

I would be happy to deeply understand why you don't want to leave the choice to the user. I read many threads about this discussion but I still don't understand. The framework will only be more powerful as it will be more adaptable.

timneutkens commented 5 years ago

The framework realise assumptions about the project structure. It breaks the Single Responsibility Principle in object oriented programming. Or, if you prefer, one of Linux principles that suggests that a software does one thing well, but only one thing. The aim of NextJS is to server-side render React. Not to suggests how the user has to organise his project.

The premise is convention over configuration.

Next.js is not a library, it does more than a single thing by design. It's a collection of:

The Next.js CLI is a compiler/bundler, but not a conventional one, as it compiles much more than the general compiler. A basic compiler takes input -> transforms -> output where input is one piece of code and output is one piece of code. Next.js on the other hand handles more: input multiple files -> transforms -> full renderable app with server and client bundles.

Hence why Next.js is a framework and not a library that does a single thing.

The aim of NextJS is to server-side render React.

This is a wrong assumption. As said earlier the main goal for Next.js is to have the right defaults for building websites / web applications and giving flexibility between tradeoffs (eg static, ssr, etc) while putting you / your team into the pit of success.

Your choice to support either /pages or src/pages is almost an answer, a compromise. You want to fulfil users needs but it seems like you have some fears about letting the user be free to organise his folders.

There are tradeoffs and impact in adding new features, the (negative) impact of allowing setting the pages directory does not outweigh the arguments for allowing it, we've seen this before with distDir, there's a whole category of issues that came out of allowing it and are still breaking between upgrades quite often.

So yes, we're careful in adding new features, because we want you to not get stuck on a certain version and we want to guarantee that they'll continue working in the future.

The best example of this is probably that almost all features outlined in Next.js 1 are still fully compatible with Next.js 9.

I would be happy to deeply understand why you don't want to leave the choice to the user

Besides what I've written above there is this reply: https://github.com/zeit/next.js/issues/8451#issuecomment-523997200

vladnicula commented 5 years ago

As said earlier the main goal for Next.js is to have the right defaults for building websites / web applications and giving flexibility between tradeoffs (eg static, ssr, etc) while putting you / your team into the pit of success.

Well then, you're assumptions about this particular issue is off compared to many people who voiced their opinions.

In the end it's you and the team that needs to support this, so whatever works for you best should be the way to go forward. I wouldn't want to maintain a large codebase that does not follow my ideals.

I hope you also understand that this kind of decisions are strongly polarizing. For my case, nextjs falls down from a tool that I really like to use to a tool I just pick when I want to get something done really fast, without much certainty of customization or long term support.

timneutkens commented 5 years ago

Well then, you're assumptions about this particular issue is off compared to many people who voiced their opinions.

This comment captures part of why we shouldn't allow it: https://github.com/zeit/next.js/issues/8451#issuecomment-523997200

It's hard to argue that anyone:

Maybe you're building short term projects, but there are thousands of actively worked on projects using Next.js. This ranges from the 6th largest website of the internet (by Alexa rank) to personal websites.

I wouldn't want to maintain a large codebase that does not follow my ideals.

Note that I wouldn't use src/pages personally, yet I did write up a RFC to allow it and all the semantics required to implement.

The discussion about introducing config options has many sides. For example in a similar fashion some asked "I want to change all chunking logic", eg how Next.js decides commons etc. instead we ended up implementing https://github.com/zeit/next.js/issues/7631 and now soon all users will profit from this. Whereas if we had introduced the option it would have been more likely to end up in userland with close to no usage.

Furthermore it increases the surface of what users have to learn to be able to start getting productive. For example nextjs.org/learn is part of many companies' onboarding process.

Strandedpirate commented 3 years ago

This is a sad trend in open source. Authors arguing against adding any new features or potentially breaking changes for "reasons". Using this logic no existing "feature" will ever be fixed, augmented, altered, enhanced or changed for "reasons".

It's not like this project's author could just make a breaking change and state it's a breaking change and increment to the next major version number... Who's ever heard of that?

"let them eat cake" - nextjs

andormade commented 3 years ago

If you found this, while looking for a solution, there is now a fork that allows you to set a custom pages directory, you can find a link in this discussion post: #23640

arosemena commented 3 years ago

Another situation where this would be desirable would be when you're targeting environments where no SSR is available, like native apps with something like capacitor, if you want to have both SSR for the browser and client side loaded content you have to do some really dirty hacks around moving the pages directory which could all be solved if we just had a build time option to select where to take the pages from, please reconsider.

balazsorban44 commented 2 years ago

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.