How to handle CSS with meteor? - css

I am building a test app to learn how to organize multiple files with METEOR.
I have a head.html and inside I have the following link to my custom CSS:
<!-- Custom CSS -->
<link type="text/css" rel="stylesheet" href="/stylesheets/globals/style.css"/>
Very normal, Yet I have trouble to make that working.
Here is my app directory:
-app folder
---client
-----head.html
-----index.html
-----stylesheets
-------globals
---------style.css
I know it seems to be a very basic question but I can not figure it out.

Basically you have 2 ways of inserting CSS in a Meteor project :
Using the Meteor build tool to automatically concatenate and minify all your CSS files living in the client/ directory : in this case you don't need to import your stylesheets using a link tag in the head. This is perfect for vital CSS files that your app should load when started.
Example : put your CSS file under client/stylesheets/globals/style.css and that's it, no need to import it, it's automatically injected in your project by Meteor.
Using the classic way of importing stylesheets in a web application : you can put your CSS files inside the public/ directory and they will be served by your app server. In this case the Meteor build process will be skipped so files won't be concatenated together nor minified. Use this method when you want to lazy load big CSS files only needed in a subpart of your app (for example admin section styling).
Example : put your minified CSS file under public/stylesheets/admin/style.css, and use something like iron:router to load the CSS file when hitting the admin route.
Router.route("/admin", {
// onRun hooks executed only once
onRun: function(){
// create a link taf holding a reference to our publicly served CSS file
var link=$("<link>",{
rel: "stylesheet",
href: "/stylesheets/admin/style.css"
});
// append to the head tag
$("head").append(link);
}
});

Related

Use html-webpack-plugin to inject bundle script tags into <asp:Content> tag in legacy .aspx files with master page?

I'm fairly familiar with webpack and the html-webpack-plugin and have used them on a couple of other (SPA) projects. But in this new project I have to convert a legacy multi-page website to use webpack. There is a custom asp.net handler (ashx) that currently bundles (and minifies in prod builds) registered scripts by placing a comma separate list of script names on the query string of the .ashx reference in a script tag: <script src="Script.ashx?i=jquery,jquery-ui,...">.
One of the problems is that almost all the pages use a master page. So, there is no <body> tag to use for the html-webpack-plugin.
If I was dealing with a small number of entries I would have no problem using a few html-webpack-plugin templates to inject the scripts and place the output files in the correct place in the project folder structure. But there are 50 aspx pages in various locations in the project folder structure. So I would very much like to avoid maintaining separate templates for all of those pages.
But given that there no <body> tags in any of these files, how do I inject the scripts into the desired place?
I've built a custom code generator to read all the aspx pages in the project and find the Script.ashx references. It then parses the comma separated query string and generates a companion .js file with one import statement for each of the referenced scripts. These companion .js files will be what are referenced in the webpack "entry" array. So, for instance /home.aspx gets a companion /home-entry.js file. That file is in the webpack config: entry { "home" : "./home-entry", ... }. And the corresponding Script.ashx is commented out in the source aspx page. I'm also code generating the webpack entry array and the html-webpack-plugin references for each entry into the plugins array in the webpack config.
Home.aspx (snippet):
<asp:Content ID="Content6" ContentPlaceHolderID="footerPlaceHolder" runat="server">
<script type="text/javascript" src="/Script.ashx?i=jquery,jquery-migrate,jquery-ui,jquery-watermark,popr,acrobat-detection,pdflinkfix,device,navbar,jqdialoghelper,home&v=<%= "" + MyNameSpace.Scripts.ScriptHelpers.AssemblyVersion %>"></script>
</asp:Content>
Entry example:
"home" : "./home-entry",
Plugins example:
new HtmlWebpackPlugin( {
chunks: ['home-entry'],
alwaysWriteToDisk: true,
filename: "./home.aspx",
inject: 'body', // or what?
chunkSortMode: "dependency",
hash: true
} ),
home-entry.js:
import '/Scripts/jquery-3.3.1.min'
import '/Scripts/jquery-migrate-min'
import '/Scripts/jquery-ui-1.12.1.min'
import '/Scripts/jquery.watermark.min'
import '/Scripts/popr/popr'
import '/Scripts/acrobat_detection'
import '/Scripts/PDFLinkFix'
import '/Scripts/Device'
import '/Scripts/NavBar'
import '/Scripts/jqDialogHelper'
import '/Scripts/Home'
Expected result: The big problem is that I cannot figure out if there is a way to tell html-webpack-plugin to inject into a specific tag. I.e. what I want it to do is find the specific <asp:Content ID="Content6" ContentPlaceHolderID="footerPlaceHolder" runat="server"> tag and inject the script tags into it. Note that there are other <asp:Content> tags that have different ContentPlaceHolderID values. So html-webpack-plugin has to find the one with ContentPlaceHolderID="footerPlaceHolder".
Actual result: I believe with a default html-webpack-plugin options, in the absence of a <body> tag, the plugin will place the scripts at the end of the file. Which will confuse asp.net.
It sounds like the codebase I am working on has a similar setup to yours. I searched for a solution for quite a while to no avail. I ended up writing my own webpack plugin which handles this situation for me now. It defaults to writing to an index.aspx page but you can specify whatever type of page and/or location you'd like it to write to.
You can check it out here. Feel free to install and use if you'd like. Its not super polished or anything but its working well for our setup.
https://github.com/pckessel/MPAInjectionWebpackPlugin

