Set sass variable value in Angular 7 - javascript

I have been working with angular for the last few weeks, and now I have a requirement to dynamically style a public site. The site admin set various color codes as well as a logo image from admin in a database. These will be reflected when the Public Site opens.
As I am from an asp.net background, previously what I would do is on master page load, take values from the DB and write them into a .less file, and let java-script library take care of it. It's simple there.
But for my current situation, I am using sass, and I am not able find a way to write variables into a .scss file.
I just learn a new thing APP_INITIALIZER from here ,but ultimately this post not showing how to write in the .scss file.
I am actually thinking this with my asp.net knowledge,but may be I am wrong ,or there are another way of implementation.
I want a simple solution ,what we do in asp.net I want to achieve this in same way.
Take variable value from DB via api,when application loading for first time.
Write values in SASS variable file .
After that SASS will take care of this and we get result as expected .
Please give some suggestion or example ,to start with .
Thanks.

As other answers explained, it is not possible to set SASS variables and process that on the client, as SASS is converted to plain CSS at build time and when app is running or in APP_INITIALIZER browser can process only CSS.
I see two options to achieve what you want.
Generally, you would have some base css for the app, and then you need to load the additional css based on admin settings. What needs to be considered from css point of view is that all css specificity in additional css should be greater than base css, because otherwise it won't override the base. That requires basic css knowledge so I won't go into details.
Method 1
Generate your additional css on server request. Load it when app is started from server URL. Reload it by js when admin change any settings.
Define backend endpoint at address /additional.css (or it could be similar to /api/theme/custom-css) which will generate css out of database. For example you have background=red in db, then the endpoint should return
body {background-color: red;}
Add <link id="additionalCss" rel="stylesheet" type="text/css" href="additional.css" /> in <head> of index.html. And that will be enough to make it work.
To reload you can use different methods, but I believe this should work
document.getElementById('additionalCss').href = document.getElementById('additionalCss').href;
This will make new request to the server, server will execute DB -> css and return the updated css, which will be applied to the browser.
And if you want to be cool (or need to support big and complex themes) scss can be used. Backend should generate scss variable definitions out of database, then should use some server-side app to compile scss -> css, and then serve compiled css back to the client. But this will be overkill if additional css is simple enough.
One important consideration of this method is browser caching, because content behind additional.css is dynamic, but browser may cache it, not call the backend and serve outdated version.
Method 2
If you don't want or can't mess with the backend. Load settings from DB by some API endpoint in json, then generate css code on the client and apply it.
Use HttpClient to get settings JSON and generate css as string out of it. For example server returns
{
"background": "red"
}
then you convert this to string as
cssCode = 'body {background-color: red}';
Use
let additionalCssStyle = document.getElementById('additionalCss');
if (! additionalCssStyle) {
additionalCssStyle = document.createElement("style");
additionalCssStyle.id = 'additionalCss';
document.head.appendChild(additionalCssStyle);
}
additionalCssStyle.innerText = cssCode;
To reload - save changed to backend, then repeat 1. and 2.

While #Cold Cerberus has suggested a good approach and is right about maintaining style related things at front-end, i am suggesting some ways for this.
As you said you want various colour combination,you can use Conditional CSS of SASS.
body[theme="theme1"] {
// theme 1 css
}
body[them="theme2"] {
// theme 2 css
}
You can use sass theme map along with conditional css.
Just update your attribute and theme will be applied automatically.
themeChange() {
const dom = document.querySelector('body');
dom.theme = theme1; // change theme here
}
If you are very particular about some element style which should be updated from back-end (like colour code) you can use ng-style along with theme approach.
<some-element [ngStyle]="{'font-style': styleExp}">...</some-element>
You have to use smart combination of above in order to fulfill your requirement.

