we're handling low level html markup as npm modules where one could specify via comment, the name of a modules whose supporting html would be injected at that location. A module contains the html, supporting SCSS and vanilla JS. From a SCSS & JS standpoint everything is buttoned up. The moment the module is installed, the SCSS is compiled, concatenated & appended to a core CSS file and then minified. The JS treatment is very similar.
Where I'm getting very hung up on is how to treat the html snippets. Here is what I've got, which works but this isn't dynamic in any way.
gulp.task('inject-atoms', function () {
gulp.src('./index.html')
.pipe(inject(gulp.src(['./node_modules/my-module-name/my-module-name.html']), {
starttag: '<!-- inject:html -->',
transform: function (filePath, file) {
return file.contents.toString('utf8')
}
}))
.pipe(gulp.dest('./'));
});
What I'd like to be able do (within the target index.html file) is specify module names whose html snippets get injected. So something like:
<!-- inject:my-module-ABC --!>
<!-- inject:my-module-XYC --!>
The only requirement being that the modules have been installed prior to trying to inject their snippets. So the gulp task would need to sweep through the index file and for each inject comment, go fetch that module's html snippet and inject it in.
Any tips on helping me move in the right direction?
Thanks!
Related
I'm trying understand some of the details of this gulpfile from foundation-emails-template.
Here is an excerpt from the file for the part I am curious about:
// Build the "dist" folder by running all of the below tasks
gulp.task('build',
gulp.series(clean, pages, sass, images, inline));
As you can see, the build task calls a bunch of methods in order. One of them is the sass method, and one following that is the inline method:
// Compile Sass into CSS
function sass() {
return gulp.src('src/assets/scss/app.scss')
.pipe($.if(!PRODUCTION, $.sourcemaps.init()))
.pipe($.sass({
includePaths: ['node_modules/foundation-emails/scss']
}).on('error', $.sass.logError))
.pipe($.if(PRODUCTION, $.uncss( // <- uncss happening here
{
html: ['dist/**/*.html']
})))
.pipe($.if(!PRODUCTION, $.sourcemaps.write()))
.pipe(gulp.dest('dist/css'));
}
// Inline CSS and minify HTML
function inline() { // <- Inlining happening here
return gulp.src('dist/**/*.html')
.pipe($.if(PRODUCTION, inliner('dist/css/app.css')))
.pipe(gulp.dest('dist'));
}
So, the sass method gets called first, which compiles the sass files into a single app.css. Part of this method also says to use uncss to remove unused css from the html files. The inline method is responsible for inlining the css into those html files.
I am confused why this works correctly. How is it that inline can be called after scss? The inline method places css in the html files that the scss method "uncss-es", yet it's called afterwards.
This seems to work correctly, so clearly I am just not understanding some sort of basic concept with gulp. Can anyone explain how this works?
Uncss removes unused css rules from your app.css file. It scans your html files and removes any rules for which it can find no selector, via querySelector() in the html file. So app.css has been cleansed before it is then inlined into your html files. This is order you would want. The css is cleaned, not the html.
I'm developing a sample application which uses bower for it's dependency management and gulp for it's build system.
I've used the main-bower-files plugin to copy all of the relevant files from the bower_components directory into a build/dist/bower_components directory.
This all works perfectly, and I can open my application's index.html which properly points to each of these files and they properly point to the assets.
My next step is to concatenate the bower_components so that I have a single CSS and a single JS file along with all of the assets (fonts, images, etc.). I have used gulp-useref to bundle all of the components, and it seems to work nicely.
However, some of the CSS and JS files being combined use relative paths to reference assets which are now incorrect since everything is in a single file:
FontAwesome
Bootstrap
and a custom bower component we are creating
Is there a standard solution for fixing the assets?
Do I need to use gulp to update the asset references or perhaps use a different plugin?
Using gulp-replace plugin we can concatenate bower_components assests.
For example:
var replace = require('gulp-replace');
gulp.task('fix-paths', ['minify'], function() {
gulp.src('public/css/site.css')
.pipe(replace('../', '../bower_components/bootstrap/dist/'))
.pipe(gulp.dest('public/css'));
});
I am using the gulp inject plugin to inject the concatenated file to the html. Something like this -
gulp.task('html', ['styles', 'vendor-js', 'templateCache', 'scripts'], function() {
gulp.src('./*.html')
.pipe(inject(gulp.src(['./dist/js/**/*.js'])
.pipe(angularFilesort()), {
'ignorePath': 'dist/js',
'addRootSlash': false,
'addPrefix': 'scripts'
}))
.pipe(inject(gulp.src(['./dist/vendors/**/*.js', '!./dist/vendors/less/less.js'], {
read: false
}), {
'name': 'vendors',
'ignorePath': 'dist/vendors',
'addRootSlash': false,
'addPrefix': 'vendors'
}))
.pipe(inject(gulp.src(['./dist/css/*.css'], {
read: false
}), {
'ignorePath': 'dist/css',
'addRootSlash': false,
'addPrefix': 'styles'
}))
.pipe(gulp.dest('dist'));
});
Let me know if you need any more code.
For CSS, I would suggest using gulp-rework, which wraps rework that has a number of very helpful plugins.
One of these is url, which provides a function for updating the urls contained within CSS.
An example where this is useful, is in CSS that contains no path to replace; e.g.
url(backgroundimage2.png)
Or, you want to perform different alterations of the URL based on type (e.g. only images, not web fonts).
A function can be composed that tests for asset type; the following example processes only image files:
// CSS
.pipe(cssFilter)
.pipe(rework(reworkUrl(function (url) {
// modifications on url, e.g. using http://medialize.github.io/URI.js/
if (url.match(/[^/]+(jpg|jpeg|png|gif)$/))
{
return '/lib/img/' + url.replace('../', '');
}
else
{
return url;
}
})))
Recently I found same problem so gone through various solutions and one of them was to replace the content of css in this answer itself. After looking the font-awesome.css it was clear that it refers relative path to reach fonts folder. same was the case with bootstrap css. Solution is simple now always make sure to keep css and fonts folder at same level and copy data. Even include your app specific min files here. Single place for all dist files makes life easy
What is the right way to copy bower resources using gulp.
I want a task "build" (for dev) that will:
Transforme /src/index.jade to /build/index.html
Copy bower resources to /build/vendor/*
Copy my resources to /build/css, js, assets
Inject this resources (my and bower's) in index.html
I'm having trouble with "font awesome", because they resources (.ttf, .otf...) are referenced in font-awesome.css as: "../font/fontawesome-webfont.ttf"
I tried with wiredep, that copied js and css to /vendor (no folder structure) and did not copied the fonts.
I also tried with main-bower-files, that also copied all resources (and fonts) to /vendor folder but also with no inner structure
And tried with bowerNormalizer, that create a folder structure like "/vendor/font-awesome//" (invalid too)
And, finally, tried with gulp-bower-files, that copied all bower files (min, dist, src), that is not right also
PS: I don't want min/uglify/concat right now. This things will be done later, at "dist" task
Another approachment:
suposing you have installed:
gulp
run-sequence
main-bower-files
gulp-inject
if you dont, you can install with npm like:
npm install gulp run-sequence main-bower-files gulp-inject --save-dev
Saving your dependencies into html file
Once you have it we start to configure the gulp tasks
//Here we only copy files to folder inside source code.
//In this case ./src/lib/
gulp.task("bower:copyfiles", function(cb){
return gulp.src(mainBowerFiles())
.pipe(gulp.dest('./src/lib'))
cb();
});
//This task is the one wich insert the script tag into
// HTML file. In this case is index.html and is in root
gulp.task('bower:insertfiles', function(cb){
return gulp.src('./src/index.html') //file with tags for injection
.pipe(inject(gulp.src(['./src/lib/*.js', './src/lib/*.css'], {read: false}), {
starttag: '<!-- bower:{{ext}} -->',
endtag: '<!-- endbower -->',
relative:true
}
))
.pipe(gulp.dest('./src')); //where index.html will be saved. Same dir for overwrite old one
})
//And this task will launch the process of copy and include into index.html
gulp.task('bower:buildlib', function(cb) {
runSequence('bower:copyfiles', 'bower:insertfiles',cb);
})
Now we have half process, we need to insert the tags into index.html to let gulp know where has to include the content
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- bower:css -->
<!-- HERE WILL BE INSERTED THE CODE. -->
<!-- endbower -->
</head>
<body>
<!-- bower:js -->
<!-- HERE WILL BE INSERTED THE CODE. -->
<!-- endbower -->
</body>
</html>
and the last step is run our task in command line
gulp bower:buildlib
Notes:
Is known some libraries installed with bower has different file configuration. f.e.: when you install bootstrap, css files are not included because inside bower.json (in the library folder on bower_components or whatever you have) is set in that way. You can fix this overwriting these options in the bower.json on your project root directory adding it like this (same bootstrap example):
"overrides":{
"bootstrap":{
"main":[
"dist/js/bootstrap.js",
"dist/css/bootstrap.min.css",
"less/bootstrap.less"
]
}
}
this way you set wich files are going to be include and wich ones not.
I solved this problem like this:
gulp.task('move', ['yourDependencies'], function(){
gulp.src(['bower_components/*.js', 'bower_components/somefile'], {
base:'.bower_components/somepath'
})
.pipe(gulp.dest(build/vendor/);
}
the base options defines the base dir of the file (that means it will not create the same dirs in the build folder). For more explanations visit: Why does gulp.src not like being passed an array of complete paths to files?
I do not know how to transform .jade - files into .html files (i'm sorry).
The inject thing can be solved with the gulp-inject plugin:
https://www.npmjs.com/package/gulp-inject
Sorry for my bad english :-)
I have just started using gulp.js and I want to know if there is a way to strip out comments from my HTML files. Of course, I don't want the comments removed from the original files, just those that will be in production. Say I have a file like this:
index.html // before gulp
<html>
<!-- Some comments -->
<!-- Some more comments -->
<div>
// some stuff
</div>
</html>
index.html // after gulp
<html>
<div>
// some stuff
</div>
</html>
Part of my question is that I'm not really sure how this should work. Am I suppose to put all of my gulped HTML files (with comments removed) in a separate directory, and only push that up to my server? I still want the comments to exist in my HTML files on my testing environment (and on my repo), just not on the files that go out to production. Any help in my understanding of how to do this would be much appreciated!
with gulp-htmlmin you can do it like this:
.pipe(htmlmin(
{
removeComments: true
}
))
see https://github.com/kangax/html-minifier#options-quick-reference for all available options.
I normally use gulp-htmlmin for removing comments among many other optimizations one can do on html files. I have a SRC folder containing the source html files with comments and a BUILD folder that contains all the optimized assets (js, css and html too) and I serve the files from the build folder when in production mode.
With https://www.npmjs.org/package/gulp-preprocess you can remove the comments.
So you would have one folder - as above - for pre gulp files and one for after it.
Then you could make 2 different tasks. One that only copies the html files and one which copies them and removes the comments.
Perhaps the simplest way is with gulp-decomment:
var gulp = require('gulp');
var decomment = require('gulp-decomment');
gulp.task('default', function () {
return gulp.src('input.js')
.pipe(decomment())
.pipe(gulp.dest('dest'));
});
I've switched from using the Resources plugin to the new Asset Pipeline plugin. However, I've come across an issue that I'm not sure how to fix.
I use several templates (ie: _template.gsp) that are included via the g:render tag from other GSP files.
_template.gsp:
<%# page contentType="text/html;charset=UTF-8" %>
<asset:stylesheet src="_template.css"/>
<asset:javascript src="_template.js"/>
<div>
...
</div>
other GSP files:
...
<g:render template="/template"/>
...
In my _template.gsp file I include several assets that are required for the code in the template to work and/or look right. When I used the resources plugin to accomplish this, things worked as expected. Any files included in templates were moved to the HEAD section of the resulting GSP file. However, with the Asset Pipeline plugin, they stay in the same location where the template was included in the calling GSP file. And to make things worse, they aren't processed correctly, so they aren't loaded correctly in the resulting HTML file.
For example, in debug the resulting HTML file looks like this
...
<link rel="stylesheet" href="/assets/_template.css?compile=false"/>
<script src="/assets/_template.js?compile=false" type="text/javascript"></script>
<div>
...
</div>
...
and everything works (although the file ideally should be loaded in the HEAD section like it used to when using the Resources plugin).
In production the resulting HTML file looks like:
...
<link rel="stylesheet" href="/assets/_template.css"/>
<script src="/assets/_template.js" type="text/javascript"></script>
<div>
...
</div>
...
however, in production all other included assets (files included in the actual GSP file) have longer filenames that look like styles-6a85c6fa983d13b6f58e12b475e9d35c.css. The _template.css and _template.js files from the template isn't being converted to one of these long filenames and if I try to access the /assets/styles.css path I simply get a blank page.
I was able to solve the first part of my problem (the assets not being in the HEAD) by creating the following tag library:
class TemplateAssetsTagLib
{
// Define the namespace and encoding
static namespace = 'tasset'
static defaultEncodeAs = 'raw'
// Tag called to move the content of this tag to where the assets tag is located (usually the HTML HEAD section)
def head = { attrs, body ->
// Get any existing asset blocks
def assetBlocks = request.getAttribute('templateAssetBlocks')
if(!assetBlocks)
assetBlocks = []
// Add the body of this tag to the asset blocks list
assetBlocks << body()
request.setAttribute('templateAssetBlocks', assetBlocks)
}
// Tag called to load any content that was saved using the head tag
def assets = { attrs ->
// Get all existing asset blocks
def assetBlocks = request.getAttribute('templateAssetBlocks')
if(!assetBlocks)
return
// Output the asset blocks
assetBlocks.each { assetBlock ->
out << assetBlock
}
}
}
It's mirrored after the Asset Pipeline deferred script functionality, but more generic.
And I've been able to solve the second problem by simply renaming the assets and removing the leading underscore. For some reason assets with a leading underscore don't get compiled during WAR creation and therefore aren't accessible in production mode.