Angular - including CSS file in index.html

I'm trying to use the angular2-busy library in an angular project created with the CLI, but am having an issue importing the stylesheet:
<link rel="stylesheet" href="/node_modules/angular2-busy/build/style/busy.css">
The browser is telling me that it cannot find the file, even with the correct path. I also checked that the file exists, and it does. When I take out the rel="stylesheet" I don't get the error, but then the animations don't work.
Here is the package I am trying to use, if anyone is curious:
https://www.npmjs.com/package/angular2-busy
Angular CLI have it's own way to initialize your global css/js.
They are located in .angular-cli.json configuration
Locate "styles": and add your css there
Example :
"styles": [
"../node_modules/angular2-busy/build/style/busy.css",
"styles.css"
],
Hope that helps.
Basically there are three different ways to do that :-
By adding it to the "styles" array in angular-cli.json file as is shown by #penleychan in his answer.
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"styles.css"
]
You can directly import the css file into styles.css file (or any other css file) that is included in "styles" array in angular-cli.json file by adding the #import statement at the top of that file.
#import "~bootstrap/dist/css/bootstrap.min.css";
Include the css file in index.html page by adding a link element.
<link rel="stylesheet" type="text/css"
href="node_modules/bootstrap/dist/css/bootstrap.min.css"
/>
You can find a more elaborated explanation and a few more alternatives at this link
How to Use Angular with Linked Cascading Style Sheets (CSS)
Always use LINKED CSSS rather than the compiled and embedded JavaScript memory version of CSS Google Angular uses. Why? Linked <link> external CSS is superior in every way to embedded CSS, mainly because linked CSS is cached across thousands of page views, visits, and users online, saving you huge bandwidth values with increased CSS rendering speed in the browser, while implementing simpler, faster CSS management, overall.
HOW TO FIX ANGULAR FOR LINKED CSS
In angular.json delete all the references to CSS files under "styles". It should look like this now:
"styles": [],
Move your CSS files to the"src" folder inside your project, then add links <link> to your external CSS files inside index.html. Add in your link paths to your CSS file starting at the "src" folder and including the "styles" folder or any folder system you desire (see below). You can store your css wherever you want in your project now as long as those folders of files are under your "src" root folder. My physical CSS files in my project for the path below now sit under "src/styles". So the link path should just be my "styles" folder plus the file name:
<link href="styles/mystyles.css" rel="stylesheet" />
Any CSS files for bootstrap, font-awesome, etc. that you want in your project have to be manually copied from your "node_modules" folder in your project into a folder under your "src" folder, just like in the location used for the CSS file above in #2. Or, you can reference them from some fully qualified url online. If you want to create a link to them as above in "index.html", or import them into the html file directly (example below), that will also work. If you were importing them before from the "node_modules" folder that will not work as the Angular CLI or webpack resolved those paths by compiling your CSS imports into JavaScript. After you move those CSS files and link or import them from the src folder, they will not be compiled into Angular JavaScript now. When using #import, be sure to drop your bootstrap and font-awesome CSS files in the same "src/styles" folder as your main style sheet and import them into that stylesheet like this:
<style type="text/css">
#import "bootstrap.min.css";
#import "font-awesome.min.css";
</style>
In the same angular.json file above, under the "assets" JSON setting, add a reference to the location of your CSS files in #2 and #3 so the builder can copy them into your dist folder. Any CSS files linked or imported from that folder will get moved by the "dist" folder system when Angular is compiled. Note the new styles path at the bottom. If you have CSS in other folders you can add them here as well. This tells the builder to create the CSS directories in the "dist" folder Angular uses and copy all the CSS files inside them, so when you build for production your index.html links point to the right CSS files on the server:
"assets": [
"src/favicon.ico",
"src/assets",
"src/api",
"src/styles"
],
You now have a powerful set of link elements to all your CSS in the head of your index.html file and can edit them in the Angular project like you normally do, knowing they will work in both the Angular development test server and in your dist production copy. Your website will also benefit from browser caching of CSS one time in memory and permanent file caches.
It took me a day to dig through documentation and testing to figure out what should have been a natural part of any simple website API with linked CSS. I'm sorry Google Angular made this so convoluted. But this change works great!
This simply removes your CSS from the compile and build angular system that pushes all your CSS into a JavaScript file, which simply embedded your CSS into an inline style sheet block in the memory of your browser and head of your HTML page. Using your own linked CSS html tags is far superior and allows better caching and control of CSS cascade rules.
Good Luck!
Try
<link rel="stylesheet" href="node_modules/angular2-busy/build/style/busy.css" >
You are missing the self closing / at the end of your code. It's possible the browser is not fixing this for you.
<link rel="stylesheet" href="/node_modules/angular2-busy/build/style/busy.css" />
Also removing rel="stylesheet" would definitely not fix the problem since the browser needs to know exactly what kind reference you are referring to.
If fixing the closing tag does not work then your path is wrong. You can also try adding a ../ to the beginning of your path. This will make it relative to the folder the site is in.
<link rel="stylesheet" href="../node_modules/angular2-busy/build/style/busy.css" />

