Meteor import LESS files per layout - meteor

I've got a meteor project with a few different blaze layout templates and I'd like for them to each have their own LESS stylesheets. How do I import them on a per-layout basis, i.e. not importing them all in the main.less file?

The easiest approach is to literally import them from your template js files like so:
// File layout.html
<template name="layout">
<div class="layout-wrapper">
</div>
</template>
// File layout.less
.layout-wrapper {
display: flex;
justify-content: center;
}
// File layout.js
import './layout.html';
import './layout.less';
Template.layout.onCreated(function () {
// etc...
});
Now when you load the template's layout.js file, either by eager loading, imports, or dynamic imports, it will insert the compiled less to the page.

The problem is that in production, Meteor concatenates all the CSS into one big file, so you can't attach a specific file only to one template.
I got around this by basically defining an automatic wrapper div like so:
In your router, define a default layout e.g. in ironRouter:
Router.configure({
layoutTemplate: 'mainLayout',
});
In your mainLayout template, create a wrapping div something like this:
<div class="custom-page-wrapper-{{currentRouteName}}">
{{> yield}}
</div>
Define a global currentRouteName helper like this:
UI.registerHelper("currentRouteName",function(){
return Router.current() ? Router.current().route.getName() : "";
});
With that, every template that uses this layout template will automatically be wrapped in a div with a custom-page-wrapper-XXXX class that is unique to each template and based on the route's name (which is guaranteed to be unique or else ironRouter will raise an error).
After that, you can specify any template-specific styling within that class in any LESS file you want.
Although this isn't exactly the same as specifying a different file for each template, it functionally accomplishes the same thing with the only expense being an extra wrapper div.

Related

How to import styles from css files into an .ejs template and send it over email?

What i want to do:
Send one email with styles;
Have separate files, one for my .ejs template and one .css for styles that correspond to that template.
What the problem is:
If i create separate routes for the styles and insert it into the HTML, the user will need to "authorize" the download of these styles;
If i just import like normal HTML, it will not go through the email.
What am i using:
Express.js
Typescript
EJS
nodemailer
What is my file structure like at the moment:
src
views
index.ejs
style.css
internal_view_group
style.css
internal_template_name
style.css
locale
pt-br.ejs
en-us.ejs
public_view_group
style.css
public_template_name
style.css
locale
pt-br.ejs
en-us.ejs
Ok, if the directory is a little messy or hard to understand, let me break it down for you:
Folder "views" contains all my templates and styles, it also contains my index.ejs, that's what i'll call for when rendering the HTML, this index will then call styles from the group, template and then call the HTML from template, considering the language it uses. It also has a style.css, a global stylesheet that must be used in all templates, regardless of it's group.
Folder "internal_view_group" is a group of templates, for example, we have an internal group, templates used for internal communication, and a public group, used for the general public communication. It also has a default style.css, that is applied to every template inside this group.
Folder "internal_template_name" is a template, it has it's locales inside "locales" folder and a stylesheet that must be applied onto the called locale.
How can i have this level of organization on my code, having separate files and still work, considering the section "The problem is"?
Since you use your index.ejs to call all other templates and styles, you can also directly inject the styles into this index.ejs using the <%- %> tag from EJS.
What this tag does: import a file (usually an .EJS), read it's content and output it unscaped to the HTML.
so what you want to do into the index.js is something similar to this:
<head>
<%-
'<style>'
+ include(`./style.css`)
+ include(`./${template_group}/style.css`)
+ include(`./${template_group}/${template_name}/style.css`)
+ '</style>'
%>
</head>
<body>
<%- include(`./${template_group}/${template_name}/locale/${locale}.ejs`) %>
</body>
This will output all style RAW contents into the code (not a minified version).
The reason for the style tag being inside strings is that VSCode may report an error in your code because of EJS tags inside style sections, with this, only the < at the start of <style> will be reported as "wrong", but with nothing at output terminal telling you.
If you find that the final size of HTML code that you want to send is too large and may become a problem, you can use javascript prototype.String functions after the include, like include('./style.css').replaceAll(' ', ''), to replace all spaces but leave line breaks (not tested)

Aurelia, scoped css

