Minify JSON and copy the result to file using Webpack? - json

I have a couple of language files that I just copy to a location on disk, and I need to continue to do so for now.
The problem is that they're not minified and I would like to do so using WebPack 3.X as this is what we use... :)
Something like https://www.npmjs.com/package/grunt-jsonmin but without the grunt part.
What I have:
Uncompressed JSON in src/lang/*.json
What I want:
Compressed JSON in dist/lang/*.json
/J

This is kind of old, but if anyone is still pondering, here's how I did it:
// npm i -D node-json-minify copy-webpack-plugin
//webpack.config.js
const JSONMinifyPlugin = require('node-json-minify'),
CopyWebpackPlugin = require('copy-webpack-plugin');
options.plugins = [
new CopyWebpackPlugin([
{
/* i18n */
from: path.join(__dirname, 'src', '_locales'),
transform: function(content) {
// minify json
return JSONMinifyPlugin(content.toString());
},
to: path.join(__dirname, 'build', '_locales')
}
])
]

In webpack 5 you can use JsonMinimizerWebpackPlugin.
It works for both rules and CopyPlugin.
const JsonMinimizerPlugin = require("json-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.json$/i,
type: "asset/resource",
},
],
},
plugins: [
new CopyPlugin({
patterns: [
{
context: path.resolve(__dirname, "dist"),
from: "./src/*.json",
},
],
}),
],
optimization: {
minimize: true,
minimizer: [
// For webpack#5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
// `...`
new JsonMinimizerPlugin(),
],
},
};

Related

Webpack 3.9.1 - How do I combine LESS files into one CSS file?

I'm very new to Webpack and I'm not certain how to handle LESS. I want to have many LESS files and I want them to compile into one CSS file after I run npm run build. This would result in a style.css file which includes everything.
My webpack.config.js looks like this:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules:
[
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.less$/,
use: [{
loader: "style-loader", // creates style nodes from JS strings
path: path.resolve(__dirname, 'src')
}, {
loader: "css-loader", // translates CSS into CommonJS
path: path.resolve(__dirname, 'src')
}]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
plugins: [new HtmlWebpackPlugin()]
};
How exactly do I configure webpack to make it combine all LESS files into one CSS file?
You can use a plugin called extract-text-webpack-plugin to achieve this. According to their documentation, this plugin moves all the required *.css modules in entry chunks into a separate CSS file. So your styles are no longer inlined into the JS bundle, but in a separate CSS file (styles.css). Now of course, in your case, you will first have to parse your .less files to .css and then bundle them up into a single file.
You can modify your webpack config like so:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({ <---- Use the plugin here to extract the styles
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin(),
new ExtractTextPlugin("styles.css"),
]};
You can use extract-text-webpack-plugin to make one css file. But only do this for a production build not while you are developing.
I would look at using the Webpack less-loader. It covers a production build here

Why webpack doesn't render CSS from components to vendor.css file?

I use this template It works well. As you can see on the screen, all lybrarys (like bootstrap) render their CSS into vendor.css, but my component renders it into html directly, just into the header part in the html file in tag. Can you tell me how to configure it right?
// webpack.config.js
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');
var merge = require('webpack-merge');
var allFilenamesExceptJavaScript = /\.(?!js(\?|$))([^.]+(\?|$))/;
//var ExtractTextPlugin = require('extract-text-webpack-plugin');
// Configuration in common to both client-side and server-side bundles
var sharedConfig = {
resolve: { extensions: ['', '.js', '.ts'] },
output: {
filename: '[name].js',
publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
loaders: [
{ test: /\.ts$/, include: /ClientApp/, loader: 'ts', query: { silent: true } },
{ test: /\.html$/, loader: 'raw' },
{ test: /\.css$/, loader: 'to-string!css' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url', query: { limit: 25000 } },
{ test: /\.(jpg1)$/, loader: 'file?name=[name].[ext]' }
]
}
};
// Configuration for client-side bundle suitable for running in browsers
var clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot-client.ts' },
output: { path: path.join(__dirname, './wwwroot/dist') },
devtool: isDevBuild ? 'inline-source-map' : null,
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin()
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
var serverBundleConfig = merge(sharedConfig, {
entry: { 'main-server': './ClientApp/boot-server.ts' },
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map',
externals: [nodeExternals({ whitelist: [allFilenamesExceptJavaScript] })] // Don't bundle .js files from node_modules
});
module.exports = [clientBundleConfig, serverBundleConfig];
and
// webpack.config.vendor.js
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractCSS = new ExtractTextPlugin('vendor.css');
module.exports = {
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [
{ test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, loader: 'url-loader?limit=100000' },
{ test: /\.css(\?|$)/, loader: extractCSS.extract(['css']) }
]
},
entry: {
vendor: [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router',
'#angular/platform-server',
'angular2-universal',
'angular2-universal-polyfills',
'bootstrap',
'bootstrap/dist/css/bootstrap.css',
'es6-shim',
'es6-promise',
'jquery',
'zone.js',
'angular2-modal'
]
},
output: {
path: path.join(__dirname, 'wwwroot', 'dist'),
filename: '[name].js',
library: '[name]_[hash]',
},
plugins: [
extractCSS,
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DllPlugin({
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } })
])
};
It seems like you are using style-loader to load your component css. You can change it to be the same loader (most likely file-loader) as the vendor.css in your webpack.config
If you compare the two css loaders in your config files, you can see that webpack.config.vendor.js has this line:
{ test: /\.css(\?|$)/, loader: extractCSS.extract(['css']) }
under loaders. That is the line that takes the CSS and puts it in its own file. So if you change the CSS loader for your webpack.config.js and make sure to add:
var extractCSS = new ExtractTextPlugin('styles.css'); // or name it whatever you want
at the top of the file. It should work.

