When I run grunt from the terminal to create a dist version of my site, the css link is commented out in the html file of the dist folder.
Before running grunt, the <head>…</head> is this:
<head>
<meta charset="utf-8">
<title>…</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=0, initial-scale=1">
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
<!-- build:css(.) styles/vendor.css -->
<!-- bower:css -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:css(.tmp) styles/main.css -->
<!-- Gridset CSS -->
<!--[if (!IE) | (gt IE 9)]><!--><link rel="stylesheet" href="./styles/gridset.css" /><!--<![endif]-->
<!--[if IE 9]><link rel="stylesheet" href="./styles/gridset-ie-9.css" /><![endif]-->
<!--[if lte IE 8]><link rel="stylesheet" href="./styles/gridset-ie-lte8.css" /><![endif]-->
<link rel="stylesheet" href="styles/normalize.css">
<link rel="stylesheet" href="styles/main.css">
<!-- endbuild -->
</head>
After running grunt, the ink to the css file is being commented out, which is obviously making the dist version of the site to look awful without any css attatched.
You can see what it looks like after running the grunt command below:
<head> <meta charset="utf-8"> <title></title> <meta name="description" content=""> <meta name="viewport" content="width=device-width,maximum-scale=1,minimum-scale=1,user-scalable=0,initial-scale=1"> <!-- Place favicon.ico and apple-touch-icon.png in the root directory --> <!--[if lte IE 8]>
<link rel="stylesheet" href="styles/main.0b0cc1af.css">
<![endif]-->
As you can see, it comments out the main.css file, then cuts off the rest of the <head>…</head>
Also, I have added my Gruntfile, if that can be any help to anybody:
// Generated on 2015-01-27 using generator-angular 0.10.0
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Configurable paths for the application
var appConfig = {
app: require('./bower.json').appPath || 'app',
dist: 'dist'
};
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
yeoman: appConfig,
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: '<%= connect.options.livereload %>'
}
},
jsTest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['newer:jshint:test', 'karma']
},
styles: {
files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['newer:copy:styles', 'autoprefixer']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
test: {
options: {
port: 9001,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect.static('test'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
},
dist: {
options: {
open: true,
base: '<%= yeoman.dist %>'
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: {
src: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
},
test: {
options: {
jshintrc: 'test/.jshintrc'
},
src: ['test/spec/{,*/}*.js']
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/{,*/}*',
'!<%= yeoman.dist %>/.git{,*/}*'
]
}]
},
server: '.tmp'
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: /\.\.\//
}
},
// Renames files for browser caching purposes
filerev: {
dist: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Performs rewrites based on filerev and the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images']
}
},
// The following *-min tasks will produce minified files in the dist folder
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= yeoman.dist %>/scripts/scripts.js': [
// '<%= yeoman.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg,gif}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseWhitespace: true,
conservativeCollapse: true,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
},
files: [{
expand: true,
cwd: '<%= yeoman.dist %>',
src: ['*.html', 'views/{,*/}*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
// ng-annotate tries to make the code safe for minification automatically
// by using the Angular long form for dependency injection.
ngAnnotate: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: ['*.js', '!oldieshim.js'],
dest: '.tmp/concat/scripts'
}]
}
},
// Replace Google CDN references
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
'views/{,*/}*.html',
'images/{,*/}*.{webp}',
'fonts/{,*/}*.*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: ['generated/*']
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'imagemin',
'svgmin'
]
},
// Test settings
karma: {
unit: {
configFile: 'test/karma.conf.js',
singleRun: true
}
}
});
grunt.registerTask('serve', 'Compile then start a connect Web server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run(['serve:' + target]);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
};
Thanks in advance!
The issue seems to be related to the conditional comments. Looks like usemin is not handling them correctly.
You can solve it by reversing the order of things, for example:
<!--[if (!IE) | (gt IE 9)]><!-->
<!-- build:css(.tmp) styles/gridset.css -->
<link rel="stylesheet" href="./styles/gridset.css" />
<!-- endbuild -->
<!--<![endif]-->
<!-- build:css(.tmp) styles/main.css -->
<link rel="stylesheet" href="styles/main.css">
<!-- endbuild -->
Related
i want to separate my project file to multi files.
with sass and JavaScript import, i can do that just for styles and scripts.
but i want to separate HTML files too.
i dont use any frameworks just webpack.
according to webpack documentation, we can do that with interpolation
https://webpack.js.org/loaders/html-loader/#interpolation
require("html-loader?interpolate!./file.html");
<div>${require('./components/gallery.html')}</div>
but i got error:
Cannot find module 'html-loader?interpolate!./file.html'
my webpack config:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const webpack = require('webpack');
require("html-loader?interpolate!./file.html");
module.exports = {
devtool: 'source-map', // to see source map of scss and ts
entry: [ // root files to load
'./node_modules/material-design-lite/material.min.js',
'./src/scripts/main.ts',
'./src/index.html',
'./src/styles/main.scss',
],
mode: 'development',
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
loader: 'ts-loader',
options: {
transpileOnly: false
}
},
{ // to auto refresh index.html and other html
test: /\.html$/,
loader: "raw-loader",
exclude: /node_modules/,
},
{
test: /\.html$/,
use: [ {
loader: 'html-loader',
}],
},
{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader", options: {
sourceMap: true
}
}, {
loader: "sass-loader", options: {
sourceMap: true
}
}]
},
{ // for images and fonts in scss file
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8000, // Convert images < 8kb to base64 strings
name: 'images/[hash]-[name].[ext]'
}
}]
}
]
},
resolve: {
extensions: ['.ts', '.js', '.json'],
plugins: [
// to get access of custom typescript paths. (e.g. _app/XXX/XX or #app/XXX/XX)
new TsconfigPathsPlugin({ configFile: __dirname + "/tsconfig.json" })
]
},
output: {
filename: "./bundle.js",
path: path.resolve(__dirname, './build'),
},
plugins: [
// use for html pre complier like jade
// new HtmlWebpackPlugin({
// filename: 'index.html',
// path: path.resolve(__dirname, './build'),
// template: './src/index.jade',
// inject: 'body',
// }),
new HtmlWebpackPlugin({
template: './src/index.html'
}),
// copy assets folder to access file from html or as http request
new CopyWebpackPlugin([{
from: './src/assets',
to: path.resolve(__dirname, './build/assets')
}]),
// to use hot, inline (auto refresh) in config file. with out this we have to set as command of webpack-dev-server
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: path.resolve(__dirname, './build'),
hot: true, // for auto refresh
inline: true, // for auto refresh
port: 3000,
overlay: true // for show error on html
}
}
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Zoom.FM</title>
</head>
<body>
<div class="side-nav mdl-list">
<div>${require('./myfile.html')}</div>
</body>
</html>
how can i do that or how interpolation work?
I found answer :)
remove require("html-loader?interpolate!./file.html")
enable interpolate in webpack config
webpack config
{
test: /\.html$/,
use: [ {
loader: 'html-loader',
options: {
interpolate: true
}
}],
},
After fixing my css/scss compiling I'm now try to run the css on my html file, but I keep getting:
GET http://localhost:8080/dist/css/screen.css 404 (Not Found)localhost/:26
GET http://localhost:8080/source/js/modernizr.js 404 (Not Found)localhost/:28
Now, my paths on my html files is the follow:
<link href="dist/css/screen.css" media="screen, projection" rel="stylesheet" type="text/css" />
<script type"text/javascript" src="source/js/modernizr.js"></script>
What am I doing wrong? is it an html path issue? or is it a gruntfile.js issue?
something must missing from either the html or gruntFile.js
hope it makes sense
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
config: {
source: 'source/',
dest: 'dist/',
dist: './dist/'
},
connect: {
options: {
port: 8080,
livereload: 35729,
hostname: 'localhost'
},
livereload: {
options: {
open: true,
base: '<%= config.source %>html',
port: 8080
}
},
dist: {
options: {
open: true,
base: '<%= config.dest %>',
livereload: false
}
}
},
watch:{
compass:{
options: {livereload: true },
files:['<%= config.source %>**/*.scss'],
tasks:['compass']
},
css: {
options: {livereload: true },
files: ['<%= config.dest %>*.css'],
tasks: []
},
js: {
options: { livereload: true },
files: ['<%= config.source %>js/*.js'],
tasks: ['jshint']
},
images: {
options: { livereload: true },
files: ['<%= config.source %>images/*.*']
},
fontsicons: {
options: { livereload: true },
files: ['<%= config.source %>images/icons/**/*.{svg,eot,woff,ttf,woff2,otf}']
},
livereload: {
// Here we watch the files the sass task will compile to
// These files are sent to the live reload server after sass compiles to them
options: { livereload: true },
files: ['<%= config.source %>html/*']
}
},
compass: {
dist: {
files: [{
expand: true,
cwd: 'sass',
src: ['source/sass/*.scss', '*.sass'],
dest: 'css/',
ext: '.css'
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-compass');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['connect:livereload', 'watch', 'compass', ]);
grunt.registerTask('icons', ['webfont']);
};
To get HTTP response from http://localhost:8080 you'll need a http server running on your computer listening on port 8080. If you have no such server running, you will get always 404 error.
E.g. on Node.js the most used is Express: http://www.tutorialspoint.com/nodejs/nodejs_express_framework.htm.
With this piece of code you'll get "Hello World" response on http://localhost:8080 and handle the routes /dist and /source:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World');
})
app.use(express.static(path.join(__dirname, 'dist')));
app.use(express.static(path.join(__dirname, 'source')));
var server = app.listen(8080, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I scaffolded a project using the YEOMAN generator-webapp (I'm running Nodejs v4.0.0, NPM 3.5.3, Bower 1.7.5, Yeoman 1.6.0). When i ran the grunt serve command everything fired up just fine. All scripts and styles got loaded without errors.
The Issue
For some reason i just can't get my head around the following issue. All browsers i have tested (chrome 47, safari 9.0.3 and mozilla 43.0.2) are showing the value of the<title></title> and <script></script> nodes as text inside the window.
The strange part is, the scripts do got executed, as seen in te console.
At first i thought it may be a LiveReload or BrowserSync problem. But even after running grunt build and serving /dist/ using http-server the error remains.
I also reinstalled the complete project after updating NPM and Bower. After running grunt serve again the problem seemed to be gone. However, after a couple of changes in the index.html file the problem reoccured. Even after returning the index.html in it's original state.
Unfortunately i couldn't find any good reading material that even talks about this issue. (this is the closest i got; https://github.com/BrowserSync/browser-sync/issues/791. I'm not sure which steps to take from here. I includes the gruntfile.js, package.json and index.html. A little help or a pointer in the right direction would be greatly appreciated.
gruntfile.js
// Generated on 2016-01-27 using
// generator-webapp 1.1.2
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// If you want to recursively match all subfolders, use:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Automatically load required grunt tasks
require('jit-grunt')(grunt, {
useminPrepare: 'grunt-usemin'
});
// Configurable paths
var config = {
app: 'app',
dist: 'dist'
};
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
config: config,
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
babel: {
files: ['<%= config.app %>/scripts/{,*/}*.js'],
tasks: ['babel:dist']
},
babelTest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['babel:test', 'test:watch']
},
gruntfile: {
files: ['Gruntfile.js']
},
sass: {
files: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['sass', 'postcss']
},
styles: {
files: ['<%= config.app %>/styles/{,*/}*.css'],
tasks: ['newer:copy:styles', 'postcss']
}
},
browserSync: {
options: {
notify: true,
background: true,
watchOptions: {
ignored: ''
}
},
livereload: {
options: {
files: [
'<%= config.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= config.app %>/images/{,*/}*',
'.tmp/scripts/{,*/}*.js'
],
port: 9000,
server: {
baseDir: ['.tmp', config.app],
routes: {
'/bower_components': './bower_components'
}
}
}
},
test: {
options: {
port: 9001,
open: false,
logLevel: 'silent',
host: 'localhost',
server: {
baseDir: ['.tmp', './test', config.app],
routes: {
'/bower_components': './bower_components'
}
}
}
},
dist: {
options: {
background: false,
server: '<%= config.dist %>'
}
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= config.dist %>/*',
'!<%= config.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Make sure code styles are up to par and there are no obvious mistakes
eslint: {
target: [
'Gruntfile.js',
'<%= config.app %>/scripts/{,*/}*.js',
'!<%= config.app %>/scripts/vendor/*',
'test/spec/{,*/}*.js'
]
},
// Mocha testing framework configuration options
mocha: {
all: {
options: {
run: true,
urls: ['http://<%= browserSync.test.options.host %>:<%= browserSync.test.options.port %>/index.html']
}
}
},
// Compiles ES6 with Babel
babel: {
options: {
sourceMap: true,
presets: ['es2015']
},
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/scripts',
src: '{,*/}*.js',
dest: '.tmp/scripts',
ext: '.js'
}]
},
test: {
files: [{
expand: true,
cwd: 'test/spec',
src: '{,*/}*.js',
dest: '.tmp/spec',
ext: '.js'
}]
}
},
// Compiles Sass to CSS and generates necessary files if requested
sass: {
options: {
sourceMap: true,
sourceMapEmbed: true,
sourceMapContents: true,
includePaths: ['.']
},
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/styles',
src: ['*.{scss,sass}'],
dest: '.tmp/styles',
ext: '.css'
}]
}
},
postcss: {
options: {
map: true,
processors: [
// Add vendor prefixed styles
require('autoprefixer')({
browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']
})
]
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the HTML file
wiredep: {
app: {
src: ['<%= config.app %>/index.html'],
ignorePath: /^(\.\.\/)*\.\./
},
sass: {
src: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
ignorePath: /^(\.\.\/)+/
}
},
// Renames files for browser caching purposes
filerev: {
dist: {
src: [
'<%= config.dist %>/scripts/{,*/}*.js',
'<%= config.dist %>/styles/{,*/}*.css',
'<%= config.dist %>/images/{,*/}*.*',
'<%= config.dist %>/fonts/{,*/}*.*',
'<%= config.dist %>/*.{ico,png}'
]
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: '<%= config.app %>/index.html'
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
options: {
assetsDirs: [
'<%= config.dist %>',
'<%= config.dist %>/images',
'<%= config.dist %>/styles'
]
},
html: ['<%= config.dist %>/{,*/}*.html'],
css: ['<%= config.dist %>/styles/{,*/}*.css']
},
// The following *-min tasks produce minified files in the dist folder
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.{gif,jpeg,jpg,png}',
dest: '<%= config.dist %>/images'
},{
expand: true,
cwd: '<%= config.app %>',
src: '*.{ico,png}',
dest: '<%= config.dist %>'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.svg',
dest: '<%= config.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
conservativeCollapse: true,
removeAttributeQuotes: true,
removeCommentsFromCDATA: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
// true would impact styles with attribute selectors
removeRedundantAttributes: false,
useShortDoctype: true
},
files: [{
expand: true,
cwd: '<%= config.dist %>',
src: '{,*/}*.html',
dest: '<%= config.dist %>'
}]
}
},
// By default, your `index.html`'s <!-- Usemin block --> will take care
// of minification. These next options are pre-configured if you do not
// wish to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= config.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= config.app %>/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= config.dist %>/scripts/scripts.js': [
// '<%= config.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= config.app %>',
dest: '<%= config.dist %>',
src: [
'*.txt',
'images/{,*/}*.webp',
'{,*/}*.html',
'fonts/{,*/}*.*'
]
}]
}
},
// Run some tasks in parallel to speed up build process
concurrent: {
server: [
'babel:dist',
'sass'
],
test: [
'babel'
],
dist: [
'babel',
'sass',
'imagemin',
'svgmin'
]
}
});
grunt.registerTask('serve', 'start the server and preview your app', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'browserSync:dist']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'postcss',
'browserSync:livereload',
'watch'
]);
});
grunt.registerTask('server', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run([target ? ('serve:' + target) : 'serve']);
});
grunt.registerTask('test', function (target) {
if (target !== 'watch') {
grunt.task.run([
'clean:server',
'concurrent:test',
'postcss'
]);
}
grunt.task.run([
'browserSync:test',
'mocha'
]);
});
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'postcss',
'concat',
'cssmin',
'uglify',
'copy:dist',
'filerev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:eslint',
'test',
'build'
]);
};
package.json
{
"private": true,
"devDependencies": {
"autoprefixer": "^6.0.2",
"babel-preset-es2015": "^6.1.18",
"grunt": "^0.4.5",
"grunt-babel": "^6.0.0",
"grunt-browser-sync": "^2.1.2",
"grunt-concurrent": "^1.0.0",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-concat": "^0.5.1",
"grunt-contrib-copy": "^0.8.0",
"grunt-contrib-cssmin": "^0.12.2",
"grunt-contrib-htmlmin": "^0.4.0",
"grunt-contrib-imagemin": "^1.0.0",
"grunt-contrib-uglify": "^0.8.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-eslint": "^17.0.0",
"grunt-filerev": "^2.2.0",
"grunt-mocha": "^0.4.12",
"grunt-newer": "^1.1.0",
"grunt-postcss": "^0.6.0",
"grunt-sass": "^1.0.0",
"grunt-svgmin": "^2.0.1",
"grunt-usemin": "^3.0.0",
"grunt-wiredep": "^2.0.0",
"jit-grunt": "^0.9.1",
"time-grunt": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "grunt test"
},
"eslintConfig": {
"extends": [
"eslint:recommended"
],
"env": {
"node": true,
"browser": true,
"es6": true,
"jquery": true,
"mocha": true
},
"rules": {
"quotes": [
2,
"single"
],
"indent": [
2,
2
]
}
},
"name": "Test_application",
"version": "1.0.0",
"main": "Gruntfile.js",
"directories": {
"test": "test"
},
"dependencies": {},
"author": "",
"license": "ISC",
"description": ""
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- build:css(.) styles/vendor.css -->
<!-- bower:css -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:css(.tmp) styles/main.css -->
<link rel="stylesheet" href="styles/main.css">
<!-- endbuild -->
</head>
<body>
<h1>Hello world!</h1>
<!-- Test script -->
<script>//<![CDATA[
var test = 'Well, this is not helping.';
console.log(test);
//]]></script>
<script>
var test = 'Wow, i have been executed! Why am i visible as text in the window?';
console.log(test);
</script>
<!-- build:js(.) scripts/vendor.js -->
<!-- bower:js -->
<script src="/bower_components/jquery/dist/jquery.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js(.tmp) scripts/main.js -->
<script src="scripts/main.js"></script>
<!-- endbuild -->
</body>
</html>
Unfortunately i still don't know which problem exactly causes the effects like described above. However, i did found a solution. It seem's the Yeomean generator-webapp module hasn't been maintained for a while and lost some stability. (The Yeomen crew is currently looking for maintainers)
They did released a Gulp edition of the webapp generator, which could be found here. I simply build a new project with the gulp generator and replaced the new app directory with the old one. Worked like a charm. Don't forget to install Gulp global first if you didn't already.
Below is my grunt file, using grunt-sass and grunt-contrib-watch to
compile my Sass. Is it possible to console log the error to chrome?
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
// Sass to CSS
sass: {
app: {
files: [{
expand: true,
cwd: 'wp-content/themes/bones/library/scss',
src: ['*.scss'],
dest: 'wp-content/themes/bones/library/css',
ext: '.css'
}],
},
options: {
sourceMap: true,
outputStyle: 'nested',
imagePath: "../",
}
},
watch: {
sass: {
files: ['wp-content/themes/bones/library/scss/{,*/}*.{scss,sass}'],
tasks: ['sass']
},
options: {
livereload: true,
spawn: false
}
},
});
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['sass', 'watch']);
};
I'm using grunt to build and deploy a simple angular web app that uses bootstrap and font-awesome. The project was initially created using yeoman generator-angular and built using grunt serve:dist
I noticed the URLS in some of my css files are not being revved or minified properly.
Edit: I've been reading about grunt tasks and I think I've narrowed it down to the rebase in cssmin/clean.
Adding noRebase: true to the cssmin options seems to fix some of the issues but cause others.
Without noRebase:true, this is in the minified css:
body{background-image:url(c:/dev/myapp/.tmp/images/ricepaper_v3.png);
#font-face{font-family:FontAwesome;src:url(/bower_components/components-font-awesome/fonts/fontawesome-webfont.eot?v=4.0.3);
Obviously I don't want it to reference bower_components or my local path.
With noRebase: true:
body{background-image:url(../images/ricepaper_v3.png);
#font-face{font-family:FontAwesome;src:url(../fonts/fontawesome-webfont.eot?v=4.0.3);
This fixes the fonts (which were never revved so the name is correct) but breaks the background image since the image is now named something like "a120f004.ricepaper_v3.png"
My gruntfilejs:
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
yeoman: {
// configurable paths
app: require('./bower.json').appPath || 'app',
dist: 'dist'
},
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['bowerInstall']
},
js: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: true
}
},
jsTest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['newer:jshint:test', 'karma']
},
styles: {
files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['newer:copy:styles', 'autoprefixer']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= yeoman.app %>'
]
}
},
test: {
options: {
port: 9001,
base: [
'.tmp',
'test',
'<%= yeoman.app %>'
]
}
},
dist: {
options: {
base: '<%= yeoman.dist %>'
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
],
test: {
options: {
jshintrc: 'test/.jshintrc'
},
src: ['test/spec/{,*/}*.js']
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the app
bowerInstall: {
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: '<%= yeoman.app %>/'
}
},
// Renames files for browser caching purposes
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>']
}
},
// The following *-min tasks produce minified files in the dist folder
cssmin: {
options: {
root: '<%= yeoman.app %>',
noRebase: true
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg,gif}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseWhitespace: false,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
},
files: [{
expand: true,
cwd: '<%= yeoman.dist %>',
src: ['*.html', 'views/{,*/}*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
// ngmin tries to make the code safe for minification automatically by
// using the Angular long form for dependency injection. It doesn't work on
// things like resolve or inject so those have to be done manually.
ngmin: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: '*.js',
dest: '.tmp/concat/scripts'
}]
}
},
// Replace Google CDN references
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
'views/{,*/}*.html',
'images/{,*/}*.{webp}',
'fonts/*'
]
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'imagemin',
'svgmin'
]
},
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= yeoman.app %>/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= yeoman.dist %>/scripts/scripts.js': [
// '<%= yeoman.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
// Test settings
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
}
});
grunt.registerTask('serve', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'bowerInstall',
'concurrent:server',
'autoprefixer',
'connect:livereload', //deploys the dist folder tot he server. otherwise use connect:livereload
'watch'
]);
});
grunt.registerTask('server', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run(['serve:' + target]);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'bowerInstall',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngmin',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'rev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
};
I noticed in the logs that it was only fontawesome that was not being revved. the background image is being revved, but for some reason it duplicates the css and doesnt delete the first local path.
Anyways, long story short I solved the issue by writing a grunt copy task and calling it in the grunt build. It just copies the bower component fonts to the expected dist folder. This seems like a fine solution as it will always use the bower updated fonts.
copy: {
...
, fontawesome: {
expand:true,
cwd: '<%= yeoman.app %>/bower_components/components-font-awesome/fonts',
dest: '<%= yeoman.dist %>/bower_components/components-font-awesome/fonts',
src: [ '**' ]
}
}