I am very new to Aurelia, and new web development in general (nodejs, gulp, and so on).
Thanks to the Aurelia CLI it was easy for me to setup a nice Aurelia project for Visual Studio Code using Typescript + SASS.
I thought it would be a good idea (but please tell me if it is not a good idea :) to use scoped css. There is already much information about this subject, but it is hard to find something that I can actually use. So I thought I would do it myself in the following way:
I have general stylesheets that can be imported "anywhere". Nothing new needs to be done to do this.
There will be component specific stylesheets that match the
component name + ".scss". So e.g. if there is a view + model like:
component.ts, component.html, there can be a component.scss which will contain styling that is specific for component.ts and component.html and thus should be scoped to this component.
I've tried to use style scoped html tags but this is not widely supported by browsers (and seems to be dropped from the spec?) and I've tried something (I forgot what I've tried exactly) as described on
https://github.com/bryanrsmith/aurelia-binding-loader
with:
<template>
<require from="styles.css!module!bind" as="styles"></require>
<div class.one-time="styles.first">First</div>
<div class.one-time="styles.second">Second</div>
</template>
which was very slow.
My knowledge about all this is very limited and I think it does a conversion from CSS to a JS object, after which the class of a tag are bound to the style in the JS object.
I thought it would make sense to to this conversion to JS at build time. So with my very limited gulp knowledge I changed process-css.ts in the following way:
import * as gulp from 'gulp';
import * as sourcemaps from 'gulp-sourcemaps';
import * as sass from 'gulp-sass';
import * as project from '../aurelia.json';
import { build } from 'aurelia-cli';
import * as path from "path";
import * as fs from "fs";
import * as rename from "gulp-rename";
import * as postcssmodules from "postcss-modules";
import * as postcss from "postcss"
import * as postcssJs from "postcss-js"
import * as tap from "gulp-tap";
export default function processCSS() {
return gulp.src(project.cssProcessor.source)
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(tap(handleCss))
.pipe(build.bundle())
};
function handleCss(cssFile, t) {
// get the path of the html file
var baseFilename = path.basename(cssFile.path, '.css');
var baseFilepath = path.join(path.dirname(cssFile.path), baseFilename);
var htmlFilepath = baseFilepath + '.html';
// check if the html file exists
if (fs.existsSync(htmlFilepath)) {
var root = postcss.parse(cssFile.contents.toString());
var cssAsJson = postcssJs.objectify(root);
var s = JSON.stringify(cssAsJson);
cssFile.contents = Buffer.from(s);
}
}
(adding handleCss).
This is not yet finished. The new object with the style has to be added to the bundle under the same name but WITH an extension ".js". How can I do this in a nice way?
It would be nice if this would work, but still it would be limited to scoped css classes, not css elements.
Another possibility I thought about is, maybe the component.scss styling can be inserted into the component.html (e.g. setting style properties of elements) during build time? If so, how could/should this be done? And are there any drawbacks from doing this?
Sorry if there are "dumb" questions in this post, basically this is all very new and it is difficult to find where to begin.
Thanks!
If you're using Aurelia with Webpack, you can use the ConventionDependenciesPlugin so that css/scss files are automatically included just like js and html. Once configured, you no longer need to require the stylesheets. Do note that you may have to restart Webpack watch if you add css/scss file after the html and js files, because ConventionDependenciesPlugin sometimes does not pick up the dependent file.

I would like to add partials in meteor.js

Using a dir structure:
clients
main.css
main.html
main.js
server
main.js
imports
ui
partials
header
header.css
header.html
header.js
header.collection.js
body
body.css
body.html
body.js
body.collection.js
footer
footer.css
footer.html
footer.js
footer.collection.js
in the client/main.html (via main.js)
I would like to create something like: (simplified)
{{headercontent}}
{{bodycontent}}
{{footercontent}}
What is the import structure to add these partials in main.js?
Thanks all
You can create these partials by creating different templates for each of them.
I will give a short example. Let's say we want to create a page(finalTemplate) with four component- 1)header,2 )footer, 3)Sidebar and 4) Content.
The structure you have made is good for these. You just need to be careful with importing the required files while writing the codes.
Just as a caution, the collections has to be imported in both server and client startup.
To include the four components in the fial you just need to include those templates.
so my final page will look like
<template name="finalTemplate">
{{> header}} //Templates are imported by {{> TemplateName}} Not by {{TemplateName}}
{{> sidebar}}
{{> content}}
{{> footer}}
</template>
Example import structure for the example you asked for:
header.js
import './header.html'
import './header.css'
import '.header.collections.js'
In startup function for server, you should import all collections files as they are needed on server side.

In meteor js, how can I make sure a CSS file will override anithing else for a specific template?

I read posts about meteor file loading order.
But if I wish to make sure a CSS snippet will override any other CSS (loaded later for another template) How can I make sure the CSS snippet has final word for a template?
(put it in a top folder non lib would anyway load it before the following templates. And using another template, the problem will be the same from the POV of that other template)
Some people suggest, and I like it, to have a CSS file for each template, so we know what CSS is used for that template and we do not build a big large CSS, even if, meteor consolidate them.
I like the convention of adding a unique class name to each template. Here's an example:
<template name="posts">
<div class="__posts">
{{#each posts}}
<p>{{text}}</P>
{{/each}}
</div>
</template>
Then in your css you can specifically target instances of the posts template like this:
.__posts p {
color: blue;
}
You don't, of course, have to use the double-underscore but I find that makes a convenient indicator that the class is unique to a template. Also note this technique solves another common problem: how to identify which template rendered which portion of the current DOM.

Why html file must go before js file when addFiles in Meteor

I'm creating a meteor package, very simple one like this
api.addFiles(['errors.js', 'errors_list.html', 'errors_list.js'], 'client');
I noticed that if I change above code to
api.addFiles(['errors.js', 'errors_list.js', 'errors_list.html'], 'client');
Meteor says: Template is not defined.
It is very hard to find out what caused this error. And why js file cannot go before html file in addFiles?
When you use Spacebars (the default templating engine), templates are defined in HTML files :
<template name="fooTemplate">
...
</template>
You can then access this template from everywhere else, be it HTML or JS:
<!-- HTML file -->
{{> fooTemplate}}
//JS file
Template.fooTemplate
If you try to do such an access before the template has been created, it will fail.
Meteor packages load files sequentially. This is how you control the load order.
If you try to use a template before it has been defined, it's undefined and will throw an exception when you try to access it (something along the lines of fooTemplate is undefined).
Thus, as in everything in programming, always initialize first and use later.
Put your HTML files before the JS, and you're good to go.

Resources