Sapper is deprecated in favor of its successor, SvelteKit, which we recommend using instead.
To support Sapper, SvelteKit, and the rest of the Svelte ecosystem, please consider contributing via OpenCollective.
The next small thing in web development, powered by Svelte
Home Page: https://sapper.svelte.dev
License: MIT License
Sapper is deprecated in favor of its successor, SvelteKit, which we recommend using instead.
To support Sapper, SvelteKit, and the rest of the Svelte ecosystem, please consider contributing via OpenCollective.
Please provide Router API for defining routes with code. I personally don't like directory structure based routing. NuxtJs stated with directory based routing but now, NuxtJs also provides a Router API for defining routes.
Not sure if this is a Sapper-specific or a general Svelte issue. I have a Svelte template I call "LazyImage" that loads a detailed image asynchronously while presenting a low-res fallback initially. In case the user doesn't have JavaScript, I want to present the detailed image first. Within my template I have:
<noscript>
<img src="...">
</noscript>
But when I run the Sapper site and navigate to the home page with JS enabled, the Network panel of Chrome dev tools shows the <noscript>
images as loading. If I comment out the <noscript>
part of my template, the image does not load (I'm sure of this because I've tried it with distinct images that are not loaded from the JS version). The <noscript>
behavior works fine when JS is disabled.
I know Svelte compiles to JS, but since it's being server-side rendered, I'm curious if there is a good reason why the network is requesting the <noscript>
version (maybe I'm missing something with my service worker or caching?). Any insights would be appreciated, and if this issue is specific to Svelte I'm happy to reopen there.
Taken from: https://github.com/sveltejs/sapper/blob/master/lib/index.js#L148
At the very least, styles should be preloaded via the server. I'd argue that fonts & co should be set as a <link rel=preload/>
by the user from within the template... but the server should send down the bare minimum assets.
Currently, Sapper requires Node 8, which means you can't run it on AWS Lambda and what-have-you
It should be impossible to have [foo].html
next to [bar].html
for obvious reasons — should be a compile time error
After Sapper hydrates the initial route, navigating to other routes causes the page to be destroyed and recreated from scratch. It's therefore not necessary for the hydration code to be sent to the browser other than for the initial route.
Not exactly sure how to achieve that, but it would be a win.
Probably isn't worth doing this on each page render, but the initial templates could be minified to save a few bytes
This page always returns the same markup. If it were possible to determine that statically, we could render the page once and serve it from a cache thereafter.
Gets a little tricky though — even that page has a dynamic-looking expression within the nav (that determines which nav link is highlighted). Would need some form of whole-app analysis. As such, it's probably not something we can do any time soon.
We're currently missing a sensible way to manipulate non-standard page route responses: not founds, redirects and so on.
A /blog/[slug].html
has no way to return a 404 or 301 depending on the slug -- you'd have to handle it client-side upon initialization.
I'm just getting started with sapper, but here are some ideas that might or not work:
Server routes could be able to render page routes
/blog/[slug].js
could then either perform something non-standard or render a /blog/_[slug].html
page route.
Server routes could take precedence over page routes
Currently, you can't have both /blog/[slug].js
and /blog/[slug].html
. If that was allowed, the server route could have first shot at serving the url, defaulting to the page route otherwise. This would be a more organized version of handling certain urls with express
above sapper
middleware. Not exactly pretty.
preload could have knowledge about response codes
Instead of only returning data, preload()
could optionally expect more info about the response, eg. { data: {}, status: 301, redirect: '/bleh' }
. This would be handled automatically by sapper both at the server ("SSRing" redirects and 404s) and the client (automatically triggering routes).
I don't know if that's giving preload
too much power, but I think it's worth exploring things in that direction. If not preload
, a similar feature.
It'd be nice to handle auth this way, too (imagine RealWorld's settings page redirecting to login by simply changing preload
a bit, without client/server differences).
Thoughts?
In dev mode, it'd be nice if the stack trace contained links that took you to the lines in question. (In prod mode maybe we don't want to show the stack trace?)
I hadn't encountered this phrase before, but @dfabulich has an interesting suggestion — the service worker could perform 'SSR' if it had the necessary code to hand.
Not quite sure how practical that is (we'd basically need to load and run the entire server webpack bundle in the service worker, which probably means generating a separate productionised version that doesn't assume any Nodeisms), but it could be a performance win? Am not quite sure, need to think through all the ramifications.
At present, main.js
is written to the destination directory (usually .sapper
). That was so that we could write it to /tmp
in Now, back before building was separated out from serving.
Writing it back to the same folder (as .main.rendered.js
or something) would allow it to use relative imports, when necessary.
Might then be a bit weird that you can't do that with service-worker.js
. Need to think about that, maybe in a separate issue.
It would be helpful if routes/settings/[submenu].html
matched both /settings
and /settings/blah
— in the first case, params.submenu
would be null
, and in the second case it would be "blah"
.
If there was a routes/settings.html
or routes/settings/index.html
, it should take precedence.
At present the middleware is responsible for running the webpack build, even in prod mode. That's convenient, but suboptimal in cases where you don't want to run the build on the server (e.g. lambda)
There's a possible race condition if the user navigates to /foo
, and while Sapper is loading the route and preloading the data, the user navigates to /bar
. Best case, we get some flickering; worst case, we end up on /foo
instead of /bar
.
Saying you wanted to show a loading indicator when navigating between routes, or something of that nature — the best way to do that would be to have a navigation hook:
import { onnavigate } from 'svelte/runtime/app';
onnavigate((from, to, promise) => {
console.log(`navigating from ${from.href} to ${to.href}`);
const loading = new LoadingIndicator();
promise.then(loading.destroy);
});
Need to consider what the arguments should be. Is there a possibility of something like onprogress
, for example? Should from
and to
just be hrefs, or should we also get params etc? Should it be possible to cancel the navigation, or change it, or inject some data (e.g. {slidingTo: 'left'}
), or delay it pending some operation?
And should it be onnavigate(...)
, or on('navigate', ...)
? i.e. do we anticipate adding more events?
Hi - I've been using basic Express and Koa for some time and missed the boat on a few generations of Node tech (particularly Webpack). Trying to catch up with this and/or Svelte framework.
When I run node server.js
I am expected to have made a webpack.client.config.js
and webpack.server.config.js
already. I see some sample JSON configs for these in other repos (such as https://github.com/sveltejs/template-webpack ). What's the right way to set these up so that I am webpack-ing all the files of a sapper app?
There should be a really good way to write acceptance tests for a Sapper app, maybe cleanly integrating with services like Cypress.
Goes for both templates/*.html
and templates/*.js
Would it be possible to provide a mechanism for writing templates in JSX rather than svelte? I guess it would be a welcome addition and could potentially address the barrier to entry for people coming from a react background.
In a lot of cases (e.g. this about page), there's no need to hydrate the page because nothing is interactive. We can just wait for the first navigation event.
This is perhaps something that belongs in Component.render(...)
:
const { html, head, css, interactive } = Component.render(data);
// if `interactive === false`, set `window.SAPPER_IS_INTERACTIVE = false`,
// then we don't bother with the initial `navigate(new URL(window.location))`
https://developers.google.com/web/fundamentals/performance/prpl-pattern/
Easy enough to preload subsequent routes. (Does it need to be configurable?)
At the moment they're just printed to the console which isn't particularly helpful
Currently Sapper assumes you're using Express (though it may also work with Connect? Haven't tried). Would be interesting to see how straightforward it'd be to support Hapi and others as well
I imagine (though I'm not sure) that Sapper supports all of the request types that express supports, but trying to export a DELETE handler currently won't work because delete
is a reserved keyword, so export function delete(){}
won't work.
Is there a clever workaround to trick js into letting me use delete
? If not, could we add one to Sapper?
I thought maybe webpack harmony magic would let this work, but it doesn't seem to:
export default {
delete(req, res) {
console.log('delete');
}
};
Thanks! And great work as always, Sapper is fun.
Is there an easy event handler for when Sapper navigates to and loads a page?
For my particular use case, I'm lazy loading images and swapping a blurry image src with a more detailed image src after the document has loaded. This works great using window.onload when I initially navigate to the page or hard refresh, but when navigating from another page within my Sapper app, the onload method is never called. Is there a Sapper equivalent for onload?
If you go to https://svelte.technology/guide#if-blocks and click around in the sidebar, you'll notice it's a little sluggish. That's because it's destroying and recreating the entire page each time, including preloading, which hits the network (it should probably be cache first, but that's a separate story).
@Rich-Harris mentioned in a Hacker News thread that Sapper will eventually have static site export functionality. I've created this issue to track the progress on that and potentially see if there's anything that can be done to jump the gun.
(For my specific use case, I really want to start using Sapper to build progressive static websites that I can deploy with Netlify)
I guess we just need to recognise file extensions other than .js, and update the webpack config in sapper-template
Ideally, the user would be able to write a custom service worker (much as you have to bring your own server), but it would be straightforward to generate a cache manifest with all the webpack-generated stuff, static routes, assets, etc.
When serving pages, we know ahead of time the URL of the main.[hash].js
file that needs to go with it — it would be easy to add a preload header.
We could probably figure out what other things need to be sent by inspecting the generated HTML (<link rel=stylesheet>
, <img>
etc). Maybe there's an existing module that does that?
More ambitiously we could attempt H2 push, but I'm not sure what's involved there.
If an <a>
element has rel=prefetch
, Sapper should store the results of preload
for the duration of the interaction rather than calling it again following click
, since there's no reason to believe the data will be coming from the service worker cache the second time round.
A link like https://svelte.technology/guide#state-management should take you directly to the relevant section, but it doesn't — it takes you to the top of the document
This probably means adding chokidar, though it might be worth trying to implement with the built-in fs.watch
stuff (or use chokidar if and only if it's installed separately?)
We don't need to wait for preload
to resolve before serving the beginning of the document (up to the first %sapper.whatever%
tag whose value isn't already known). Doesn't win us much, but still probably worth doing.
For static sites (e.g. svelte.technology), it might be nice to have an equivalent of next export
. Could be done like so:
// scripts/export.js
const exporter = require('sapper/export');
const pages = [
'/',
'/guide',
'/repl',
'/blog'
].concat(getListOfBlogPostsSomehow());
exporter.export(pages, 'dist').then(() => {
console.log('done');
});
That would run server.js
in a separate process and basically just curl
those URLs into dist
, and copy over the assets
folder and the files generated by the compiler.
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.
Sapper shouldn't try to do the job of dedicated logging middleware, but it should provide some visibility into what's happening. Not sure what established practices are here, probably worth cribbing from Next and Nuxt
It's small enough that maybe it doesn't make sense to make an extra request?
At some point we'll need to be able to do this sort of thing:
import { goto } from 'sapper/runtime/app.js';
goto('/a?b=c').then(() => {
// navigation succeeded
});
goto('/d', { replaceState: true }).then(...)
Presumably it would only fail if the href
matched some route and there was an error during preload or render.
Open question whether or not it should navigate if no route is matched (i.e. just doing window.location.href = href
). I suppose probably yes.
Also:
routes
directoryRather than the initial page doing preload
on both server and client, the server should send the preloaded data with the client app, so that it's unnecessary.
Follow-up to #40. Does it make sense to try and run webpack on service-worker.js
?
It's a little awkward to do so, since the service worker needs to be rendered after the client bundle has been created (as it depends on the assets generated therein). And it would be a shame to add another webpack config. It would also be a shame to include all the unnecessary gubbins webpack would add to the file.
The alternative is to stick with the process we have now, which (at least post-#40) might be a little confusing, since it means main.js
and service-worker.js
are subject to different rules.
Looks like Sapper doesn't work on Windows yet...
C:\Apps\Testarea\svelte\_sapper>npm run dev
> [email protected] dev C:\Apps\Testarea\svelte\_sapper
> node server.js
fs.js:1214
binding.utimes(pathModule._makeLong(path), atime, mtime);
^
Error: EINVAL: invalid argument, utime 'C:\Apps\Testarea\svelte\_sapper\.sapper\main.js'
at Object.fs.utimesSync (fs.js:1214:11)
at create_client_main (C:\Apps\Testarea\svelte\_sapper\node_modules\sapper\lib\utils\create_app.js:33:6)
at create_app (C:\Apps\Testarea\svelte\_sapper\node_modules\sapper\lib\utils\create_app.js:54:2)
at connect (C:\Apps\Testarea\svelte\_sapper\node_modules\sapper\lib\index.js:22:2)
at Object.<anonymous> (C:\Apps\Testarea\svelte\_sapper\server.js:20:9)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev: `node server.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dev script.
npm ERR! This is probably not a problem with npm. There is likely additional log ging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\bin\npm-cache\_logs\2017-12-17T21_11_38_903Z-debug.log
Moved from sveltejs/sapper-template#14 cc @1wheel
I'll get an error like this on the client:
process-update.js:136 [HMR] Update check failed: Error: Manifest request to /client/7f71269cd30032b87e4f.hot-update.json timed out.
at XMLHttpRequest.request.onreadystatechange (http://localhost:3000/client/main.7f71269cd30032b87e4f.js:64:22)
handleError @ process-update.js:136
cb @ process-update.js:47
Promise rejected (async)
check @ process-update.js:84
module.exports @ process-update.js:42
processMessage @ client.js:251
handleMessage @ client.js:131
handleMessage @ client.js:94
bootstrap 7f71269cd30032b87e4f:63 Uncaught (in promise) Error: Manifest request to /client/7f71269cd30032b87e4f.hot-update.json timed out.
at XMLHttpRequest.request.onreadystatechange (bootstrap 7f71269cd30032b87e4f:63)
request.onreadystatechange @ bootstrap 7f71269cd30032b87e4f:63
Promise rejected (async)
check @ process-update.js:81
module.exports @ process-update.js:42
processMessage @ client.js:251
handleMessage @ client.js:131
handleMessage @ client.js:94
And then everything hangs. API routes don't start processing requests (no console.log
printing in the terminal) until the process is killed and then requests finish.
Don't know enough about this stack of tools to debug, but might have something to do with lack of error handling here?
preload({ params, query }) {
return fetch(`/api/feed`).then(r => r.json()).then(posts => {
return {posts}
})
}
At present, Sapper prefetches all code-split chunks in no particular order. It could do better. In increasing order of difficulty:
Also, in some cases it'd make sense not to prefetch at all.
uglifyjs-webpack-plugin postinstall is failing on Windows 7.
Inspired by http://instantclick.io/, we could preload pages that the user is about to click on (i.e. load the route, if we haven't already, then call the preload
function if it exists).
A (unlikely but possible) security issue — if a page sets a value on store
, it will be present when that page (or any other page also using the store) is re-rendered for another request. In extreme cases this could result in personal information being shared.
Not totally sure what the best solution is.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.