I'm using Grunt and assemble to build my HTML pages for a static site and I want to minify my HTML.
So I would assume that Assemble the plugin that runs the handlebars templates against a data set would have a minify option.
There is no mention of it on the Assemble docs;
http://assemble.io/docs/Options.html#configuration-options
But there is a mention that alludes to in handlebars-helper-minify docs;
https://www.npmjs.org/package/handlebars-helper-minify#-assemble-task-options
- But this has no effect.
I cannot find anything else on the internet, surely this is a more common request...
grunt.initConfig({
assemble: {
options: {
assets: '../source',
data: ['package.json','data/*.{json,yml}'],
partials: 'templates/modules/*.hbs',
ext: '.html',
helpers: 'templates/helpers/*.js',
layout: 'templates/layout/master.hbs',
removeHbsWhitespace: true,
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true
}
},
dev: {
options: {
production: false
},
files: [{
expand: true,
cwd: 'templates/pages',
src: ['*.hbs'],
dest: '../source'
}]
}
}
});
You need to register {{minify}} helper explicitly in the Gruntfile
helpers: ['handlebars-helper-minify', 'templates/helpers/*.js']
Alternatively, try add handlebars-helper-minify module to devDependencies and keywords in your project's package.json.
{
"devDependencies": {
"handlebars-helper-minify": "~0.1.1"
},
"keywords": [
"handlebars-helper-minify"
]
}
In your master.hbs layout, wrap it with {{minify}} for example:
{{#minify}}
{{> header }}
{{> body }}
{{> footer }}
{{/minify}}
check out grunt-prettify by one of the authors of Assemble. an example of its use besides the project's README is here in this Gruntfile:
/**
* Beautify generated HTML to make diffs easier
*/
prettify: {
tests: {
options: {ocd: true},
files: [
{expand: true, cwd: 'test/actual', src: ['**/*.html'], dest: 'test/actual/', ext: '.html'}
]
}
},
good luck
Related
file-loader is creating two separate images in my build folder. One is the named correctly and saved in the correct path, the other is named [hash].png (which is the default) and is stored in build, not build/images. The second incorrect file is 0 bytes; this is the one being linked in the final index.html file in the build folder. I've defined both outputPath and publicPath. publicPath doesn't seem to actually do anything though, regardless of what I put there. Am I misunderstanding what it does?
module.exports = {
entry: {
index: './app/main.js',
vendor: './app/vendor.js'
},
output: {
path: path.resolve(__dirname, './build'),
filename: '[name].[contenthash].js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/, /api/, /tests/, /coverage/],
use: 'babel-loader'
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.html$/,
use: 'html-loader'
},
{
test: /\.(svg|png|jpg|gif)$/,
use:{
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'images/',
publicPath: 'images/'
}
}
},
]
},
plugins: [
new HtmlWebpackPlugin({ template: './app/index.html' }),
new CleanWebpackPlugin()
]
};
Image link in final html:
<img src="465107fe07e3ec18a463.png">
Another post with the same issue that didn't get any answers:
Webpack, I am trying to use file loader to load images but whenever i run build i get 2 images not 1 and the one linking to the html file is wrong
I eventually figured it out. As of Webpack 5.0, this can be handled without installing a loader at all. So file-loader, url-loader, raw-loader, etc. are now obsolete.
https://webpack.js.org/guides/asset-modules/
This is a problem of file-loader v6.
I solved this with the way adding esModule option.
Both html-loader, css-loader and loader that using image url need the esModule option false.
Or you should use the file-loader except v6.
{
loader: 'css-loader',
options: {
esModule: false
}
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
Which loader/plugin should I use to move multiple html files from one folder (src) to another (dist) which only imports files that obey certain rules in this example I need to import multiple html files, so the regex would be:
/.html$/
I know that I can move html using html-webpack-plugin but I don't want to create object instance for every page I want to move. I also don't want to make multiple imports in my app.js (entry point for webpack).
So i tried with copy-webpack-plugin but this one moves everything from src to dist. Is it possible to filter with my regex pattern or do you know other way that works to do this?
new CopyWebpackPlugin([{
from: './src',
to: path.resolve(__dirname, "dist")
}],
I gues that I could use system
mkdir dist && cp ./src/*.html ./dist
And simply run this in my package.json in the script before running webpack -d
but this is not the "polite" way of doing this. I'm sure that webpack can do that easily..
Ps. Also, it would be nice to minimize those files, if possible.
Moving all files in batch
So for now it works like this. To not have to include every single file from the src folder in to my app.js (which is my entry point for webpack) I required all files using require.context()
Because my app.js is also in my src folder I use relative path to require all other file:
// requires all files in current directory and sub directories
require.context("./", true, /^\.\/.*\..*/);
Or if you want to import files with certain extension sue this instead:
// requires all html files in current directory and sub directories
require.context("./", true, /^\.\/.*\.html/);
So now everything is imported and I don't have to require files manually. The only thing I have to do is set entry to app.js using path.resolve.
I now can use test property to get what I want from within in webpack.config.js module rules.
...
module: {
rules: [
{
test: /\.(html)$/,
use:
[
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
context: './src',
outputPath: '/',
publicPath: '/'
}
},
...
This works fine my files are moved (but not minified). Perhaps someone can take this a little bit further and the answer will be completed.
Below i place full file for reference only
webpack.config.js
// imports node plugin which allows us to save data to a file for example css external files
var ExtractTextPlugin = require("extract-text-webpack-plugin");
// cleans defined folders before webpack will build new files now we can remove package.json commands "rm -rf ./dist && ..."
var CleanWebpackPlugin = require("clean-webpack-plugin");
// copies to memory html from template file and injects css and javascript as well as img src to newly generated html file.
var HtmlWebpackPlugin = require("html-webpack-plugin");
// to include jquery we need to import 'jquery' in app.js but also we need to make connection between bundle.js jquery script
var Webpack = require('webpack');
// includes node path resover that is need for webpack-dev-server to run properly
var path = require('path');
// webpack configuration
module.exports = {
entry: [
path.resolve(__dirname, "src/app.js"),
],
output: {
path: path.resolve(__dirname, 'dist'), // defins the main utput directory
filename: 'js/bundle.js',
},
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 8080,
},
module: {
rules: [
{
test: /\.(html)$/,
use:
[
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
context: './src',
outputPath: '/',
publicPath: '/'
}
},
]
},
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'img/',
publicPath: '/' // this path relates to reference path from the index.html file that imports out bundle.js file
}
}
},
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
]
},
{
test: /\.sass$/,
include: [
path.resolve(__dirname, "src/sass")
],
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: [
{
loader: 'css-loader',
options: {
minimize: false,
sourceMap: true,
}
},
'sass-loader'
]
})
},
]
},
plugins: [
// mapping jQuery variable to our node module dependency (remember to import 'jquery' in app.js)
// below we make jquery available as both the $ and jQuery variable
new Webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
// use extract plugin to build an external file loded by sass-loader > complied to css > movig to bundle.css
new ExtractTextPlugin({
filename: 'css/bundle.css'
}),
// remove all files from this folder before generating new files
// new CleanWebpackPlugin(['dist']),
],
}
You should be able to use copy-webpack-plugin's support for globs to achieve what you want.
new CopyWebpackPlugin([
{
from: './src/*.html',
to: path.resolve(__dirname, 'dist')
}
])
The globs accept minimatch options too.
EDIT:
In addition, if you're copying just HTML (and want to minify them), you might want to take a look at html-webpack-plugin. The minify option allows you to minify those HTML files.
I am new to Webpack and I am having a hard time to understand how I can access the content of my json file being added in entry and loaded using json-loader:
entry :
en: {
`${config.basePaths.tmp}script.js`,
`${config.basePaths.tmp}en.json`
}
},
output: {
publicPath: '/js/',
path: `${config.paths.scripts.dist}`,
filename: `[name].script.js`
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
},
{
test: /\.coffee$/,
loader: 'coffee-loader'
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
}
The object is added to my output file (en.script.js) but I have no clue how to access it... It looks like this:
function(module, exports) {
module.exports = {
"en": {
"title": "I love webpack",
"something": "else"
}
};
}
Please help me.
You should not put a JSON file as the entry point. Entry points are meant to be the starting point of your app and if you specify multiple files per entry point it's just to include them in the same bundle, but they don't really interact with each other (see Concepts - Entry Points).
Instead with webpack you can import files that are not JavaScript, such as .json, and if you have an appropriate loader it will turn that into valid JavaScript which you can use just as any other JavaScript you import. So in your script.js (your entry point) you can import the JSON with:
import enJson from './en.json';
Now you can use enJson as you want, which contains the JavaScript representation of en.json. And by the way remove that from your entry, because webpack will figure out which files are used by looking what is imported from your entry point (and all its dependencies).
entry : {
en: `${config.basePaths.tmp}script.js`,
},
So some quick background on the site's current setup:
My company's site currently runs off of a CMS. All pages are generated and routed via the CMS, so there are no .html files anywhere. It's all generated via razor (.cshtml), the CMS as a backend/data-store, and routing is handled through the CMS.
If it were up to me I'd rewrite the entire thing, but I don't have that luxury. I'm doing my best to rewrite the site with a Vue.js + webpack front-end wherever possible and slowly rebuild this site over time using more modern techniques than are currently implemented.
However, I'm running into a problem setting up Webpack's dev server with our current configuration.
I think I know what the problem is, however I'm having difficulty understanding the http-proxy-middleware's configuration settings.
I believe the way I currently have everything setup, the dev server is proxying everything - therefore not picking up any changes I make to the .vue/.js files I modify (via hot reloading).
Unfortunately I HAVE to proxy the majority of the site (pages [.cshtml files], legacy scripts, various APIs, etc.), however I don't want to proxy MY .js files and .vue files (you can assume anything of mine is in /dist/ or /src/. Everything else is the old site and must be proxied via "my.server".
Additionally, I set this up as a quick test via vue cli's webpack-simple configuation - however I can also set it up via the non-simple variation if needed. I started with "-simple" to "K.I.S.S" (Keep it simple stupid) and slowly layer on the complexity as desired.
Here's my webpack.config.js file as it currently stands:
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this nessessary.
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true,
proxy: {
'/': {
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}
}
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
As far as I can tell the issue lies in the proxy:
proxy: {
'/': {
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}
}
Obviously the '/' is targeting everything, but while I can find plenty of examples of how to proxy specific sections and not anything else, I need the opposite. I need to proxy everything EXCEPT /dist/ and /src/. Any help would be greatly appreciated - and who knows, I may be way off here and this isn't even my problem.
Ultimately, though, the issue is when I run the dev server, if I setup proxying, everything on the site runs except my .vue files - if I don't proxy the server, nothing runs except my .vue files. Therefore it stands to reason the proxying simply needs to be applied to the legacy portions only and not the vue portions - but if I'm way off base, that's the ultimate issue and I'm open to solutions of any kind.
Thanks in advance for any insight anyone can provide!
webpack-dev-server allows you to configure multiple proxy configurations.
Using this style of configuring the proxy will give access to more advanced context filtering via the context option.
You can use globbing:
proxy: [{
context: ['**', '!/src/**', '!/dist/**', '!**/*.vue'],
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}]
Or you can write your own filtering logic.
proxy: [{
context: function(pathname, req) {
// exclude /src/ and /dist/
return !pathname.match("^/(src|dist)/");
},
target: {
"host": "my.server",
"protocol": 'http:',
"port": 80
},
ignorePath: false,
changeOrigin: true,
secure: false
}]
sources:
https://github.com/chimurai/http-proxy-middleware#context-matching
https://github.com/webpack/webpack-dev-server/issues/562#issuecomment-241736936
https://github.com/webpack/webpack-dev-server/blob/ee9181ca3ae40d35f8e419123423df51f2f40700/examples/proxy-hot-reload/webpack.config.js#L4
A project I'm working on is using the code splitting facility of Webpack. I'm having trouble actually getting source maps to work with it. I've used source maps successfully on other projects that don't use code splitting and wonder if this is the issue. The output from gulp task indicates that source maps are indeed being created - they just don't appear to be available in Chrome.
This is the relevant section of my gulp file.
files = globule.find(['./src/Components/*.*', '!./src/**/*-test.js']);
gulp.src(files)
.pipe(webpack({
entry: "./src/components/settings.js",
output: {
filename: 'Settings.js',
publicPath: "/admin/Content/Scripts/apps/",
chunkFilename: "[name].js"
},
module: {
loaders: [{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel-loader'
},{
test: /\.json$/,
loader: 'json-loader'
},{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader',
'css-loader')
}]
},
devtool: 'source-map',
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
alias: {
'reactuifw': process.env.NODE_ENV === 'development'
? process.env.REACT_UIFW + 'react-uifw.js' : 'react-uifw', 'react' : __dirname + '/node_modules/react'
}
},
externals: {
jquery: '$'
},
cache: true,
plugins: [new ExtractTextPlugin('bundle.css')]
}))
Any idea whats wrong?
I've never gotten proper source maps working with devtool: 'source-map'; I think maybe it's shorthand for a particular config of the SourceMapDevToolPlugin? I use the plugin explicitly instead of using the 'devtool' option, with config as described in this github issue (ignore the WebStorm stuff). The issue has to do with the sourceRoot used in the maps. Maybe give that a shot and see if you get usable maps?