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
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.
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!
I am struggling to get my SASS sourcemaps to work correctly. The problem seems to be the "sources" attribute within the sourcemap and how my SASS files are nested.
I have a Gulp task that compiles SASS to CSS. Here is an example of that
var paths = {
styles: {
src: './Stylesheets/SCSS/',
files: './Stylesheets/SCSS/**/*.scss',
dest: './Stylesheets/CSS/'
}
}
gulp.task('compile-sass', function (){
return gulp.src(paths.styles.files)
.pipe(sourcemaps.init())
.pipe(sass({
outputStyle: 'compressed',
includePaths : [paths.styles.src]
}))
.pipe(prefix({
browsers: ['last 2 Chrome versions'],
cascade: false
}))
.pipe(sourcemaps.write('../Maps/', {
includeContent: false,
sourceRoot: '../SCSS'
}))
.pipe(gulp.dest(paths.styles.dest));
});
The above works for everything else - writing maps to disk, prefixing etc. I am using latest nodejs, gulpjs and relevant npm packages.
An example of folder/asset structure from within my Stylesheets folder:
SCSS/print.scss
SCSS/sectionA/style.scss
SCSS/sectionA/partial/_partialA.scss
SCSS/sectionA/partial/_partialB.scss
SCSS/sectionB/... etc
For SASS files in the root of SCSS/ the sourcemaps work properly. Chrome will show where the source styles are.
For SASS files in a subfolder within SCSS/ the sourcemaps do not work. The problem is the "sources": attribute has the wrong file listed in it.
The print.scss map for example will correctly have "sources":["print.scss"]. But sectionA/style.scss map will have "sources":["style.css"] instead of "sources":["partial/_partialA.scss", "partial/_partialB.scss"] as I would expect.
I have confirmed moving /SCSS/sectionA/style.scss to /SCSS/style.scss and amending any import paths does solve the issue. But I need it to be nested, not in the root of /SCSS.
If I can provide more detail please let me know. I have tried the answer from Path to source map is wrong and it does not solve my issue. I have also tried manipulating mapSources with no avail.
# Update 2019-05-24
My answer talks about using CSSNext. CSSNext was deprecated. The theory in my answer is still applicable using postcss-preset-env.
# Update 2017-03-08
After experimenting with PostCSS, I have used CSSNext to process the CSS after SASS has converted it. CSSNext auto-prefixes and doing it this way retains the connection to the original scss files in the sourcemap.
See my GitHub repo for an example.
After following Mark's feedback and investigating the gulp-autoprefixer module I believe this issue raised on the GitHub repo for gulp-autoprefixer is related to the incorrect sourceroot problem.
Using a variation of the hack from ByScripts I am able to get sourcemaps with the correct sourceroot for nested scss files. The hack used in the ByScripts gulpfile inits the sourcemaps function twice. Once before prefixing, and once after.
I have created a GitHub repo to try and illustrate a reduced test case and a workaround. Inspecting the css produced by the workaround shows the correct relationship back to the source scss.
My gulp file has this in it:
gulp.task('bower2',function () {
return gulp.src(mainBowerFiles('**/*.css'), {debugging:true})
.pipe(gulp.dest(dist_path+'/styles'))
;
});
But it's not finding the CSS files, none of them. I've been successful with the js files though.
I'm not trying to do anything fancy, just build all of the css files into a single vendor.css file (in the case, font-awesome and bootstrap, that's it).
Thanks,
Nick
Try like this.
gulp.task('bower2',function () {
return gulp.src('**/*.css')
.pipe(gulp.dest(dist_path+'/styles'));
});
For some reason gulp has issue with mainBowerFiles() function when you are trying to use it for css task.
I am using the following Gulp task to copy required fonts from the Font Awesome Bower package, this works fine and outputs files like so:
App > Build > Fonts > Font Files
gulp.task('copyfonts', function() {
gulp.src('./bower_components/components-font-awesome/fonts/**/*.{ttf,woff,eof,svg}')
.pipe(gulp.dest('./fonts'));
});
I am trying to refactor this task so that it moves the fonts from any bower package (Bootstrap, for example) using the ** wildcard.
gulp.task('copyfonts', function() {
gulp.src('./bower_components/**/fonts/**/*.{ttf,woff,eof,svg}')
.pipe(gulp.dest('./fonts'));
});
App > Build > Fonts >
Bootstrap > Fonts > Font Files
Font-Awesome > Fonts > Font Files
TL;DR
Using my second method is copying the files as shown above, copying over the package folder and moving that with a 'fonts' folder as a child. Could anyone help show me where I have gone wrong...
I'm a little late to the party here, but for anyone that stumbles upon this in the future: I believe you have a typo in your font glob: eof should be eot.
gulp.src('./bower_components/**/fonts/**/*.{ttf,woff,eof,svg}')
should be
gulp.src('./bower_components/**/fonts/**/*.{ttf,woff,eot,svg}')
Not the best idea to always rely that a package will keep fonts in specific folders, those things can change.
Possibly you're missing another /**/ before fonts (one folder level). Or why all those checks, you know what extensions fonts will have, perhaps add wildcard like **/*.{ttf,woff,eof,svg}
Have you ever tried managing it with gulp-main-bower-files? https://github.com/ck86/main-bower-files
you can test this task
i worked by it
gulp.task('copyfonts', () =>
gulp.src('./app/assets/fonts/*')
.pipe(gulp.dest('./dist/assets/fonts'))
);
I ran into this same issue. After running my gulp builds, my fonts never successfully copied to my dest/fonts folder. The issue was inside my gulp.js file on these lines:
function fonts() {
return src('app/fonts/**/*.{eot,svg,ttf,woff,woff2}')
.pipe($.if(!isProd, dest('.tmp/fonts'), dest('dist/fonts')));
};
After editing the last line, my fonts successfully copied over!
function fonts() {
return src('app/fonts/**/*.{eot,svg,ttf,woff,woff2}')
.pipe(dest('dist/fonts'));
};