How to use a free bootstrap template in meteor

How to use a free bootstrap template (e.g., from startbootstrap.com) in meteor. I mean where the resources- html file, css folders and js folders of the free template should be put and what packages are needed to add/remove in meteor project file? I have tried it several times but got errors and the program crashes each time. I also transfer the script and link tags from section to section, but it did not work.
Just add the css of the template to the client of your Meteor project. Also, try using the nemo64:bootstrap package for Bootstrap. This will add some files to your project automatically, one of which will say is editable at the top. You can put your custom css in that file.
You can put the relevant html, css, and js files anywhere on the client. (Sticking it inside a folder called client will do that).
Image and font files should go in a folder called public.
You will need to make meteor templates from the HTML files. As is they will be missing any <template name="foo"> tags.
The css files can go anywhere under /client and they will automatically be added to the project. These are the easy ones.
The js files are the harder ones. If you put these under /client they will be wrapped by Meteor and will not have global scope. In all probability they won't work at all. You can put them under /public and modify your head.html file to include them to get around that problem. Odds are there won't be very many js functions in the free template anyway so you might want to read through them and see which ones you really need and then convert those to be proper template helpers or global functions on the client.

How to expicitly load only specific (not all) css files in Meteor.js

I want to develop a usual website with Meteor.js (not one-page web app) and I want to load only specific css files for every page. So not all pages share the same css code.
Is it possible?
First off if you are using Meteor you are not building a "usual" site, you are building a very powerful SPA (single page application). You can imitate a "usual" website with introducing routing, try IronRouter.
OK now about CSS. Once you deploy Meteor all your CSS and JS are merged and minified. So if you want to achieve what you are asking you will need to add a package like this one.
https://atmospherejs.com/mrt/external-file-loader
https://github.com/davidd8/meteor-external-file-loader
Then attach it to trigger once a template is created:
Template.myCustomTemplate.created = function() {
Meteor.Loader.loadCss("//example.com/myCSS/style.css");
};
I believe you could also load the CSS from the Meteor server through Meteor's Asset API. Read more here: https://docs.meteor.com/#/full/assets
I found a simple solution. In your meteor project folder create a folder named "public" (no quotes). In that folder create a folder called "css" (no quotes). Put the CSS file in that folder.
In the html file which you want the specific CSS file to apply to do the following:
<head>
<link href="css/yourfile.css" rel="stylesheet">
</head>
Since the last part of your question says, "So not all pages share the same CSS code." you might consider using less and wrapping your template in a different div class.
For example
HTML file
<template name="page1">
<div class="page1css">
<p class="content">Page 1 content</p>
</div>
</template>
LESS File
.page1css {
.content {
font-size: 2em;
}
}
This way you can just wrap your pages and the corresponding css in the correct class.