First of all, in ASP .NET, it might be not bad to have a db hold CSS rules and other static assets. This is because it is a Server Side Rendering framework, so it kinda makes sense.
On the other hand, in Angular, it is client side (with the exception of Angular Universal, but you'll still have to expect working in similar approaches). Even with translations (i18n or custom), in Angular world, it is most likely stored on the front end (i18n .json files) and not from the back (db or so).
So you'll have to go and have your theme's stored in a certain manner you prefer and make your way to switching between them dynamically with Angular. You can of course store the keys/variables for the styles/themes but your actual CSS code is still stored on .css files.
Try to see this simple example from CSS vars in use while dynamically setting app theme (Angular). This is only just one way and there are lots of ways to do this and you might have to look for your personal preference.
UPDATE:
There might be erroneous implications of my answer above, but I'll leave it as is and just share one experience I had that is related to this topic.
I have worked on a webapp where the user can customize his theme via settings, likewise, The CSS rules aren't stored on DB, but the color values to be set on sass variables are. There was a special script where CSS scripts will be compiled (was returned on demand which made it a bit slow but a splash screen just saves your day, not AOT compiled) along with the custom values, which I don't have any idea how it was done. The same with translations, I also recently worked on a project where translations are from db, but there's a script to run for every release/deployment that generates and updates the .json files in the assets/i18n folder.

I don't think that what you want will be possible to do... Angular processes the SASS files during application build and writes all the common results into a plain old css file. The component-specific stuff will get generated as javascript that, in turn, will apply your styling at run time.
Hence all the SASS variables you need to set up have to be present at compile time.
What you can do, though, is to pre-define your setup in Angular components and then toggle it based on an input (from your DB or wherever else), like so:
// your.component.ts
#Component({
// ... component stuff
styles: ['h1.option1 {color: red;}', 'h1.option2 {color: blue;}'],
template: `
<h1 *ngIf="optionSelection$ | async as option; else noOption"
[class.option1]="option == 1"
[class.option2]="option == 2">
Hey there, I'm styled!
</h1>
<ng-template #noOption>
<h1>No option received</h1>
</ng-template>
`
})
export class YourComponent {
optionSelection$: Observable<number>;
constructor(yourService: YourService){
this.optionSelection$ = yourService.getYourOption().pipe(startWith(null));
}
}
Hope this helps a little :-)

Since sass is a pre compiled css. we cannot dynamically change the theme without generating a seperate theme.css. This is where JSS comes to play. JSS is a javascript based style inject mechanism, where css are directly injected into the files you are using it.
react-angular-material uses it extensively, where we can pass color variables dynamically to change theme of the application.
for instance this guy has made it with angular.
Docs:
jss-angular,
jss
links: jss-with-angular

It is not possible in that way but rather than using the sass variable, you use the value of the sass variable. It may be any value.
Why? because sass is compiled during packaging and in the end, it would still generate plane CSS.
An example of a framework making use of this optional style processor is angular.
In your case I would recommend looking into dynamic themeing within angular as what you require definitely needs JavaScript. Look into the guide on medium given by one of the contributors.
https://stackoverflow.com/a/54559350/3070499

Related

How to use commercial themes with meteor.js