Raw loader with ES6 imports

I'm trying to use ES6 with webpack. Its okay for javascript module imports/exports, but I can't get raw-loader to work.
Here is what I am intending to do in my source file
import template from './template.html'
The template.html file has raw HTML in it.
module.exports = {
context: __dirname,
entry: [
'babel-polyfill',
'./app/app.js',
],
module: {
preLoaders: [
{
test: /\.js$/,
include: __dirname + '/app/',
loader: 'eslint-loader',
},
],
loaders: [
{
test: /\.js$/,
include: __dirname + '/app/',
loader: 'babel-loader?presets[]=es2015',
},
{
test: /\.html$/,
include: __dirname + '/app/',
loader: 'raw-loader',
},
],
},
output: {
path: './build/',
filename: 'app.js',
},
};
When I launch webpack, the code is generated as so:
module.exports = "module.exports = \" hello\\n <div>\\n <ul>\\n <li ng-repeat...
It should only be the "hello\n <div>..." string that should be exported.
Any help on this ? I really don't understand how to do this.
Import with raw-loader returns object with default property (import * as template from './file'). You can call it template.default to get what you want.
Here was the similar issue
And here you cant give a glance the way how you can update code of raw loader to use imported value as it is. Just have tinkered with this for a while

WebPack Cache busting hash in file names never changes

I am trying to get cache busting in my gulp file output to work. Currently it outputs a file like this: main.2d06434c1c57525870ac-e7615836.js but whenever I modify typescript files and rebuild the hash in the file name output is always the same.
I have tried the built in webpack hashing and the gulp vinyl-named hashing to see if there was something wrong with one of their configurations but again their output filename is the same on each rebuild.
Here is the related part of my builder task. Thanks!
var packer = gulp.src(['./src/basePolyfills.ts', './src/external.ts', './src/main.ts'])
.pipe(named())
.pipe(webpack({
output: { filename: '[name].[hash].js' },
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts' },
{ test: /\.html$/, loader: 'html' }
]
},
resolve: { extensions: ['', '.js', '.ts'] }
}))
.pipe(hash())
.pipe(gulp.dest('./wwwroot/js/'));
Where is your hash() coming from? As far as I know, webpack automatically calculates chunkhashes. Be aware that there is a difference between "hash" and "chunkhash". chunkhash is a hash per chunk, whereas "hash" seems to be a hash over all files.
Can you try:
var packer = gulp.src(['./src/basePolyfills.ts', './src/external.ts', './src/main.ts'])
.pipe(named())
.pipe(webpack({
output: { filename: '[name].[chunkhash].js' },
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts' },
{ test: /\.html$/, loader: 'html' }
]
},
resolve: { extensions: ['', '.js', '.ts'] }
}))
.pipe(gulp.dest('./wwwroot/js/'));

Configure wallaby for React-redux-es6-typescript-immutable applications

How to configure wallaby for React-redux-es6-typescript-immutable application. I use webstorm editor. My base code is committed here
I tried the following code in wallaby.js, but it throws
ReferenceError: Can't find variable: exports
at src/store.ts:3
module.exports = function (wallaby) {
return {
files: [
'src/*.ts'
],
tests: [
'test/*Spec.ts'
],
compilers: {
'**/*.ts': wallaby.compilers.typeScript({
module: 5, // ES6
target: 2 // ES6
})
},
preprocessors: {
'**/*.js': file => require('babel-core').transform(
file.content,
{sourceMap: true, presets: ['es2015']})
}
}
}
I have more or less the same setup as you. Did you try setting the env variable to node?
My working wallaby.js config file for babel 6 is the following:
module.exports = function() {
return {
files: [
{pattern: "src/**/*.js*"}
],
tests: [
{pattern: "tests/integration/*.js"}
],
env: {
type: "node"
},
preprocessors: {
"**/*.js": file => require("babel-core").transform(file.content, {sourceMap: true, presets: ["es2015"]})
}
};
};