Integrate CKEditor in Meteor

I'm trying to use CKEditor in a meteor application:
My attemps:
Put CKEditor folder with all the files (js, css, lang, plugins and skins) in the public folder, include the reference to the javascript file (ckeditor.js) in the header and use the appropiate class in textarea elements. Failed because the editor only works if the textarea is in the body (in any template the textarea control remains unmodified).
Put the javascript files (ckeditor.js, config.js, styles.js) in client/lib/compatibility folder and the remaining files in the public folder. This time the application cant locate the files (skins, plugins, ...) because is looking for localhost:3000/client/lib/compatibility/ckeditor/ ...
Has anybody make this integration works before?
I got this working and wanted to post a solution for future visitors. First, you need to put everything from the CKEDITOR build download in the public folder. CKEDITOR comes with all sorts of stuff and references everything based on relative directories.
Your public folder should have a directory named ckeditor it should contain contain the following files and folders:
adapters
lang
plugins
skins
ckeditor.js
config.js
contents.css
styles.js
In your primary layout file reference CKEDITOR like so:
<head>
<script type="text/javascript" src="/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="/ckeditor/adapters/jquery.js"></script>
</head>
In your template:
<template name="yourTemplate">
<textarea id="content" name="content"></textarea>
</template>
Finally, in the rendered function of your template:
Template.yourTemplate.rendered = function() {
$('#content').ckeditor();
};
Normally, you would say this.$('#content').ckeditor() but that doesn't work because CKEDITOR is in your public folder. As a result, you need to the global reference to the #content element.
Put only the CKEditor files that you would've included in <head> inside a folder in client/lib, i.e. client/lib/ckeditor. That's all you need to do to get them served to the client: there's no need to reference anything in any <head> or anything like that. All .js and .css files that Meteor finds inside client are automatically concatenated and served to the client. This applies to any client-side library, not just CKEditor.
The next thing you need to do is cause CKEditor to be initialized on the pages that use it. Say you have a template called edit with a textarea with an ID of editor. And say you're also loading the CKEditor jQuery Adapter. Inside a JavaScript file within client, put:
Template.edit.rendered = function() {
$('#editor').ckeditor();
}
The key here is that the initialization happens after the textarea editor exists and is ready, because this code is executed after the edit template is fully rendered. It will be reexecuted anytime edit is rerendered. Any other client-side library is included and initialized similarly.
EDIT Image files referenced via .css are a pain in Meteor. The "proper" way to deal with them is to put them all under the folder public, in this case for example public/ckeditor. Then edit the CKEditor .css files so that all references to image URLs point to your new folder at the root, i.e. /ckeditor/image1.png etc. (leave out "public").

Resources