require.js - runtime dynamic variables to build path - node.js

Is it possible to inject runtime information in to a require.js "data main" script and use to build paths? More explanation...
In my node.js app.js I dynamically find the path to the configured 'theme' like this:
var themePath = require('./conf/config.js').config.theme.full_path;
and later in the require.js data main script, I'd like to prepend this theme path when defining paths. So assuming I've set my requirejs data-main="xxx" and the following is the xxx file, I'd like to do something like the following:
require.config({
baseUrl: "/js/",
paths: {
"templates" : DYNAMIC_THEME_PATH + '/templates',
"views" : DYNAMIC_THEME_PATH + '/views'
}
});
I'm not sure 1. how I can "see" the themePath from within this require.js data main file, and 2. is this even possible?
EDIT - My solution
So the real challenge I was having was getting a runtime variable discovered on the server in to the require.js data main script. In node land, global doesn't correspond to the window on the client side (of course) because the javascript isn't in to the browser yet .. duh. So I don't see how you can get this discoverable in the client side script.
Ok, so what I WAS able to do was inject the discovered theme path in the ejs, then, dynamically load the data main script with that prepended like:
<script data-main="<%= theme_path %>/main" src="../js/libs/require-jquery.js"></script>
Of course this means I have to have the data main script in the theme directory which wasn't my initial plan; however, it does have the advantage that I can then use relative paths to load my path/to/templates path/to/views, etc. etc.
Lastly, I sort of hate when folks answer they're own questions .. so I'm going to leave this up in hopes that someone can either give me a better recommendation or better explain this and they can get the credit ;)

Related

Suave with netcoreapp2.0

I've been following this Suave tutorial:
https://legacy.gitbook.com/book/theimowski/suave-music-store/details
And in general this looks good. However, I was trying to make it work with Linux and for some reason I was unable to compile it with code when TargetFramework was set to "net461" (Target Framework not found), so I tried changing it to "netcoreapp2.0". It compiled, but I hit a problem later on:
https://theimowski.gitbooks.io/suave-music-store/content/en/css.html
At the end it says to add a WebPart:
pathRegex "(.*)\.(css|png)" >=> Files.browseHome
which fails for me. All compiles, but I get
This page isn’t working
localhost didn’t send any data.
I took a look at Suave's source code and it turned out that "Files.browseHome" searches for a file under "ctx.runtime.homeDirectory".
I noticed that this is set on my machine to:
/home/<my_user_name>/.nuget/packages/suave/2.2.1/lib/netstandard1.6
and obviously, that's not my project directory, so no wonder it couldn't find the file.
My question here is: what shall I do in order to make my Suave app handle my css/png files correctly using Files.browseHome ?
EDIT:
Just found out that replacing the WebPart with:
pathRegex "(.*)\.(css|png)" >=> Files.browse "/home/<my_username>/<path_to_my_project>/bin/Debug/netcoreapp2.0/"
works fine, but it looks ugly. Any idea how to make it better ? Basically I don't want to be forced to hardcode the absolute path anywhere.
I think the answer is to be found in https://suave.io/files.html, which suggests creating a config as follows:
let config =
{ defaultConfig with homeFolder = Some (Path.GetFullPath "./public") }
The path returned by Path.GetFullPath will depend on the current working directory that your app sees when it's started (which will, in turn, depend on how you start the app: from the command line, from a systemd unit file, etc.) There are too many possible variables here for me to be able to give you exact instructions, but if your startup method can cd into an appropriate folder before starting your Suave server, then that should solve your problem.
If you run into difficulties with getting the current working directory set correctly, then you could just hardcode the full path in the config:
let config =
{ defaultConfig with homeFolder = Some "/home/<your_username>/<path_to_your_project>/bin/Debug/netcoreapp2.0/" }
But that's kind of ugly, and not really portable (you'd have to modify that path again once you deploy the app). So I'd recommend the approach of making sure your start script does a cd to the right location, then using Path.GetFullPath with a relative path. Alternately, you could have a config file that gets read in at app startup where you specify the home path, or pass it in as an environment variable... All kinds of possibilities. Just make sure that your code can be handed some information on startup that specifies the correct "home" folder, and then put that in your Suave config as I've shown, and that should solve it.

Use node `fs` module on webpack compile

A bit about what I'm trying to achieve.
I'm building dev library that shows the list of files. And I want to set file color depending on when file was changed.
So, as a result of generation, I want an array like this:
[
{
lastChange: '2009-06-29T11:11:55Z',
fileContents: {name: 'VmSome'},
},
// ...
]
This is meant to work in browser environment. Meaning all file related information should be included into bundle.
Current progress
At the moment I'm not quite sure whether that's even possible.
I'm getting a list of files via webpack require.context:
require.context('./tree', true, /.js$/)
This gives me access to file content and path. But not to anything else.
Thanks for your attention.
I would first try modifying webpack-file-list-plugin. As of now, it creates a JSON that gives all files packed, their name and some more info... You could definitely add your code to fetch more information to the JSON.
https://github.com/object88/webpack-file-list-plugin/blob/master/src/index.js

Insert all javascript files from a dir as scripts in Jade programmatically

