As I am using next-i18next, I figured that I am calling language API (json format) when I build the next.js project by using i18next-http-backend in next-i18next.config.js
Downside of it, is that I need to REBUILD the project when language data is changed ...
So, I found this function called i18n.reloadResources() which works perfectly inside getServerSideProps(). (The reason why I want to avoid server-side rendering is that the language data is way too big. more than 800kb, for one language and I have 15 language translations. Every pages with 800kb API call is miserable ... I think)
However, I do not want to call API every time I re-render the page, and I found out about Incremental Static Regeneration (ISR, on-demand), but seems like it does not work the same way. In other words, it is not working.
Any suggestions for this type of situation?
Related
I am currently using meteorhacks:ssr along with wkhtmltopdf in order to generate downloadable pdfs within my Meteor app. It is working end-to-end, which is great, apart from one last element.
The template helpers which have been specified in packages across my app, are not visible. From the examples in the documentation for SSR it uses templates and helpers specified at a super-package level, which is not feasible with a package based arrangement for an app.
The only way I can see to make them available both client and server-side is to store the functions in an object, and then to loop through the helper functions in client and server code to render the functions accessible in both places.
That methodology works, but it is rather lacking in beauty. Does anyone have any other experience/ideas with this?
As my Meteor project grows and I add more templates, partials and helpers, it gets harder to figure out what will be the data context for it. Then I'll have to console.log(this) inside a helper function to figure out what's the data I'm dealing with.
Does anybody have a naming scheme or any other strategy to handle this?
Or is this mess just a sign I'm failing to modularize stuff properly and should refactor everything?
For me, each module has a folder. Each folder contains helpers.js, events.js, the "ons" (onCreated.js, onDestroyed.js, onRendered.js) and finally templates.html. If your project is big, break these out into individual subfolders for the necessary CRUD actions (I have a create folder and an update folder because reading & deleting happens in the update templates.
My template names are long and verbose, but that's OK, WebStorm does a good job of guessing what I want. For example, if I had some infowindow that listed all the addresses associated with a client: clientMap, clientMapPopup, clientMapPopupLocationList clientMapPopupLocationListItem.
Regarding data context, it's usually pretty easy to see since my helper is the one that added something to the context. Although I honestly try to avoid using that unless I'm in an {{#each}} because IMHO things like grabbing grandparent context is neither elegant nor robust. Instead, I have a temporary module object that I create & destroy on route changes.
So if my global object is Global = {}. In the onCreated and onDestroyed I write Global.Module = {} Then, I can create all the module-scoped variables I want (ReactiveVars, ReactiveDicts, local collections, primitives, client markers object, etc).
All that said, doing what you do & looking at my schema js (e.g. collections/clients.js) is still the fastest/thoughtless way to see what you want & what you're currently getting.
I want to attach YUI modules synchronously.
Given the YUI modules are already on the page
When I run: console.log YUI().use('base').Base
Then I get `undefined`
However,
When I run: YUI().use('base', (Y) -> console.log Y.Base)
Then I eventually get the Y.Base ctor function
It looks like loader is attaching async as it works fine using the callback method. IIRC the first method is supposed to work too though. What am I missing?
If you're using YUI in a controlled environment like Node.js, then you should be able to use useSync configuration:
YUI({ useSync: true }).use('base').Base
But in a browser, or any other client runtime you should stick to the asynchronous nature of Y.use so loader can do its job of computing the proper list of modules to be attached based on the feature detections etc. Having the modules included manually in the pase is just not enough. Imagine the scrollview-base in IE, which requires an special module called scrollview-base-ie, unless you do detection when building the initial markup that includes that module only when running in IE, you will have a missing module. Again, stick to the asynchronous pattern when loading stuff.
YUI modules really want to be called through a Y object in a callback. If you know for sure that all the code you need is loaded on the page, you can attach them all synchronously with a use *. See https://github.com/evangoer/yui3-cookbook/blob/master/examples/loading/use_synchronous.html for an example.
This is quite a lengthy post, so bear with me. I'm not sure whether it is primarily about ASP.NET Session State behaviour, NInject, application design, or refactoring. Read on and then you can decide... :-)
Background
First, a bit of background. We are working on trying to refactor a large webshop into a more maintainable , structured design. The webshop is currently running on .NET 3.5, but the design is more of a hangover from the classic ASP days. Obviously we cannot tackle everything in one go, so many of the features / technologies / approaches have to be taken as a given. With that in mind...
The app maintains everything to do with the current session (user profile, cart, session choices, etc.) in a context object which is simply a large XML document that gets serialized to and deserialized from the Session as a string. The XML format is also important because the rendering is done via XSLT.
This has led to a number of problems :
It's a kind of God object with far
too many concerns.
It's loosely typed and relies too much on XML manipulation / XPath.
There is no standard way / pattern for retrieving the session xml document or for writing it back. We have a horrible mixture of methods that take the document in as a parameter, modify it and return it, methods that retrieve it themselves, modify it and save it back to session, etc, etc. This has lead to a lot of hard to trace bugs, over-use of serializing /deserializing from the Session, etc.
Our Solution
What we have done is try to introduce a strongly -typed wrapper around the xml document, which breaks it up into different concerns and to manage the lifecycle transparently to the rest of the app.
What we are aiming for is the following workflow:
Beginning of the request, we populate
the session document from the xml
string stored in the session.
The rest of the app interacts with it
only through the strongly typed
wrapper. The whole app uses the same
instance and does not have to worry
about when to retrieve or save the
state back to session.
At the end of the request, the underlying xml document is serialized back to the Session.
Since we are using NInject(v1) as the IOC of choice, we decided to use this to manage the lifecycle of our context object. The context object was wrapped with the OnePerRequest attribute and the dispose method was hooked up to a method that would save the xml document back to Session as a string.
It doesn't work...
We soon encountered a problem that the NInject OnePerRequest module didn't appear to have access to SessionState. The first thing we tried was a hack that we would keep the Session object in a variable to make sure we could still write to it. This appeared to work on a development machine but it became obvious it didn't when moving to out of process state.
It still doesn't work...
We tried inheriting from the OnePerRequest behaviour / module, and adding the IRequiresSessionState marker interface (OnePerRequestRequiresSessionState). However, this was not enough as the method which NInject uses to release references and clean up gets hooked up to the EndRequest method. Session is available in EndRequest but it has already been serialized to the out of process state server so changing something now is not reflected when the session string is retrieved at the beginning of the next request.
We then decided to change the even t to hook up to. We ditched EndRequest and hooked up our OnePerRequestRequiresSessionState "release all" method to the PostRequestHandlerExecute event, which is BEFORE the session data gets serialized out of process.
It works... then it doesn't...
This seemed to work. On a single server and on a web farm. Then we noticed weird behaviour. There seemed to be two different versions of the context and you would randomly switch between them. Add something to the cart, it's not there. Go to browse to another product and the previous product would show up in the cart.
After some tracing, we discovered the culprit: Response.Redirect. Sprinkled throughout the site in literally hundreds of places is Response.Redirect(url);. With this version of the redirect, the execution of the page is stopped immediately. This means that PostRequestHandlerExecute is not fired and the current version of the Context object is not thrown away by NInject... and everything falls apart. New versions are not created properly, etc. EndRequest is fired which is why the normal NInject OnePerRequest module works fine with it, just not our bastardized version that tries to use session state.
Of course, there is an override to Response.Redirect where you can pass a boolean value in to tell it whether to terminate the existing page or continue to execute - Response.Redirect(url,false). Continuing obviously fires our event and everything works but... it continues to execute the rest of the page! This means executing everything that comes after the call to Redirect and we have absolutely no idea what that means (since the existing site expects it to stop).
What next?
So, any suggestions on what to do? So far we've discussed :
Abstracting our redirect behaviour
and going through a central method
that controls the redirect (perhaps
hacking out a way to call the
PostRequestHandlerExecute even t or
maybe a custom Redirect event that
our NInject module can also
subscribe to and clean up).
Seeing if there is a way we can
force the Session object to save in
EndRequest if it hasn't been saved
previously in
PostRequestHandlerExecute, and do
the ninject clean up in EndRequest
Remove our dependency on Session
completely and use another storage
mechanism: DB, document DB,
distributed HashTable, etc. Any
advice? Suggestions we haven't
thought of? Things you've tried
that have / haven't worked?
I think you're on the right track. Here's some thoughts I had:
in addition to the strongly typed wrapper you have, I'd suggest a facade for accessing the context object that returns your wrapper, something like an IContextProvider. that way you can introduce it piece-meal, and then when it's fully integrated, you can refactor the provider without breaking the things that use it. I can't tell, but you might have already done this. it'll also be easier to change your persistence mechanism if you choose to. if you can do this, I would suggest once you get all the dependencies isolated from the context object, change it to not persist as XML. the SessionState will store a binary object much faster, and you can always serialize to XML if you need to do transforms.
I don't think that Ninject is the correct mechanism for what you're trying to do. it's difficult to signal end of the request in Ninject, since garbage collection can't be depended on. have you considered using an IHttpModule instead? you can use the AcquireRequestState and ReleaseRequestState or EndRequest to handle getting/setting the context in Session. only allow the app to get to the context object through the facade.
if you're on a webfarm, you're probably using a database for your Session storage anyway, so putting your context into a DB won't be much different.
Firstly, while it's good to demonstrate you've put in the work, (and I and others may not have replied if it wasn't clear how much you're interested in a resolution)... that's a massive wall of text! Here's a +1 on your way to investing in a bonus for a complete response that talks about the Ninject ASP.NET extensions and how they apply to each individual element of your issue. Having said that, hopefully someone will come along with a real resolution for you.
Even though it's [very] 2.0 specific, Nate's Cache and Collect Post is required reading. While it seems you're pretty au fait with the tradeoffs involved and have debugged deep in, the article is well worth a few reads.
I'd also consider moving to V2 of Ninject - a lot of this stuff has been revised significantly. It's not magically going to work, but represents a mature rewrite based on a lot of learning from V1. Have you read the (V1 or) V2 unit tests for Ninject? They'll show you the low level tools at your disposal in order to realise your goals.
Bottom line for me is that you need to work out a strategy for your state management independent of DI, and then by all means use the container/DI system as a part of the implementation.
I have an unusual environment in a project where I have many files that are each independent standalone scripts. All of the code required by the script must be in the one file and I can't reference outside files with includes etc.
There is a common function in all of these files that does authorization that is the last function in each file. If this function changes at all (as it does now and then) it has to changed in all the files and there are plenty of them.
Initially I was thinking of keeping the authorization function in a separate file and running a batch process that produced the final files by combining the auth file with each of the others. However, this is extremely cumbersome when debugging because the auth function needs to be in the main file for this purpose. So I'd always be testing and debugging in the folder with the combined file and then have to copy changes back to the uncombined files.
Can anyone think of a way to solve this problem? i.e. maintain an identical fragment of code in multiple files.
I'm not sure what you mean by "the auth function needs to be in the main file for this purpose", but a typical Unix solution might be to use make(1) and cpp(1) here.
Not sure what environment/editor your using but one thing you can do is to use prebuild events. create a start-tag/end-tag which defines the import region, and then in the prebuild event copy the common code between the tags and then compile...
//$start-tag-common-auth
..... code here .....
//$end-tag-common-auth
In your prebuild event just find those tags, and replace them with the import code and then finish compiling.
VS supports pre-post build events which can call external processes, but do not directly interact with the environment (like batch files or scripts).
Instead of keeping the authentication code in a separate file, designate one of your existing scripts as the primary or master script. Use this one to edit/debug/work on the authentication code. Then add a build/batch process like you are talking about that copies the authentication code from the master script into all of the other scripts.
That way you can still debug and work with the master script at any time, you don't have to worry about one more file, and your build/deploy process keeps everything in sync.
You can use a technique like #Priyank Bolia suggested to make it easy to find/replace the required bit of code.
I ugly way I can think of:
have the original code in all the files, and surround it with markers like:
///To be replaced automatically by the build process to the latest code
String str = "my code copy that can be old";
///Marker end.
This code block can be replaced automatically by the build process, from one common code file.