sveltejs / sapper

The next small thing in web development, powered by Svelte
https://sapper.svelte.dev
MIT License
7k stars 434 forks source link

Single npm package with a single config file #68

Closed ansarizafar closed 6 years ago

ansarizafar commented 6 years ago

NuxtJs is a single package/Cli/Express middleware and it hides all other dependent packages like webpack etc. NuxtJS has an optional single config file (nuxt.config.js) for setting user defined options. Sapper should do the same.

EmilTholin commented 6 years ago

It is a design choice to expose all the plumbing for configuration, as stated in the introductory blog post:

It should be possible to understand and customise every aspect of the system — no webpack configs locked up in the framework, and as little hidden 'plumbing' as possible

ansarizafar commented 6 years ago

Nuxtjs, NextJS, StencilJs and now Vue are using single package as It is easy to update a single package. A starter project with multiple dependencies and multiple config files is hard to update/upgrade. You can easily customize webpack and other framework specific configurations by using the single and optional configuration file provided by these other frameworks.

EmilTholin commented 6 years ago

I personally don't think it's an issue. Where do you think the pain points are?

On the server, sapper is just a middleware. Would you like the global fetch and requirement to serve the asset folder to be hidden in sapper, but optionally configureable in the middleware instead?

// server.js
const static = require('serve-static');
const fetch = require('node-fetch');
const { PORT = 3000 } = process.env;

app.use(sapper({
  fetch: (url, opts) => {
    if (url[0] === '/') url = `http://localhost:${PORT}${url}`;
    return fetch(url, opts);
  },
  assetMiddleware: static('assets')
}));

Is it the webpack configs that you would like to have abstracted away, and only change if needed?

// sapper.config.js

module.exports {
  serverConfig: ({ config, defaultLoaders, dev }) => {
    const { htmlLoader } = defaultLoaders;

    config.module.rules = [
      htmlLoader,
      myCustomLoader
    ];

    return config;
  },
  clientConfig: ({ config, defaultLoaders, dev }) => {
    // ...
    return config;
  },
  folders: {
    assets: 'assets',
    routes: 'routes'
  }
}
ansarizafar commented 6 years ago

Yes, webpack configs and any framework specific configuration. All other frameworks are using this approach for better developer experience and easy framework update/upgrade. One npm package and one optional config file. Even webpack 4 (Next version) is using the approach. We can learn from NuxtJS and StencilJS.

Rich-Harris commented 6 years ago

In my view this is a weakness of existing frameworks — it looks convenient initially, but as soon as you need to tweak things (adding Passport to your server, using DefinePlugin to replace variables such as API endpoints in your app), you suddenly need to learn a new framework-specific way of doing so, which means unlearning what you already know and trawling through documentation. In my experience, the less 'magic' a system has, the more resilient it is in the long term.

There's also a distinct advantage to the degit sveltejs/sapper-template my-app approach: you can easily fork that repo and creating one that's more applicable to you or your company (e.g. with CSS for your brand, your linter rules, etc).

I hear what you're saying, and it's possible that there's a happy medium in between the two approaches, but it is a deliberate decision — the less logic that's bottled up in esoteric configuration files, the better.

Rich-Harris commented 6 years ago

(An additional thought: perhaps if degit was more sophisticated and had a degit update command that helped with the process of pulling in newer commits from the starter template?)

ansarizafar commented 6 years ago

All these frameworks allow you to configure anything you want using a single configuration file. You don't need to learn any new api to configure webpack. You can use any other npm package like passport without any issue. All other frameworks including react are doing it for a reason and If we want to make Svelte/Sapper a mainstream framework then we should follow the same approach.

joshua1 commented 6 years ago

@Rich-Harris , a feature like a default layout needs to be specified in a config file, and remove the need for this block

components: {
            Layout
        }

you have to write repeatedly, unless when applying a different layout to a route or component and having to wrap every template block in the Layout Tag. This also applies to the :Head which can be in a config file for general use and can also be component specific. While taking the open everything approach, having a config file for certain things will help prevent app level bloat

it's possible that there's a happy medium in between the two approaches,

This here ^^ should be explored

Rich-Harris commented 6 years ago

@ansarizafar

You don't need to learn any new api to configure webpack. You can use any other npm package like passport without any issue.

I'd dispute that — look at https://github.com/zeit/next.js/#customizing-webpack-config, for example. Rather than having all your webpack config readily visible in a normal config file, where anyone can read it and feel confident of their understanding of what's happening, you have to define a function that manipulates an existing config — the very definition of a new API.

And yes, you can use Passport, but with Next.js (picking on it because I know the others less well) you write your server in a slightly unusual way:

const express = require('express')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
.then(() => {
  const server = express()
  // ...custom code goes here
})

All your custom logic goes inside an app.prepare().then(...) handler, and we have separate app and server objects (in most Express tutorials, app is the thing that's called server here, and if there is an object called server, it's the result of calling app.listen(...). This is a necessary consequence of the design. Because it deviates from community conventions, documentation for things like Passport is harder to read, because you're constantly translating in your head to and from the framework's way of doing things.

Sapper is 'just middleware', so it adheres more closely to those conventions. This is fully intentional!

The idea of 'hiding' dependencies inside a monolithic framework is one that can only end in those hidden dependencies getting out of date. It takes control out of the hands of app developers, in return for the illusion of easier upgrade paths.

@joshua1

a feature like a default layout needs to be specified in a config file, and remove the need for this block

If you look at one of the routes in the starter sapper-template repo, you'll notice that the layout component has a parameter — in this case specifying which nav button should be active. If we were to create a config file that specified a default layout, some undesirable things would happen:

I'd argue each of those things are much worse than the modest boilerplate involved! Regarding <:Head>, the bits that are shared between all pages should go in your templates/2xx.html file; the <:Head> component is for the bits that aren't shared.

ansarizafar commented 6 years ago

@Rich-Harris I have mostly used NuxtJS and PoiJS https://poi.js.org. In my opinion, not everyone will customize Webpack configuration so It is a better idea to hide webpack configurations and expose a function for custom configuration. In case of single framework package, Beside easier upgrade, package maintainers can control dependencies versions. I am still in favour of Single configuration file and single package.

ansarizafar commented 6 years ago

Check this Evan You Tweet

https://twitter.com/youyuxi/status/951256164284715008

ansarizafar commented 6 years ago

Webpack 4 is also trying to be as configuration-less as possible https://github.com/webpack/webpack/issues/6244

egoist commented 6 years ago

I actually quite like the design choice Sapper made, the webpack config is also so simple that you don't even need to lock it inside the package: https://github.com/sveltejs/sapper/blob/master/webpack/config.js Seems the only things that matter are entry and output, then you can freely customize other parts of your webpack config, with confidence. If you prefer a webpack abstration like webpack-blocks / webpack-chain or even Poi, you can use them to craft your webpack config too.

btw the command sao sveltejs/sapper-template my-app is totally legit too, with a -u flag you can update the cached template. 😄

Rich-Harris commented 6 years ago

oh, sao with the -u flag is neat! will have to check it out.

I'm going to close this issue as I don't think it aligns with Sapper's goals.