I have a Jade file index.jade and I have a dir public\js that contains a few js script files.
views
index.jade
public
js
a.js
b.js
...
Is there a way to automatically and programmatically include them all as scripts in the index.jade?
script(src='/js/a.js')
script(src='/js/b.js')
...
Yes, you can do that. Before we get into the solution let's talk about why it's better to NOT do it.
Jade/pug compiles all of the templates into an in-memory JavaScript function so when your users request a page it's very fast as there's no disk access required. Disk access is usually the slowest part of a web request, and it's why there are so many caching and CDN solutions out there. When you read the file system for these files every request in to that page will be scanning the disk multiple times, first to read the directory then to insert the files to the output.
Will these script files really be changing so often that you need to incur this disk access on every request? If you have so many script files that it's inconvenient to add them individually then you could probably group the script tags into a single template and use inheritance or mixins to help you.
With that, said if you still really want to do it this way here's how to do it...
You need to read the files in your route and pass the array to the template:
var fs = require('fs');
fs.readdir(path, function(err, files) {
// you should use a loop with a regex like ([^\/]+$) here to strip out the directory names
// this will be specific to your server's file system setup
res.render('<viewname>', scripts);
}
Then in the template:
each script in scripts
script(src= script)

grunt concat js / css

I have created a web site using backbone + requirejs + bootstrap on client side and php REST on server side. The site contains a lot of .js file. I use requirejs to load the .js when it is needed (to implement asynchronous loading).
However, I have start using Node.js + Yeoman + grunt + bower recently. I use Yeoman webapp generator to create the basic structure of my web again. When I build my web, it concat all the .js files into 1 single .js file and put the tag on the index.html to refer it.
From my understand the pros is that the whole .js is cached in client's browser. which is slow at first time visit, but fast on re-visit. Since everything is concat to 1 file and it is loaded to the client's browser, so I guess the asynchronous loading is not work in this case. (correct me if I wrong).
* the web site is created for both mobile and desktop. (1 src for 2 version)
Should I concat all .js files in 1 single file
OR should I use requirejs to require the .js when I need it (Asynchronous loading)?
How to config requirejs in Node. I have tried it in normal way (include the data-main in index.html, when I compile using grunt build. it give me error "... is no more support".
Is browserify similar to requirejs in Node?
I have spent a week to figure it out already but still no luck. Hope someone can point me to the right direction. Thanks a lot.
The .js file structure is something like this:
-app
-vendor
-jquery.js
-backbone.js
-assets
-js
-model
-person.js
-collection
-people.js
-router.js
-controller.js
-dist
-js
-build.js
i had familiar issues. So lets start with strategy of file concatenation. There are three major ways to follow:
first - always concat all modules in one file, in this case you loose on first start and may win or next starts, but you can face another issue - you use less then half of modules from concatenated file at a time, but always load all modules.
second way is to build specific concatenated file with specific module set for each type of page - so you know how many page type you have and build file for each - following this you can decrease size of file, but its hardly to maintain and need manual sets correction in case of page changes.
third - build 1 concatenated file with libs and modules which in use nearly on all pages, all other stuff (additional modules, views, special models and collection) load on demand. This way is good in case of SPA pages.
Let me say a few words about grunt + r.js configauration.
Keep this link for first times .
Here is the sample of config:
requirejs: {
compile: {
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js",
name: "path/to/almond",
out: "path/to/optimized.js"
}
}
}
Main point here mainConfigFile - it is a file then you keep require.config
Next step - configure r.js - keep this link its very helpfull as describe all possibilities of r.js.
Usually its quite enough to checkout these links.
Also you can checkout recommend file structure for multi page site to avoid issues in future.
Also here is a link to a similar post - you may find it usefull.
If you have any additional questions let me know.
And a few words about CSS - logic nearlly the same : you can build separate file for each page or create sinngle. The main point here is how large your site is. In my case i've choose second option, but to be honest first one is more scalable, especially in large projects
I can get the requirejs work with Backbone now. However, I cannot use Marionette with error something like "Backbone is undefined". I've install Marionette with this command "bower install marionette --save". I did some search on google, and someone said use the AMD version of Marionette should fix this issue and after replace Marionette with AMD version it is work.
But my question is how can I install the AMD version of Marionette using "bower install"?
My web use bootstrap. When I compile the web with "grunt build". it copy bootstrap's font from "app/bower_components/bootstrap/dist/fonts" to "dist/bower_components/bootstrap/dist/fonts" but the web is refer the font on "dist/fonts". How can I change it to refer to the right directory?
I use yo webapp (with bootstrap) to generate the structure of my web.

NodeJS: Jade, Coffee, Scss assets rendered without writing to disk

I'm looking for some middleware modules that allow me to render ".css" from ".scss", ".html" from ".jade", ".js" from ".coffee" on the fly without rendering to disk.
Every module I've encountered so far wants to write to disk before serving it instead of just streaming it.
Obviously this is only for local development since I'm not interested in dealing with file-revving and caching problems.
Answering my own question here:
The middleware to use is compile-middleware. Works fine by default with connect, but with express I had to modify it in order to not write headers (ugly i know, but time waits for no one) : https://github.com/airtonix/compile-middleware
implementation:
https://gist.github.com/airtonix/9601224
Original Credit goes to (You should try using this one first):
https://github.com/shinohane/compile-middleware
You should simply use a JavaScript task runner like:
Grunt: http://gruntjs.com/ or
Gulp: http://gulpjs.com/
These plugins could help you get started (gulp related):
https://www.npmjs.org/package/gulp-watch
https://www.npmjs.org/package/gulp-jade
https://www.npmjs.org/package/gulp-coffee
https://www.npmjs.org/package/gulp-sass
Here's a simple tutorial: http://www.codersgrid.com/2014/01/11/gulp-js-streaming-build-tool-beats-grunt-js/
I got nothing against grunt, both of them are awesome :)
Hope it helps!

Resources