Metalsmith portrays itself as a ridiculously simple static site generator. I'm trying to write the most basic of sites just to get myself familiar with the basics of the software, but I can't seem to get even that to build. Here's my folder structure:
|- build/
|- index.js
|- src/
|-index.html
|- templates
|-index.hbt
My index.js file:
var Metalsmith = require('metalsmith');
Metalsmith(__dirname)
.destination('./build')
.build();
My index.html file:
---
title: Home
template: index.hbt
---
And my index.hbt template:
<!doctype html>
<html>
<head>
<title>FOO</title>
</head>
<body>
something
</body>
</html>
My understanding is that the build command should look through the src directory and parse any file it finds with that YAML stuff at the top. So it should look at index.html, see that it renders using the templates/index.hbt template, and basically just move the file into build/index.html. But when I run node index.js I get absolutely nothing. No progress indicator, no "Done building your stuff!" message, just a blinking command prompt line. My build directory is empty. Obviously something is breaking, but there are no logs to check, and no status messages to google. What am I doing wrong? Shouldn't there be at least one page created in the build directory?
Found the answer, in a comment on a tutorial, of all places: https://blog.robinthrift.com/2014/04/14/metalsmith-part-1-setting-up-the-forge/. It's also on the github examples: https://github.com/segmentio/metalsmith
According to those links, you need to include an error callback on the .build() function:
Metalsmith(__dirname)
.build(function(err) {
if (err) throw err;
});
In addition to the error callback issue, which you've already identified, I think you're missing a few things in your files. True, Metalsmith is very simple, but its simplicity means that a lot of the functionality (like support for templates) is brought by modules that you need to install and include explicitly.
You say the content of your index.js file is:
var Metalsmith = require('metalsmith');
Metalsmith(__dirname)
.destination('./build')
.build();
Is that everything you have in you index.js? If you want to use Handlebars templates, you need to explicitly add the metalsmith plugin that handles templates, and instruct it to use handlebars:
var Metalsmith = require('metalsmith');
var templates = require('metalsmith-templates');
Metalsmith(__dirname)
.destination('./build')
.use(templates('handlebars'))
.build();
And make sure that you install the metalsmith-templates and handlebars modules from npm.
Also, you probably know this, but in your index.hbt, you'll need to change
<title>FOO</title>
to
<title>{{ title }}</title>
in order to load the title metadata from index.html.
Let me know if this gets you going, or if you need more help.
Related
I created a jhipster ui only angular 6 app.
I now want to add a script to index.html:
<head>
...
<script src='widgets/widgets.js'></script>
</head>
When I run the index.html is copied to the build/www directory fine, but in the app my script tag or any other changes are not there.
Seems that webpack does not use my new version.
How do I get webpack to use the changed template?
You have to use webpack in order to achieve the script tag injection.
Add your script to the entry points of webpack in the entry property located in webpack.dev.js (or prod) file, then add the related key inside the chunks array of the HtmlWebpackPlugin (it is located in webpack.common file).
This should inject the script tag inside your index.html
I am building a nodejs app using Handlebars as my template engine. I have a template like this one (template.hbs):
<html>
<head></head>
<body>
{{ my_var }}
</body>
</html>
I wonder if I can work (write code) with this file while using on node a minified version ( that will be compiled and delivered for the user ) like this (minified_template.hbs):
<html><head></head><body>{{ my_var }}</body></html>
I mean, I would like some program to be running all time, watching for changes on "template.hbs" and generating "minified_template.hbs". This way I can save bandwidth and money. Is there such a program that can do it? I've heard of Webpack but after searching on google I am still no sure it can do this kind of job.
Thanks in advance.
I have found the answer to my question. It's name is "Gulp":
Install nodejs, then run on commandline:
npm install -g gulp
npm install --save-dev gulp-minify-html
create a file named "gulpfile.js" as:
var gulp = require('gulp');
var minifyHtml = require("gulp-minify-html");
gulp.task('minify-views', function () {
gulp.src('./views/*.html')
.pipe(minifyHtml())
.pipe(gulp.dest('./views_minified'));
});
gulp.task('watch-views', function () {
gulp.src('./views/*.html')
.pipe(minifyHtml())
.pipe(gulp.dest('./views_minified'));
gulp.watch(["./views/*.html"],['minify-views']);
});
Then, from commandline, run:
gulp watch-views
When anny file under the "views" folder is modified, it gets minified by gulp and saved with tha same name to the folder named "views_minified".
I just did a fresh installation of sails (v0.11.0) in my server and after checking this up and working on controllers I found that css, js and templates files included into the assets folders are not being injected to the layout, if there any reason for this to happen? I mean, it is a clean fresh sails installation....
In my quest to get SailsJS to auto-inject stylesheets into the layout file under views/layouts/layout.handlebars in my case, I've found out a couple things...
When you first create your sails app using:
sails new APPNAME --template=handlebars --verbose
note: link below explains above syntax...
Using handlebars templates in Sails.js
Go to config > views.js
It will say:
layout: 'layouts/layout.handlebars'
change to:
layout: 'layouts/layout',
Go to tasks > config > sails-linker.js
Because I'm in development mode right now I will Ctrl + f searching for:
"devStyles"
devStyles: {
options: {
startTag: '<!--STYLES-->',
endTag: '<!--STYLES END-->',
fileTmpl: '<link rel="stylesheet" href="%s">',
appRoot: '.tmp/public'
},
files: {
'.tmp/public/**/*.html': require('../pipeline').cssFilesToInject,
'views/**/*.html': require('../pipeline').cssFilesToInject,
'views/**/*.ejs': require('../pipeline').cssFilesToInject
//ADD HANDLEBARS INJECTION HERE
}
},
Notice it has .html, & .ejs types being injected but not .handlebars
add this line:
'views/**/*.handlebars': require('../pipeline').cssFilesToInject
where I commented:
//ADD HANDLEBARS INJECTION HERE
At this point you should be able to drop a .css file into assets > styles and have it auto-copied to .tmp/public/styles
run:
sails lift
in your command prompt and give it about 20 seconds or so to have the stylesheet manifest its style on whatever page you have in your routes.js
'/': {
view: 'index'
}
As you can see, I made a new .handlebars file index.handlebars and set it as my root level page. You may have to refresh the page a time or two to get the newly auto-injected CSS to show.
P.S. It appears there is no more need to append --linker when first creating a SailsJS project. Also fyi, I'm using sails version 0.11.0
Also if you run sails lift --verbose the line below is how you know the .handlebars injection is working
verbose: Grunt :: File "views/layouts/layout.handlebars" updated.
Hope this helps!
Also, when adding Handlebars Helpers they should go in a file helper.js which should be located in config > helper.js
At the top of the helper.js file I found I had to require handlebars as follows
handlebars = require('sails/node_modules/express-handlebars/node_modules/handlebars');
Having a lot of trouble understand how paths are treated at various points in the configuration and usage of grunt-usemin.
I've got the following repo layout, where the repo root will also be the web app root:
/dashboard/index.html
/Gruntfile.js
/vendor/...some 3rd party CSS and JS...
So the index.html file -> somedomain.com/dashboard/index.html.
The index.html file includes some CSS and JS assets from the /vendor folder. I have grunt configured to put build output in a build folder:
/build/dashboard/index.html
In the index.html file, I have usemin blocks wrapped around all the CSS link and JS script tags:
<!-- build:css(.) app.min.css -->
<!-- build:js(.) app.min.js -->
I had to specify an "alternative search path" with "(.)" so that a script tag for "/vendor/backbone.js" will find it in the right place. Until I did that, it was looking for /dashboard/vendor/backbone.js.
I want the output of processing the CSS/JS assets to be output to build/dashboard/app.min.css and build/dashboard/app.min.js, and included by index.html using a simple relative "app.min.css/js" path.
The problem is, grunt-usemin seems to be using the "app.min.*" path I'm specifying for both contexts in a way that makes it impossible for them to work together:
1) It treats the path as relative to the build directory for purposes of creating the file; the files end up in build/app.min.css and build/app.min.js.
2) It treats the path as relative to the index.html file for purposes of generating the new link/script tags; the browser loads build/dashboard/index.html, which then tries to load "app.min.css", which maps to build/dashboard/app.min.css.
Is there a solution?
I'm really late to the party, but I was also extremely frustrated by this issue and didn't find any satisfying fixes or work arounds. So I worked out some pretty dirty tricks to hopefully better work around this issue. So I'd like to share it with you.
First of all, let's quickly review why this issue happens. When usemin generates output JS/CSS files, it performs a simple path join between your dest directory and the output directory you specified in your usemin block. So if dest is build and usemin block is
<!-- build:css(.) app.min.css -->
then it joins build with app.min.css to spit out the output file at build/app.min.css
But then the usemin task simply replaces the path in your block to you end up with
<link rel="stylesheet" href="app.min.css"/>
which is now linking the wrong directory since your HTML file is under build/dashboard/index.html
So my work around revolves around this idea: what if dest directory is relative to where the HTML file is located? Wouldn't that solve this issue? So given the above example, what if dest is build/dashboard? You can see that it will spit out the output file location and link it correctly. Keep in mind that you are supposed to create a copy task to copy over your HTML files, so make sure your HTML file is copied to build/dashboard/index.html as before.
Of course, the next question would be what if I have HTML files in multiple directories? Wouldn't that be super painful and unintuitive to create a useminPrepare target for each directory, where HTML files could reside? This is why I create a very special grunt task just for working around this issue while I was creating my own grunt scaffolding. I call it useminPreparePrepare Yes, it's deliberately named stupidly, because I'm hoping to remove this thing altogether one day when usemin people make an actual fix for this issue.
As its name suggests, this is a task to prepare useminPrepare configs. It does exactly what I described above. All of its configs mirror useminPrepare configs (in fact, most of them are simply copied over to useminPrepare), with one exception: you need to specify a src directory to identify the root directory of all of your sources so that it can generate relative path to the HTML files. So in your example src: "." will be fine. To use useminPreparePrepare, import it into your build first (you may want to just copy and paste my code, I don't mind), rename your useminPrepare task to useminPreparePrepare and add src property that I just mentioned. Make sure you run useminPreparePrepare with whatever target you like, then immediately run useminPrepare without specifying target so that all of its targets are run. This is because useminPreparePrepare will generate one target for each directory relative to where HTML files are found and copies over your configs for the useminPreparePrepare target your ran. This way, your config can simply look for all HTML files.
Example
"useminPreparePrepare": {
// Search for HTML files under dashboard even though src is .
// because we want to avoid including files generated under build directory.
html: "dashboard/**/*.html",
options: {
src: ".",
dest: "build",
...
"usemin": {
html: ["build/**/*.html"],
...
"copy": {
html: {
files: [{
expand: true,
src: ["dashboard/**/*.html"],
dest: "build"
}
]
},
...
Hope this helps! Have a good day.
EDIT: I realized that given the above example, if you actually include all HTML files from current directory, you will include the generated HTML files too if they are not cleaned ahead of time. So either you clean them ahead of them or look under dashboard directory. I'd recommend separating src and dest directories so that config could look a lot more intuitively.
I don't like it, but the only way I've found to make it work so far is to specify a full path:
<!-- build:css(.) /dashboard/app.min.css -->
<!-- build:js(.) /dashboard/app.min.js -->
The leads to the app* files being in /build/dashboard alongside index.html (which is where I want them), and index.html ends up with the following tags:
<link rel="stylesheet" href="/dashboard/app.min.css">
<script src="/dashboard/app.min.js"></script>
It means the dashboard app is now acutely aware of it's location within the whole, so you can't just rename or relocate it's position in the tree without updating those paths.
I have just started a new brunch.io project using the brunch-with-brunch skeleton (I just want a local server able to display native HTML/CSS/JS).
I have created two files on my own : index.html located in public/ containing the standard doctype, head and body tags plus a script tag referencing the app.js generated by brunch located at public/javascripts/app.js as below :
<script type="text/javascript" src="javascripts/app.js"></script>
As specified by the README.md file located in the app/ directory, I write my applications-specific files in the app/ directory. So I have on file named app.js located in app/ and containing :
console.log("OK");
I start the server with the command :
brunch watch --server
The problem is that I don't see anything in the js console (the server is running at localhost:3333), despite the facts that the html is rendered and the public/javascripts/app.js (generated by brunch) contains these lines (among others) :
require.register("app", function(exports, require, module) {
console.log("ok");
});
What's going on ?
EDIT : The javascript directly written in the html script tag works fine.
Brunch wraps all files by default in module definitions (require.register). So, the console.log is not executed ASAP.
So, you will need to load the entry point in your index.html: <script>require('app')</script>
Module definitions can be disabled.