Svelte/Sapper.js - How to initialize store with localStorage data? - javascript

I come from a React background, but I'm switching to Svelte and Sapper for my next application in order to fight the massive bundle size that comes with React these days. However, I'm having trouble initializing Svelte's store with data retrieved from localStorage.
As per the Sapper docs (https://sapper.svelte.dev/docs#Getting_started), I created my project by running npx degit "sveltejs/sapper-template#rollup" my-app from the command line. I then installed the dependencies and removed the demo code in the src folder.
I then created two files: src/routes/index.svelte and src/store/index.js.
Code for both:
src/store/index.js
import {writable} from "svelte/store";
export let userLang;
if(typeof window !== "undefined") {
userLang = writable(localStorage.getItem("lang") || "en");
} else {
userLang = writable(null);
}
src/routes/index.svelte
<script>
import {userLang} from "../store";
</script>
<p>Your Preferred Language: {$userLang}</p>
When I run the application and hit the index route, I see this:
Your Preferred Language: null
which then almost immediately updates and changes to
Your Preferred Language: en
when there is no lang item in localStorage, and changes to
Your Preferred Language: fr
After explicitly setting localStorage.setItem("lang", "fr") from the developer console and refreshing.
I know that the store is being initialized on the server first where window is undefined and then is being rehydrated on the client. So this behavior is expected.
So my question is: how can I skip the server initialization entirely? Is it possible to only set up the store on the client (where localStorage is defined) so that the user's chosen language is immediately available?
I can't default to having everything in English or any other language after the user has chosen to change their preferred language. I also can't get the user language from the browser via navigator.language on initial page load either since navigator is undefined on the server as well.
And having a flash of empty text appear before the store rehydrates would screw up the UX for my application, especially when the value of userLang is going to be used all over the place with translations.
So any strategies or hacks for this are definitely appreciated.
**** Deeper Issue ****
I would actually prefer to not have server-side rendering at all for this application, but I do need all the other excellent features that Sapper provides, like routing, prefetching, and static site building.
So I tried running npx sapper export as per the docs to generate a completely static site in an effort to remove the server from the equation, but the exact same issue still occurs, even though there is no server being used at all.
Does anyone have any advice on how to configure Sapper and turn off SSR but keep the other features?
Thank you!
**** Update ****
As per Rich Harris's answer, wrapping the markup with {#if process.browser} does the trick just fine. So I've updated the src/routes/index.sveltefile like so:
<script>
import {userLang} from "../store";
</script>
{#if process.browser}
<p>Your Preferred Language: {$userLang}</p>
{/if}
And the userLang variable is immediately set with the value from localStorage or defaults to en as I intended for this simple demo. There is no more flash of null, so it's essentially behaving like it's client-side only at this point.
I will work on fleshing out my project and see if there are any more issues I encounter. Til then, I think this solves my issue.

At present, SSR is non-optional. There's an issue open for an SPA mode — https://github.com/sveltejs/sapper/issues/383 — that would behave as you describe, we just need to get round to it.
We also plan to have built-in support for i18n in a future release: https://github.com/sveltejs/sapper/issues/576
In the meantime, you can fake it by wrapping all your markup in {#if process.browser} — anything inside won't be server rendered, but will be present as soon as JavaScript kicks in.

Related

Is it possible to call a function ONLY on the first run?

I am developing an app using Telerik's Nativescript. I would like to know whether it's possible to call a function the first time the app is ran, but not for each consecutive run.
My first thoughts were to ship a one line text file with the content false. On the first run I would check this file and get the value. If it were false I'd run the function and then update the text file content to true, otherwise I'd let the app continue as normal.
I think there must be a better, more efficient way to do this. Any ideas folks?
I've no idea why you're getting a all these browser technology answers but as you're using NativeScript you most probably want to take a look at the Application Settings module.
A value set with Application Settings will persist for as long as the app is installed on the device. If the user is re-installing the app it'll (of course) be reset.
It's as easy as:
var appSettings = require("application-settings");
if(!appSettings.getBoolean("hasRunned", false)) {
// Do the stuff you want to do on first run
// and then set it to true
appSettings.setBoolean("hasRunned", true);
}

EmberJS Reset Warning: Library is already registered with Ember

Some background...
We have an ASP.NET app we're slowly converting over to EmberJS. We have a single Ember application we instantiate for certain portions of the site. As we migration pages they get routes in the Ember app. The goal is to have everything in Ember over time. In the interim, the user can click on links that take them back to ASP.NET portions.
Our issue is with resetting the state of the Ember app if the user either clicks back to go back into Ember or clicks on a new link that takes them back into the Ember portion.
We've tried calling .reset on the application, but doing so gives us an error saying the following. Our application is called ConsoleCli and not the standard App.
Library "ConsoleCli" is already registered with Ember
Moreover, we get the following error saying one of our modules has already been registered.
Cannot re-register: `location:history-js`, as it has already been resolved.
I tried wrapping my registration of the history module with a check, but that creates a whole other slew of errors
if(!application.__container__.lookup('location:history-js')){
application.register('location:history-js', HistoryJsLocation, { singleton: true });
}
I read https://github.com/emberjs/ember.js/issues/10310 and I think it means reset() is supposed to clear all registries once this has all been merged into the main branches.
Shouldn't called App.reset() right in the middle of using an EmberJS application just reset it with no issue?
Excuse my lack of understanding, we're just learning all of this as we go.
We're running the following versions
Ember 1.11.0-beta.2
Ember Data 1.0.0-beta.15
jQuery 2.0.3
TIA!
I think you might have run into this bug: https://github.com/emberjs/ember.js/issues/10310
Try the fix mutewinter suggests in that thread, it has worked for most people (involving myself).

How do I change the underlying Phantomjs object settings using Chutzpah?

We have some QUnit javascript tests running in Visual Studio using the Chutzpah test adapter. Everything was working fine until we changed our api (the one being tested by the js files) recently, and added some validations over the UserAgent http header. When I tried to update the tests to change/mock the user agent I realized it was not directly possible even by overriding the default browser property.
After a few days of scavenging, I finally found what exactly is happening. Chutzpah is creating a phantomjs page object for the test files to run on. This is being done on a base javascript file (chutzpahRunner.js) located at the Chutzpah adapter installation path. These are the last lines on the file, that effectively start the tests:
...
// Allows local files to make ajax calls to remote urls
page.settings.localToRemoteUrlAccessEnabled = true; //(default false)
// Stops all security (for example you can access content in other domain IFrames)
page.settings.webSecurityEnabled = false; //(default true)
page.open(testFile, pageOpenHandler);
...
Phatomjs supports changing the user agent header by specifying it in the page settings object. If I edit this chutzpahRunner.js file in my machine, and manually set the user agent there, like this:
page.settings.userAgent = "MyCustomUserAgent";
My tests start to work again. The problem is that this is not in the project itself, and thus cannot be shared with the rest of the team.
Is it possible to change the properties of the phantomjs objects created by Chutzpah to run the tests? I'd like to either change them from inside my own tests, or from another script file I could embed on the pipeline.
Without a code change in Chutzpah it is not possible to set those properties on the PhantomJS object. Please file an issue at https://github.com/mmanela/chutzpah asking for this functionality and then fork/patch Chutzpah to add it (or wait for a developer on the project to hopefully get to this).
Update:
I pushed a fix for this issue. Once this is released you can use the following in a Chutzpah.json file:
{
"userAgent": "myUserAgent"
}

Is it possible to make an object created in console persistent throughout the session?

Goal: making a standalone modular JavaScript debuggin-utility (includes custom dom and event manipulation methods) to be used in the console (preferably Chrome) on any random sites of interests (with no backend access).
Usage: initially include module script directly via copy-paste to console or by creating a new script element pointing at myhomepage.com/shortandeasytoremember.js and call methods on the namespace from there on.
Problem: how to best make it persistent throughout the session on that webpage (so that I wouldn't need to reinclude it after every refresh) ?
Note: any additional browser compatibility is not required - as long as it works in the latest Chrome, it's all fine by me (but any effort in the compatibility department is always much appreciated for the sake of others). IF YOU READ THIS IN A FAR FUTURE and by then there exists a better solution than what is written down below, please take a moment to contribute with your superior knowledge.
What I currently have is an event listener on window.unload to save any state data to localStorage and a string to make it easier to reinclude the module after page reload using eval(localStorage.getItem('loadMyNS'));.
(function(ns, undefined){
'use strict';
//util methods on ns and few monkey patches for debugging ...
var store = 'if(!window.MyNS){' +
'var xyz9=document.createElement("script");' +
'xyz9.src="http://myhomepage.com/shortandeasytoremember.js";' +
'document.head.appendChild(xyz9);}';
localStorage.setItem('loadMyNS', store);
ns.save = function () {
// and use localStorage for some more data
// to be used by other methods after page reload
};
window.addEventListener('unload', ns.save, false);
}(window.MyNS = window.MyNS || {}));
(browsers with no localStorage or addEventListener may benifit from this article)
I've also concidered using the same schema with window.name instead of localStorage (as long as this still seems legid) just because writing eval(window.name) would take less typing ^^.
The trouble (one of them) I have with the "eval-script-tag-inclusion" is on the sites which block external non-https script sources. An ideal solution would be a globally accessible module which would live with state and methods included (and no initialization required after refresh) at least until I close the the window (or overwrite the ref ofc).
If that is currently absolutely not possible, a lesser solution yet still superior to my current code would suffice.

How to force update of design changes to clients using xPages?

I am bulding a webpage using xPages and I am making constant changes to script and design, this include both server and client javascript , stylesheet and image changes.
Each time I change a javascript or stylesheet I want to see my changes in the webbrowser and I also want my users to get the latest changes when they access the webpage.
I know I can use Shift-Reload, or CTRL-reload and clear my webbrowser cache. and I also know that I can change the objects expiration date, but I want a smoother and better controlled way to do this.
Looking for any kind of best practice for doing this.
Thanks
Thomas
In the xsp.properties file for the application or on the server for server wide use you can set xsp.application.forcefullrefresh=true. The xsp.properties file documentation says:
# Application refresh
# When this property is set to true, then a full application refresh is requested when
# the design of a class changes (means that all the data are discarded in scopes).
# xsp.application.forcefullrefresh=false
The new XSP Portable Command Guide says "This property was introduced in Notes/Domino 8.5.3. It is set to false by default and is particularly useful during the development phase of an XPages application."
I have not fully tested this behavior but it sounds promising. You could/should of course only set it to true WHILE you make the changes. once stable, set it back.
/Newbs
Adding to Ferry's answer and your comment;
Instead of "?dummy=randomvalue", you can use "?version=2.1". So it will be cached but when you change design, you can just increase the version.
There's a problem with this approach as some proxy servers won't cache anything with query params. Better to rename the file directly, adding date or version number to it. It will always work.
To disable caching temporarily use Fiddler2. It's easy to enable and disable in one place across any web client. As well as added benefits for the http request tracking features.
To fully disable any caching add url + '"?dummy=" + #Unique();' to every url to javascript or image files...
The way I am reading this question is that you want every change you make to appear immediately on the client's browser or client. Are you really sure you want to do this? It sounds like you are not doing any testing so any typos, bugs, crashes, etc will be passed on to your users. Sounds like a bad plan to me. I hope I am wrong and that you are using a template and pushing only your fully tested changes up to an production version instead of making the changes in the production version.
I would just put out a schedule of when changes are going to be pushed up to production and let the users reload their browser or client at that time. Either that or do it during off hours and when they next log on, they get the newest changes.
Adding to Ferry's answer and your comment;
Instead of "?dummy=randomvalue", you can use "?version=2.1". So it will be cached but when you change design, you can just increase the version.
maybe you could look at how domino can control caching of url's.
http://www.ibm.com/developerworks/lotus/library/ls-resp_head_rules/
NEwbs answer is a good one but it is useful to note that in Firefox there is a very useful plug in called "web developer" from Chris Pederick that allows you to disable the cache.
http://chrispederick.com/work/web-developer/
The other really useful one is Firebug which is just amazing - It makes any HTML work much easier
https://addons.mozilla.org/en-US/firefox/addon/firebug/
I did found another solution by putting my css and js in a theme it is easy to just rename the files.
as described here
http://goo.gl/vFTii
Why do not we use the window.location.reload()...
Which does the same like ctrl+F5
It reloads the page, which is similar to context.reloadpage

Categories