I'm a newbie who's trying to build a meteor app, and I was looking to cut some time by using a commercial theme. Let's take this as an example:
http://themeforest.net/item/metronic-responsive-admin-dashboard-template/4021469?WT.ac=category_item&WT.seg_1=category_item&WT.z_author=keenthemes
I have two options:
1) Use the html to create meteor templates, using spacebars tags, etc.
But how would I implement the theme javascript? doesnt it comes in conflict with meteor?
2) Use angular.js, as the theme is provided in angular.js format other than plain html. But wouldnt this create conflicts? is this a better approach?
In general, what is the easiest and best way to use commercial themes with meteor?
I bought similar themes on wrapbootstrap. I think it is the same problem here. (for Angular theme I do not know, as it would be trickier I think to integrate it with bootstrap)
Generally with such themes, you have a lot of 3rd-part JS libraries. You have to get them.
First option, you find a similar packages on atmosphere and you can add it. (A lot of jQuery library are simply wrapped as packages).
Second option, there is no such package (you can make and add them, and it would help the community :)). You can import them on the page you need with a package like wait-on-lib
You can import the libraries where you need them only. But I think the first option is cleaner.
And you will probably have some custom.js for each different page you have in your template, you have to transfer this logic when you render a template. For example the custom.js for the index file in your template will be transformed in :
A template name index where you can put the HTML and
Template.index.rendered = function(){
/* your custom js */
}
For the CSS you can simply copy past the files in client/css (for example) the files will be loaded.
I do not know if I have been very clear, but I managed to integrate such themes in meteor project. And do not forget to remove unnecessary files, for example when you add the bootstrap package, you can remove the bootstrap css and js files integreted to your template.
P.S : You may have to search/remplace path in the css and js files from the templates to load some images for example. Put all such files (as images) in your public folder, where you want, but do not forget to rewrite the path in your css and js files.
For example if you bougth a template where they have folder like :
folder_css
folder_image
...
the path are written this way :
/* css files */
background-image: url(../folder_image/myimage.png);
But in a meteor project, all files in public folder are at the root of the project, so you can rewrite your path, with for example something like this :
/* css files */
background-image: url(img/myimage.png);
Rewrite path in JS files also and I think it should work.

How to make a plugin based project

I want to make a web based application that can have plugins/apps 'installed' to it. What i mean by Apps is say a weather app which has its own CSS and JS files in a container with a specific ID like id="Weather-app".
The Problems: (Assuming everything is on the same server)
Having Duplicate IDs, Class'
Conflicting script and style sheets
how to actually check a folder named 'Plugins', Find a file named Weather-app and then load the contents of 'Weather-app' into the main Application.
I have looked around on Google and haven't managed to find any information on how you would go about this. Hopefully someone on here will know. I would like to use JavaScript & JQuery if possible. I dont know if there is already a source out there for this purpose but if there is a link would be great!
1 - Avoid the use of IDs for generics, always use classes instead.
2 - Prefix the classes on HTML generated by plugins you are creating with some name space. i.e.: js-plugin-foobar-nameOfClass
You can avoid having the user add a ".js" and a ".css" file for each pluggin. You can generate css classes with javascript. That way you will only have to import one file for each pluggin: How to dynamically create CSS class in JavaScript and apply?
Take a look at the jQuery widget factory, you can build your plugins to use it, and that should facilitate your life. They also have some coding guidelines: http://jqueryui.com/widget/

Can I make a custom colour definitions that I can share between CSS, JS and HTML?

