I am coding a little website to be my homepage.
So far I managed to do what I wanted with express and handlebars templates but I am doing this website to test my boundaries, and I lack using a frontend framework and working with web components.
so for the sake of challenge and learning, I settled on svelte
which is not exactly a framework, I read, but is a delight to write with and seems very promising on the performance side.
The problem is I want to keep the hand on my website, and sapper, the full framework that comes with svelte, is a bit too much of a black box for me.
(you put this file here and that file there,
compile with this complex configuration you shouldn't touch
and BOOM you got routes)
What I would like is to use express to manage the routes and then render the svelte app, either with a different page/app for a route, or the same app with different variables.
Could anybody point me in the right direction?
I considered using sessions or a socket, but I have no idea of how to listen to this client-side and the documentation/articles about svelte are sparse and all talk about sapper.
here are a few lines of code I wrote in a test app. I know it's not the way you do it but it was for curiosity's sake
// --------------server.js
// ...
app.set('view engine', 'hbs')
app.set('views', path.join(__dirname, '../views'))
// Using a view engine on TOP of svelte
// is certainly a bad choice
app.use(express.static('app/public'))
// to make the svelte compiled .js and .css available
app.get('/test', (req, res) => {
res.render('home', {user:true})
// I tried to send props like this
// it did not get the props in svelte,
// but what I found is that svelte ADDS itself to the page
// and does not remove the HBS code, event though it is in the target container
})
edit
I will finally use sapper, thank you for the advices...
I really would like them to implement some sort of svelte middleware that allows to render/serve pages individually (once they are build of course)
If you do it like that, splitting your web application into several independent svelte apps that are served from express, then you need to keep the (web-)application wide state on the backend or keep it in the local storage on the browser. You can't use the states provided by sveltes store (writeable, etc), because that's in-memory and destroyed whenever you navigate to a new page (via express).
If sapper is to much magic but you want to keep running a single-page-app, have a look at svelte-spa-router. That isn't configuration based.
Related
Background:
I'm building an SPA (Single Page Application) PWA (Progressive Web App) using Vue.js. I've a remote PostgreSQL database, serving the tables over HTTP with PostgREST. I've a working Workbox Service Worker and IndexedDB, which hold a local copy of the database tables. I've also registered some routes in my service-worker.js; everything is fine this far....
I'm letting Workbox cache GET calls that return tables from the REST service. For example:
https://www.example.com/api/customers will return a json object of the customers.
workbox.routing.registerRoute('https://www.example.com/api/customers', workbox.strategies.staleWhileRevalidate())
At this point, I need Workbox to do the stale-while-revalidate pattern, but to:
Not use a cache, but instead return the local version of this table, which I have stored in IndexedDB. (the cache part)
Make the REST call, and update the local version, if it has changed. (the network part)
I'm almost certain that there is no configurable option for this in this workbox strategy. So I would write the code for this, which should be fairly simple. The retrieval of the cache is simply to return the contents of the requested table from IndexedDB. For the update part, I'm thinking to add a data revision number to compare against. And thus decide if I need to update the local database.
Anyway, we're now zooming in on the actual question:
Question:
Is this actually a good way to use Workbox Routes/Caching, or am I now misusing the technology because I use IndexedDB as the cache?
and
How can I make my own version of the StaleWhileRevalidate strategy? I would be happy to understand how to simply make a copy of the existing Workbox version and be able to import it and use it in my Vue.js Service Worker. From there I can make my own necessary code changes.
To make this question a bit easier to answer, these are the underlying subquestions:
First of all, the StaleWhileRevalidate.ts (see link below) is a .ts (TypeScript?) file. Can (should) I simply import this as a module? I propably can. but then I get errors:
When I to import my custom CustomStaleWhileRevalidate.ts in my main.js, I get errors on all of the current import statements because (of course) the workbox-core/_private/ directory doesn't exist.
How to approach this?
This is the current implementation on Github:
https://github.com/GoogleChrome/workbox/blob/master/packages/workbox-strategies/src/StaleWhileRevalidate.ts
I don't think using the built-in StaleWhileRevalidate strategy is the right approach here. It might be possible to do what you're describing using StaleWhileRevalidate along with a number of custom plugin callbacks to override the default behavior... but honestly, you'd end up changing so much via plugins that starting from scratch would make more sense.
What I'd recommend that you do instead is to write a custom handlerCallback function that implements exactly the logic you want, and returns a Response.
// Your full logic goes here.
async function myCustomHandler({event, request}) {
event.waitUntil((() => {
const idbStuff = ...;
const networkResponse = await fetch(...);
// Some IDB operation go here.
return finalResponse;
})());
}
workbox.routing.registerRoute(
'https://www.example.com/api/customers',
myCustomHandler
);
You could do this without Workbox as well, but if you're using Workbox to handle some of your unrelated caching needs, it's probably easiest to also register this logic via a Workbox route.
During one of the interviews I got a question how to separate business logic from controller in Express. Would be that a correct solution?
const db =require('./db')
const helpers =require('./helpers')
exports.getBooksValue = (req, res)=>{
const books = db.get(req.params)
const booksValue = helpers.calculateBookValue(books)
res.send(booksValue)
}
Actually there is no correct(standard) solution in express whereas ruby on rails for example has mvc pattern in its standard way since express encourages more flexibility.
Your solution looks good, but if you are focusing on further seperation,
I suggest you to make config folder and managing db's information inside of that file.
Inside of config folder, make sure to seperate whether it is for production or development.
You can also use dotenv in config folder for importing env values more safely.
I am building a website based on https://github.com/Vheissu/aurelia-starter-node. It will have some backend logic in the /api area and there will be also a SPA area handled by Aurelia. I would like to:
read config in express app (https://www.npmjs.com/package/config) using require('config')
use this config on the server (usual stuff)
use a subset of this config on the client (in the Aurelia app)
I know about https://github.com/Vheissu/Aurelia-Configuration but I don't want to maintain two config sets handled by different libraries, dealing with setting the environment in two places etc.
Question: is there a clean way to do what I am looking for?
My thoughts so far:
pass something to aurelia bootstrapping logic, but I can't find any info about this
ugly solution: rendering the config as global variable into index.html (the one which is the master page for the SPA) and read it from Aurelia code, more less like How to pass data from ASP.NET WebForms to Aurelia Global Scope
I ended up keeping the configuration in the server code and rendering only the client part of it to the body of the page like so:
When defining aurelia routes for my app:
let model = {
clientConfig: {
x: 123
}
};
res.render('index.html', model);
And then in view (using ejs templates):
<script>
var config = <%- JSON.stringify(clientConfig) %>;
</script>
For me this feels much cleaner than maintaining the config in two places.
I'm building an express app in express 4.0 (rc3), since I'm starting from scratch and in development for a while, but if there's a way to do this in 3.0, that'd be welcome too.
What I want is a set of comment REST routes that I can attach to other routes in my API. So:
/posts/:postID/comments/:commentID
/profiles/:profileID/comments/:commentID
The way I was doing it was to encapsulate the comment routes into a module, including a buildRoutes(router) function in the module.
Then I can do app.use('/api/comments', commentController.buildRoutes(express.Router())) in my main server definition, and then in my profile module's buildRoutes(router), I can do
buildRoutes = function(profileRouter)
.... build the basic CRUD routes ...
profileRouter.get('/:profileID', show)
profileRouter.use('/:profileID', commentController.buildRoutes(express.Router()))
It seems like only the .VERB methods actually replace :wildcards in the route, and not the .use one. I could always muddle through with a piece of custom middleware that goes on a /api/profiles/* and maps the appropriate URL parameters into req.fields, but I want to make sure that this is actually required.
So this wasn't particularly easy to do the way I originally intended. However, I just avoided the entire problem by reframing my buildRoutes method to accept a baseURL and a router argument. Instead of modularizing it completely, now I say, profileController.buildRoutes('/api/profiles/', router) which in turn calls commentController.buildRoutes('/api/profiles/:profileID/comments', router), and so on.
It's not terribly satisfying (I would rather encapsulate path/routing information and hide that from the controller) but it works.
My application has 2 purposes:
It needs to run stand-alone, where it needs routing for choosing a
study etc.
Or, it runs integrated in an other project, and only needs
one controller and one view.
Currently i have a routeProvider configured for the stand-alone application, injecting the pages in the ng-view tag in the HTML.
Now is my question: How can i inject an controller and view in the ng-view (For the integration). I cannot manipulate the HTML since it is static. I cant use a single routeProvider rule, because this can interfeir the application that integrates mine (Other plugins can use the #/.. for info or other things).
In your situation you can't use routeProvider when other stuff interferes.
Of Course you could prevent routeProvider to act on outside changes of the hashbang with workarounds but thats not nice.
routeProvider will listen to all changes of the url after the hashbang.
So what you should do is to manually bootstrap() your angular app with the controllers you need. If your app is small enough you could even use directives to achieve lazy loading of templates with the attribute templateUrl : "/myurl"
Usually to create a dynamic App use Routing. Simnple point.
The best way to use Angular if you want to unleash all its might don't integrate it.
I explain why:
+ Your state never gets lost due to page reloads
+ You have full control of the environment and don't have to worry about interfering scripts etc.
+ If your user should manually reload, you can redirect to home/login or even better use requireJS or HTML5 local storage to recover your scopes after a reload
Cheers, Heinrich