I have these requirements:
Concatenate css files.
Rev the concatenated css file.
Rev resource files referenced by css files (images, fonts, etc...). File references are relative and come from third parties, so I have no control over them.
Rewrite file references in css files for revving, and to make them relative to the concatenated file, rather than the original file.
My project layout:
dist/
index.html
app-<hash>.css
bower_components/
bootstrap/
fonts/
glyphicons-halflings-regular-<hash>.woff
glyphicons-halflings-regular-<hash>.ttf
etc...
app/
index.html
appStyles.css
bower_components/
bootstrap/
dist/
css/
bootstrap.css
etc...
fonts/
glyphicons-halflings-regular.woff
glyphicons-halflings-regular.ttf
etc...
So, as an example, bootstrap.css references glyphicons-halflings-regular.ttf using the relative path: '../../fonts/glyphicons-halflings-regular.ttf'. This needs to be rewritten to the relative path 'bower_components/bootstrap/fonts/glyphicons-halflings-regular-hash.ttf'.
I have been able to get a gulp-usemin task working that concatenates my css files and revs the output. It even works with source maps, which is a bonus (not required).
However, I can't get usemin to rewrite paths in css files to adjust for revving and to make them relative to the concatenated file. How do I do this? Do I need another plugin in the css chain? Here is what I have so far:
var resourcesRevved = [
'app/bower_components/bootstrap/**/*.ttf',
'app/bower_components/bootstrap/**/*.woff',
etc...
];
gulp.task('copy:resources:revved', ['clean:dist'], function() {
return gulp.src(resourcesRevved)
.pipe(rev())
.pipe(gulp.dest('dist'));
});
gulp.task('usemin', ['copy:resources:revved'], function() {
return gulp.src('./app/index.html')
.pipe(usemin({
css: [
sourcemaps.init({
loadMaps: true
}),
'concat',
rev(),
sourcemaps.write('.')
]
}))
.pipe(gulp.dest('dist/'));
});
Here is the usemin section in index.html:
<!-- build.css app.css -->
<link href="bower_components/bootstrap/dist/css/bootstrap.css" rel="stylesheet">
<link href="app/appStyles.css">
etc...
<!-- endbuild -->
Related
I have template folders full of arbitrary css/html/js/image files. I want to be able to access them via require:
var someHtml = require('./templateFolder/foo.html');
Here, foo.html contains references to foo.png, foo.css, and foo.js, I want them all inlined in the html document itself, in base64 encoding, style tags, and script tags, respectively. Is this possible? If so what would the webpack configuration look like?
EDIT: Further Context
I want this
<html>
<head>
<link rel="stylesheet" type="text/css" href="foo.css">
<script type="text/javascript" src="bar.js"></script>
</head>
<body>
</body
</html>
to be transformed into this:
<html>
<head>
<style> Contents of foo.css </style>
<script> Contents of bar.js</script>
</head>
<body>
</body
</html>
In other words, I want a each html file and all of its resources to be transformed into a single html file. I don't necessarily have a lot of control as to what the html files look like.
It looks like you could use the html-loader for webpack for your use case:
https://github.com/webpack-contrib/html-loader
A sample webpack.config file would include:
module: {
rules: [{
test: /\.html$/,
use: [ {
loader: 'html-loader',
options: {
minimize: true
}
}],
}]
}
You should then be able to require a html file you want with require("html-loader!./file.html");
For more information look up the link above!
Edit:
To automatically inline images for example you can make use of the attrs parameter:
By default every local is required (require('./image.png')). You may need to specify loaders for images in your configuration (recommended file-loader or url-loader).
You can specify which tag-attribute combination should be processed by this loader via the query parameter attrs. Pass an array or a space-separated list of : combinations. (Default: attrs=img:src)
Edit:
To do the same for stylesheet links and js you could use https://www.npmjs.com/package/html-inline-source-webpack-plugin
Note: I am aware of https://github.com/babel/babel-standalone#usage and am not asking about transpiling in the browser.
I'm wondering if either of the following is possible:
Option 1 - Transpile stuff in an HTML file
Say I have the following src/index.html with some inline ES6:
<!-- src/index.html -->
<h1>This is some HTML stuff...</h1>
<script>
() => console.log('I am some inline JS.');
</script>
After some type of build end up with the following dist/index.html which has inline ES5:
<!-- dist/index.html -->
<h1>This is some HTML stuff...</h1>
<script>
function() {
console.log('I am some inline JS.');
}
</script>
Option 2 - Concatenate transpiled JS to an HTML file
Say I have the following src files:
<!-- src/index.html -->
<h1>This is some HTML stuff...</h1>
and a JS which contains ES6:
// src/index.js
() => console.log('I am some JS from another file.');
After some type of build end up with the following dist/index.html which has inline ES5 concatenated to the bottom of the file in a script tag:
<!-- dist/index.html -->
<h1>This is some HTML stuff...</h1>
<script>
function() {
console.log('I am some JS from another file.');
}
</script>
I've looked through a bunch of webpack loaders, but nothing seems to fit this. There may be a really simple solution, but what am I missing? Is there a babel plugin or webpack loader which could handle either of these.
P.S. I would prefer a setup with Option 1.
The Polymer team has a util that strips js from html. Crisper. You can use that to strip the js from the script tags, then feed it to your transpiler, then inject it back into the html.
I'm new to Laravel and whole framework stuff.
I do (may) understand a part of how the page rendered via laravel, but even after extensive search, I do not understand how laravel mix works.
Suppose that there is a page requires a global js and css library (lets specify jQuery and bootstrap)
Also the page requires custom js file like someJsTools.js.
Elementary speaking, in the past, those files referenced via <script src="blah"></script> and <link rel="blah" /> inside head tag and I used to it. In this env, all I have to do is specify those tags page by page.
// pageA requires jQuery.js, bootstrap.css and one CUSTOM JS file imatrouble.js
<head>
<link rel="stylesheet" herf="bootstrap.css"/>
<script src="jquery.js"></script>
<script src="imatrouble.js"></script>
</head>
//pageB requires jQuery.js, bootstrap.css and two custom js files.
<head>
<link rel="stylesheet" herf="bootstrap.css"/>
<script src="jquery.js"></script>
<script src="imatrouble.js"></script>
<script src="withimatroubleimadisasterlikewhateveryoucanimagine.js"></script>
</head>
PageA and PageB both requires common jQuery.js and bootstrap.css file. From what I learn, laravel Mix combine all js files into one and I don't get it here.
Problem 1 - One file do everything?
If it is true that "mix" things all together as one file, then how this one file could handle all of this different requirements seperatelly? I believe that my knowledge is wrong and its from my incorrect understanding of laravel mix and perhaps webpack mechanism.
Problem 2 - How can I manage all different page and every different situation?
Whether the problem above is originated from my missunderstanding or not, I cannot figure out what part of I (will) do could cause differences between pages. If mix only works for common global library, then all I have to do is just load custom js/css files manually. I currently assume that it is highly unlikely.
Please, someone help me to escape this chaos.
Have a good day.
It is purely based on your requirements. It depends on how you are customising your assets file.
For example :
Jquery, Angular,Bootstrap,Font Awesome is common for all your pages. So what I usually do is. I combine all css files to one file and all js files to one. Like below..
CSS mix
elixir(function(mix) {
mix.styles([
"libraries/bootstrap.css",
"libraries/font-awesome.min.css",
"custom/default.css",
], 'public/assets/css/common.css');
});
JS mix
elixir(function(mix) {
mix.scripts([
"libraries/jquery-1.10.2.js",
"libraries/bootstap.js"
"libraries/angular.js",
"libraries/angular-animate.js",
"custom/defaut.js"
], 'public/assets/js/common.js');
});
Suppose some pages need specific dependency[product, orders...etc]. For instance if product page needs wow.js, product.js and wow.css,product.css
CSS mix
elixir(function(mix) {
mix.styles([
"libraries/wow.css",
"custom/product.css",
], 'public/assets/css/product.css');
});
JS mix
elixir(function(mix) {
mix.scripts([
"libraries/wow.js",
"custom/product.js"
], 'public/assets/js/product.js');
});
So final laravel mix file looks like below
gulpfile.js
var elixir = require('laravel-elixir');
elixir.config.sourcemaps = true;
/**
* Global CSS MIX
*/
elixir(function(mix) {
mix.styles([
"libraries/bootstrap.css",
"libraries/font-awesome.min.css",
"custom/default.css",
], 'public/assets/css/common.css');
});
/**
* Global JS MIX
*/
elixir(function(mix) {
mix.scripts([
"libraries/jquery-1.10.2.js",
"libraries/bootstap.js"
"libraries/angular.js",
"libraries/angular-animate.js",
"custom/defaut.js"
], 'public/assets/js/common.js');
});
/**
* Product CSS MIX
*/
elixir(function(mix) {
mix.styles([
"libraries/wow.css",
"custom/product.css",
], 'public/assets/css/product.css');
});
/**
* Product JS MIX
*/
elixir(function(mix) {
mix.scripts([
"libraries/wow.js",
"custom/product.js"
], 'public/assets/js/product.js');
});
Now all your assets files are ready. Now you need to include wherever you want.
Suppose on your homepage you only requires common.js and common.css files.
homepage.blade.php
<head>
<link rel="stylesheet" href="{{ asset('assets/css/common.css') }}"/>
<script type="text/javascript" src="{{ asset('assets/css/common.js') }}"></script>
</head>
On the product page, you require both common and product assets file dependency. Include like below
product.blade.php
<head>
<link rel="stylesheet" href="{{ asset('assets/css/common.css') }}"/>
<link rel="stylesheet" href="{{ asset('assets/css/product.css') }}"/>
<script type="text/javascript" src="{{ asset('assets/js/common.js') }}"></script>
<script type="text/javascript" src="{{ asset('assets/js/product.js') }}"></script>
</head>
Is there currently a way to do relative output paths? Within gulp-useref or otherwise?
My current situation:
project_folder/
app/
index.html
about/
index.html
scripts/
index.js
about.js
In the index.html based out of app/, everything works fine:
<!-- build:js scripts/main.min.js -->
<script src="/scripts/main.js"></script>
<!-- endbuild -->
The index.html file sits next to the scripts folder so the relative path syncs up properly.
But here's the about/index.html:
If I pass in the path like this – ../scripts/about.min.js – the generated about.min.js gets output one folder too far back, resulting in this situation:
project_folder/
scripts/
about.min.js
dist/
index.html
about/
index.html
scripts/
index.min.js
With the about/index.html looking for it in <script src="../scripts/about.min.js"></script>.
If I don't pass in the relative path in about/index.html:
about.min.js ends up in the proper location, but then the path is incorrect in about/index.html – set to <script src="scripts/about.min.js"></script>.
Suggestions? I could have a different version of the useref task running at different folder levels. I've also considered figuring out some way to alter the path after everything runs through based on how far away it is from the base folder, but I'm not quite sure where to start if that's a viable choice. I just don't know if I'm missing something more obvious.
Because this is meant to be a feature in a tool I'm putting together, doing it manually each time isn't really viable.
Here's the snippet from my gulpfile.js that's relevant to this. I have a nunjucks template that runs before this happens, so that's why it works from .tmp:
gulp.task('html', ['templates'], function() {
var assets = $.useref.assets({searchPath: ['.tmp', 'app', '.']});
return gulp.src('.tmp/**/*.html')
.pipe(assets)
.pipe($.if('*.js', $.uglify()))
.pipe($.if('*.css', $.csso()))
.pipe($.rev())
.pipe(assets.restore())
.pipe($.useref())
.pipe($.revReplace())
.pipe($.gzip({append: false}))
.pipe(gulp.dest('dist'))
.pipe($.size({title: 'html'}));
});
Any help would be appreciated! Thanks for tool!
I had a similar issue. I would try adjusting your search path. Mine originally looked like this:
var assets = $.useref.assets({searchPath: './'});
changing it to this fixed it:
var assets = $.useref.assets({searchPath: ''});
Why not use absolute paths?
<!-- build:js /scripts/main.min.js -->
<!-- build:js /scripts/about.min.js -->
You would then need to move your index files to the correct locations using other gulp tasks that could depend on the above task.
gulp.task('full-build', ['partial-build'], function () {
gulp.src('index.html', { base: './' })
.pipe(gulp.dest(buildLocation));
});
I also faced similar kind of issue and find a solution. It may help others
My dir structure was like
Project_root
app
scripts
index.html
bower_component
And in the index.html file it was referencing like the following which was auto generated by inject
<!-- build:js js/lib.js -->
<!-- bower:js -->
<script src="../bower_components/jquery/dist/jquery.js"></script>
<script src="../bower_components/angular/angular.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js js/app.js-->
<!-- inject:js -->
<script src="/app/scripts/app.js"></script>
<script src="/app/scripts/controllers/authentication.js"></script>
<!-- endinject -->
<!-- endbuild -->
In the gulpfile I was setting up the searchPath and got some strange behavior in the output file
$.useref.assets({searchPath: ''}); >> it generated only lib.js file
$.useref.assets({searchPath: ['']}); >> it generated only app.js file
Finally both app.js and lib.js file generated with the following code
$.useref.assets({searchPath: ['./bower_components','']});
I'm currently using the gulp-usemin pluign, however I'm struggling with one thing: using the images the package provides!
<!-- build:css lib/css/main.min.css -->
<link rel="stylesheet" type="text/css" href="bower_components/font-awesome/css/font-awesome.css">
<!-- endbuild -->
The font-awesome bower package also comes with the fonts:
bower_components/font-awesome/fonts/**.*
I currently compile my css with the usemin plugin:
gulp.task('usemin', function() {
return gulp.src('src/index.html')
.pipe(usemin({
css: [minifyCss(), 'concat'],
}))
.pipe(gulp.dest('dist/'));
});
Right now this scans my HTML with the above build paths, and successfully minifies it.
However the problem I have, is that now my font-awesome CSS is looking for the fonts in the wrong place, as they're no longer in the same directory.
How do I fix this?
Figured this out by finding this question: Can you remove a folder structure when copying files in gulp?
My task is now uses gulp-rename:
gulp.task('copy-bower_fonts', function() {
return gulp.src(paths.bower_fonts)
.pipe(rename({
dirname: '/fonts'
}))
.pipe(gulp.dest('dist/lib'));
});
The fonts from the packages which look for ../fonts/ now points to a correct location.