I have a blue-ish colour that I want to use in many places in my app and at the moment I am copying and pasting it between styles in my CSS. Is there a way of defining a constant like the standard colours, 'blue', 'red' etc. that I could share between my CSS, my HTML and my JS?
I'd like to be able to say (somewhere, preferably CSS)
myblue = #33CC99
in CSS say...
background-color:myblue;
in HTML say...
<td color="myblue"/>
and in JavaScript
tag.style.backgroundColor = myblue;
I'm guessing this is impossible and google turned nothing up, so has anyone got any ideas? I doubt I am the only person to come across this.
A very promising product that "compiles" higher-level expressions like variables into CSS is LESS. It needs Ruby. I haven't used it yet but it's definitely worth a look.
A more primitive way to do this would be using a server-side scripting language like PHP.
You would define constants in PHP like so:
define ("MYBLUE", "#33CC99");
and then outputting the value where needed using <?=MYBLUE;?>
Big downside: To do this in external css and js files, you would obviously have to have them parsed by the PHP interpreter, which is not good performance wise if you have a lot of visitors. For a low-traffic site, it probably doesn't matter.
Yes, this is impossible. You could, however, write your own CSS preprocessor (or use one of the existing ones out there), for instance with PHP. The big downside is that you would have to output the colorcode on your whole site with PHP and your scripts would look like
tag.style.backgroundColor = <? echo $myblue; ?>
and likewise in CSS
.someClass {
background-color: <? echo $myblue ?>
}
or something similar. And that isn't really nice either. Of course you could use any server sided script language of your choice. As far as I can judge, this is the only possibility to use a color-constant throughout a whole website.
You could have a look at some processors:
http://cssp.codeplex.com/
http://www.shauninman.com/archive/2007/06/27/css_server_side_pre_processor
http://icant.co.uk/articles/cssconstants/
You may look at HAML+SASS. Though you cannot define variables for all three languages at once, these two can make writing HTML+CSS much easier.
How I would approach this is to make a class in my CSS.
.color_class {color: #33CC99;}
Then call it in my HTML
<td class="color_class" />
You can assign multiple classes to an HTML element.
In the JS, just name the class
document.getElementById('id').className = 'color_class';
Of course you can play with how you want to select your element. A JS library probably has even easier methods for assigning CSS classes.
To achieve this with out using any dynamic CSS (e.g. serving a PHP file with content-type text/css), your best bet is to separate out the places where you define the 'theme'.
<script type="text/javascript">
var theme = '#003366';
</script>
Then you can use a JavaScript file to write out styles based on the themes.
However, if you are able to use a CSS pre-processor, go with that. You'll have much more flexibility and the code will be easier to maintain. I almost always use a PHP or JSP page for CSS.
As other users have noted you can't do this in straight HTML, JS or CSS unless you pass all HTML, JS and CSS content via a CGI/PHP/ASP script - which isn't actually a bad approach as it's easy to maintain.
If you use a query string in the reference to included CSS / JS files - e.g. '/css/stylesheet.php?timestamp=2010-01-01+00:00:00', then almost all clients will aggressively cache your CSS/JS files, negating any impact on load parsing them in a scripting language may have (though unless the site is likely to be particularly busy I wouldn't be too connected about that).
If you are using Apache (which is likely), an alternative approach would be do use something like mod_set to re-write all HTML, JS and CSS files on the fly for you. This may be more difficult to support if you are not familiar with configuring Apache (or are using another web server).
With regard to tag naming:
With either approach I strong suggest using a clear tagging system to denote your dynamic variables (e.g. %MyBlue%) and to consider having variables names be representative (e.g. %HeadingBackgroundColor%, %FontColor%, even if both are set to %MyBlue%), as that can prevent things getting hairy later on (when you discover that changing one value has intended consequences).
Using more representative names may seem unnecessarily verbose at first glance, but it causes problems in many cases because colours end up clash in unintended ways when they are significantly different from the original scheme (this is true of a lot of mainstream software which is skinnable - because the author made the assumption that %value1% and %value2% would always go together and so would %value1% and %value3% - meaning in effect the options for themeing are severely limited by an unintended dependancy).
I do this at build time by running my CSS files through Freemarker.
I am not sure of your end goal. If it is to allow selection of one of several themes for a web page, you could simply have multiple CSS files, and a cookie/session variable/database store of the user's prefered style sheet. Then you could just do
<link rel=<? echo stylepref; ?> type='text/css'>
or something along those lines
If you want to be able to completely customize the site, then one of the above answers would be needed.
There's no concept of 'variables' in CSS, but I'd strongly recommend not doing what you're doing. there's no good reason that you can't define all your style information in your CSS sheet as CSS classes. If you do that, and then just apply said classes in html and javascript, that's one major load off in terms of copying and pasting.
Second, remember that you can define more than one CSS class for an element, e.g.
<div class='blue-text white-background'>my content</div>
You can then define those independantly in CSS, a la:
.blue-text { color : Blue; }
.white-background { background-color: white;}
and you can even create rules that only take effect when both are applyed:
.blue-text.white-background { color : AliceBlue; }
If you want to have the color choices dynamically generated, the only real way to do that is as others have suggested, which is either preprocess your files before deployment, or have the CSS dynamically generated and served by your language of choice.
In pure client side CSS grouping selectors allows you to put the same color on many different elements:
p, .red, #sub, div a:link { color: #f00; }

Add ASP.NET server script to mostly-static .JS / .CSS files without losing IntelliSense?

Using VS2008 and ASP.NET 3.5 (or VS 2010 / .NET 4.0?), how can I include a bit of dynamic ASP.NET server-side code in mostly-static JavaScript and CSS files?
I want to do this to avoid cloning entire JS or CSS files to vary just a small part of them multi-tenant sites. Later, I want to extend the solution to handle localization inside javascript/CSS, dynamic debugging/tracing support, and other cool things you can get by injecting stuff dynamically into JavaScript and CSS.
The hard part is that I don't want to lose all the cool things you get with static files, for example:
JS/CSS code coloring and intellisense
CSS-class "go to definition" support in the IDE
automatic HTTP caching headers based on date of underlying file
automatic compression by IIS
The server-side goodness of static files (e.g. headers/compression) can be faked via an HttpHandler, but retaining IDE goodness (intellisense/coloring/etc) has me stumped.
An ideal solution would meet the following requirements:
VS IDE provides JS/CSS intellisense and code coloring. Giving up server-code intellisense is OK since server code is usually simple in these files.
"go to defintion" still works for CSS classes (just like in static CSS files)
send HTTP caching headers, varying by modified date of the underlying file.
support HTTP compression like other static files
support <%= %> and <script runat=server> code blocks
URL paths (at least the ones that HTTP clients see) end with .JS or .CSS (not .ASPX). Optionally, I can use querystring or PathInfo to parameterize (e.g. choosing a locale), although in most cases I'll use vdirs for this. Caching should vary for different querystrings.
So far the best (hacky) solution I've come up with is this:
Switch the underlying CSS or JS files to be .ASPX files (e.g. foo.css.aspx or foo.js.aspx). Embed the underlying static content in a STYLE element (for CSS) or a SCRIPT element (for JS). This enables JS/CSS intellisense as well as allowing inline or runat=server code blocks.
Write an HttpHandler which:
looks at the URL and adds .aspx to know the right underlying ASPX to call
uses System.Net.HttpWebRequest to call that URL
strips out the containing STYLE or SCRIPT tags, leaving only the CSS or JS
adds the appropriate headers (caching, content type, etc.)
compresses the response if the client suports compression
Map *.CSS and *.JS to my handler.
(if IIS6) Ensure .JS and .CSS file extensions are mapped to ASP.NET
I'm already using a modified version of Darick_c's HttpCompression Module which handles almost all of above for me, so modifying it to support the solution above won't be too hard.
But my solution is hacky. I was wondering if anyone has a more lightweight approach for this problem which doesn't lose Visual Studio's static-file goodness.
I know I can also hack up a client-side-only solution where I split all JS and CSS into "vary" and "won't vary" files, but there's a performance and maintenance overhead to this kind of solution that I'd like to avoid. I really want a server-side solution here so I can maintain one file on the server, not N+1 files.
I've not tried VS10/.NET 4.0 yet, but I'm open to a Dev10/.net4 solution if that's the best way to make this scenario work.
Thanks!
I have handled a similar problem by having a master page output a dynamic generated JSON object in the footer of each page.
I needed to have my js popup login dialog box support localization. So using JSON.NET for serialization, I created a public key/value collection property of the master page that pages could access in order place key/values into such as phrase key/localized phrase pairs. The master page then renders a dynamic JSON object that holds these values so that static js files could reference these dynamic values.
For the js login box I have the masterpage set the localized values. This made sense because the masterpage also includes the login.js file.
I do commend you on your concern over the number of http requests being made from the client and the payload being returned. Too many people I know and work with overlook those easy optimizations. However, any time I run into the same issue you're having (which is actually quite often), I have found I've usually either taken a wrong turn somewhere or am trying to solve the problem the wrong way.
As far as your JS question goes, I think Frank Schwieterman in the comments above is correct. I'd be looking at ways to expose the dynamic parts of your JS through setters. A really basic example would be if you have want to display a customized welcome message to users on login. In your JS file, you can have a setMessage(message) method exposed. That method would then be called by the page including the script. As a result, you'd have something like:
<body onLoad="setMessage('Welcome' + <%= user.FirstName %>);">
This can obviously be expanded by passing objects or methods into the static JS file to allow you the functionality you desire.
In response to the CSS question, I think you can gain a lot from the approach Shawn Steward from the comments makes a good point. You can define certain static parts of your CSS in the base file and then redefine the parts you want to change in other files. As a result, you can then dictate the look of your website by which files you're including. Also, since you don't want to take the hit for extra http requests (keep in mind, if you set those files to be cached for a week, month, etc. it's a one time request), you can do something like combining the CSS files into a single file at compilation or runtime.
Something like the following links may be helpful in pointing you in the right direction:
http://geekswithblogs.net/rashid/archive/2007/07/25/Combine-Multiple-JavaScript-and-CSS-Files-and-Remove-Overheads.aspx
http://www.asp.net/learn/3.5-SP1/video-296.aspx?wwwaspnetrdirset=1
http://dimebrain.com/2008/04/resourceful-asp.html
By utilizing the combining at run or compile time you can gain the best of both world by allowing you to logically separate CSS and JS files, yet also gaining the reduction of payload and requests that comes with compressing and combining files.

Put javascript in one .js file or break it out into multiple .js files?

My web application uses jQuery and some jQuery plugins (e.g. validation, autocomplete). I was wondering if I should stick them into one .js file so that it could be cached more easily, or break them out into separate files and only include the ones I need for a given page.
I should also mention that my concern is not only the time it takes to download the .js files but also how much the page slows down based on the contents of the .js file loaded. For example, adding the autocomplete plugin tends to slow down the response time by 100ms or so from my basic testing even when cached. My guess is that it has to scan through the elements in the DOM which causes this delay.
I think it depends how often they change. Let's take this example:
JQuery: change once a year
3rd party plugins: change every 6 months
your custom code: change every week
If your custom code represents only 10% of the total code, you don't want the users to download the other 90% every week. You would split in at least 2 js: the JQuery + plugins, and your custom code. Now, if your custom code represents 90% of the full size, it makes more sense to put everything in one file.
When choosing how to combine JS files (and same for CSS), I balance:
relative size of the file
number of updates expected
Common but relevant answer:
It depends on the project.
If you have a fairly limited website where most of the functionality is re-used across multiple sections of the site, it makes sense to put all your script into one file.
In several large web projects I've worked on, however, it has made more sense to put the common site-wide functionality into a single file and put the more section-specific functionality into their own files. (We're talking large script files here, for the behavior of several distinct web apps, all served under the same domain.)
The benefit to splitting up the script into separate files, is that you don't have to serve users unnecessary content and bandwidth that they aren't using. (For example, if they never visit "App A" on the website, they will never need the 100K of script for the "App A" section. But they would need the common site-wide functionality.)
The benefit to keeping the script under one file is simplicity. Fewer hits on the server. Fewer downloads for the user.
As usual, though, YMMV. There's no hard-and-fast rule. Do what makes most sense for your users based on their usage, and based on your project's structure.
If people are going to visit more than one page in your site, it's probably best to put them all in one file so they can be cached. They'll take one hit up front, but that'll be it for the whole time they spend on your site.
At the end of the day it's up to you.
However, the less information that each web page contains, the quicker it will be downloaded by the end-viewer.
If you only include the js files required for each page, it seems more likely that your web site will be more efficient and streamlined
If the files are needed in every page, put them in a single file. This will reduce the number of HTTP request and will improve the response time (for lots of visits).
See Yahoo best practice for other tips
I would pretty much concur with what bigmattyh said, it does depend.
As a general rule, I try to aggregate the script files as much as possible, but if you have some scripts that are only used on a few areas of the site, especially ones that perform large DOM traversals on load, it would make sense to leave those in separate file(s).
e.g. if you only use validation on your contact page, why load it on your home page?
As an aside, you can sometimes sneak these files into interstitial pages, where not much else is going on, so when a user lands on an otherwise quite heavy page that needs it, it should already be cached - use with caution - but can be a handy trick when you have someone benchmarking you.
So, as few script files as possible, within reason.
If you are sending a 100K monolith, but only using 20K of it for 80% of the pages, consider splitting it up.
It depends pretty heavily on the way that users interact with your site.
Some questions for you to consider:
How important is it that your first page load be very fast?
Do users typically spend most of their time in distinct sections of the site with subsets of functionality?
Do you need all of the scripts ready the moment that the page is ready, or can you load some in after the page is loaded by inserting <script> elements into the page?
Having a good idea of how users use your site, and what you want to optimize for is a good idea if you're really looking to push for performance.
However, my default method is to just concatenate and minify all of my javascript into one file. jQuery and jQuery.ui are small and have very low overhead. If the plugins you're using are having a 100ms effect on page load time, then something might be wrong.
A few things to check:
Is gzipping enabled on your HTTP server?
Are you generating static files with unique names as part of your deployment?
Are you serving static files with never ending cache expirations?
Are you including your CSS at the top of your page, and your scripts at the bottom?
Is there a better (smaller, faster) jQuery plugin that does the same thing?
I've basically gotten to the point where I reduce an entire web application to 3 files.
vendor.js
app.js
app.css
Vendor is neat, because it has all the styles in it too. I.e. I convert all my vendor CSS into minified css then I convert that to javascript and I include it in the vendor.js file. That's after it's been sass transformed too.
Because my vendor stuff does not update often, once in production it's pretty rare. When it does update I just rename it to something like vendor_1.0.0.js.
Also there are minified versions of those files. In dev I load the unminified versions and in production I load the minified versions.
I use gulp to handle doing all of this. The main plugins that make this possible are....
gulp-include
gulp-css2js
gulp-concat
gulp-csso
gulp-html-to-js
gulp-mode
gulp-rename
gulp-uglify
node-sass-tilde-importer
Now this also includes my images because I use sass and I have a sass function that will compile images into data-urls in my css sheet.
function sassFunctions(options) {
options = options || {};
options.base = options.base || process.cwd();
var fs = require('fs');
var path = require('path');
var types = require('node-sass').types;
var funcs = {};
funcs['inline-image($file)'] = function (file, done) {
var file = path.resolve(options.base, file.getValue());
var ext = file.split('.').pop();
fs.readFile(file, function (err, data) {
if (err) return done(err);
data = new Buffer(data);
data = data.toString('base64');
data = 'url(data:image/' + ext + ';base64,' + data + ')';
data = types.String(data);
done(data);
});
};
return funcs;
}
So my app.css will have all of my applications images in the css and I can add the image's to any chunk of styles I want. Typically i create classes for the images that are unique and I'll just take stuff with that class if I want it to have that image. I avoid using Image tags completely.
Additionally, use html to js plugin I compile all of my html to the js file into a template object hashed by the path to the html files, i.e. 'html\templates\header.html' and then using something like knockout I can data-bind that html to an element, or multiple elements.
The end result is I can end up with an entire web application that spins up off one "index.html" that doesn't have anything in it but this:
<html>
<head>
<script src="dst\vendor.js"></script>
<script src="dst\app.css"></script>
<script src="dst\app.js"></script>
</head>
<body id="body">
<xyz-app params="//xyz.com/api/v1"></xyz-app>
<script>
ko.applyBindings(document.getTagById("body"));
</script>
</body>
</html>
This will kick off my component "xyz-app" which is the entire application, and it doesn't have any server side events. It's not running on PHP, DotNet Core MVC, MVC in general or any of that stuff. It's just basic html managed with a build system like Gulp and everything it needs data wise is all rest apis.
Authentication -> Rest Api
Products -> Rest Api
Search -> Google Compute Engine (python apis built to index content coming back from rest apis).
So I never have any html coming back from a server (just static files, which are crazy fast). And there are only 3 files to cache other than index.html itself. Webservers support default documents (index.html) so you'll just see "blah.com" in the url and any query strings or hash fragments used to maintain state (routing etc for bookmarking urls).
Crazy quick, all pending on the JS engine running it.
Search optimization is trickier. It's just a different way of thinking about things. I.e. you have google crawl your apis, not your physical website and you tell google how to get to your website on each result.
So say you have a product page for ABC Thing with a product ID of 129. Google will crawl your products api to walk through all of your products and index them. In there you're api returns a url in the result that tells google how to get to that product on a website. I.e. "http://blah#products/129".
So when users search for "ABC thing" they see the listing and clicking on it takes them to "http://blah#products/129".
I think search engines need to start getting smart like this, it's the future imo.
I love building websites like this because it get's rid of all the back end complexity. You don't need RAZOR, or PHP, or Java, or ASPX web forms, or w/e you get rid of those entire stacks.... All you need is a way to write rest apis (WebApi2, Java Spring, or w/e etc etc).
This separates web design into UI Engineering, Backend Engineering, and Design and creates a clean separation between them. You can have a UX team building the entire application and an Architecture team doing all the rest api work, no need for full stack devs this way.
Security isn't a concern either, because you can pass credentials on ajax requests and if your stuff is all on the same domain you can just make your authentication cookie on the root domain and presto (automatic, seamless SSO with all your rest apis).
Not to mention how much simpler server farm setup is. Load balance needs are a lot less. Traffic capabilities a lot higher. It's way easier to cluster rest api servers on a load balancer than entire websites.
Just setup 1 nginx reverse proxy server to serve up your index .html and also direct api requests to one of 4 rest api servers.
Api Server 1
Api Server 2
Api Server 3
Api Server 4
And your sql boxes (replicated) just get load balanced from the 4 rest api servers (all using SSD's if possible)
Sql Box 1
Sql Box 2
All of your servers can be on internal network with no public ips and just make the reverse proxy server public with all requests coming in to it.
You can load balance reverse proxy servers on round robin DNS.
This means you only need 1 SSL cert to since it's one public domain.
If you're using Google Compute Engine for search and seo, that's out in the cloud so nothing to worry about there, just $.
If you like the code in separate files for development you can always write a quick script to concatenate them into a single file before minification.
One big file is better for reducing HTTP requests as other posters have indicated.
I also think you should go the one-file route, as the others have suggested. However, to your point on plugins eating up cycles by merely being included in your large js file:
Before you execute an expensive operation, use some checks to make sure you're even on a page that needs the operations. Perhaps you can detect the presence (or absence) of a dom node before you run the autocomplete plugin, and only initialize the plugin when necessary. There's no need to waste the overhead of dom traversal on pages or sections that will never need certain functionality.
A simple conditional before an expensive code chunk will give you the benefits of both the approaches you are deciding on.
I tried breaking my JS in multiple files and ran into a problem. I had a login form, the code for which (AJAX submission, etc) I put in its own file. When the login was successful, the AJAX callback then called functions to display other page elements. Since these elements were not part of the login process I put their JS code in a separate file. The problem is that JS in one file can't call functions in a second file unless the second file is loaded first (see Stack Overflow Q. 25962958) and so, in my case, the called functions couldn't display the other page elements. There are ways around this loading sequence problem (see Stack Overflow Q. 8996852) but I found it simpler put all the code in one larger file and clearly separate and comment sections of code that would fall into the same functional group e.g. keep the login code separate and clearly commented as the login code.

Categories