Webpack replace asset for cache busting - html

I have question, might be really silly as I am a beginner with Webpack but so far impressed.
So, I have a really small personal project with Flask(Python) on the backend and React on the frontend and I'm fighting with cache busting (I mean, not now, while I'm developing no problem whatsoever with cache, but I'm worrying already for when I deploy).
I am using Webpack to bundle the js and css (right now just the js though). So I was wondering if it is possible with Webpack for me to write, say in the css, something like:
some-selector {
background: #00ff00 url("my-background.png") no-repeat fixed center;
}
or in the HTML
<script src="bundle.js"></script>
and have Webpack to replace those strings with the resource with a cache busting hash for when building for production?
like
some-selector {
background: #00ff00 url("my-background.987asdh23193jf13.png") no-repeat fixed center;
}
and
<script src="bundle.23kjbi24f92do20f.js"></script>
I saw some sutff about html-webpack-plugin or string-replace-loader but not quite what I was looking for.
So, the questions:
is it possible with Webpack?
is it possible at all?
is there a better way to do it?

Yes it is possible to do cache busting using webpack and you can use this code for that or reference is https://medium.com/#okonetchnikov/long-term-caching-of-static-assets-with-webpack-1ecb139adb95#.nctflpxl2
I never tried for images but it is also possible using webpack.
var webpack = require('webpack');
const path = require("path");
var ChunkHashReplacePlugin = require('chunkhash-replace-webpack-plugin');
var WebpackMd5Hash = require('webpack-md5-hash');
var ManifestPlugin = require('webpack-manifest-plugin');
var node_dir = __dirname + '/node_modules';
var HtmlWebpackPlugin = require('html-webpack-plugin');
var InlineManifestWebpackPlugin=require('inline-manifest-webpack-plugin');
module.exports = {
context: __dirname + '/app',
entry: {
app: './app.js',
vendor: ['angular', 'underscore', 'restangular', 'angular-ui-router', 'bootstrap', 'angular-ui-bootstrap', 'angular-animate', 'angular-sanitize']
},
output: {
path: path.join(__dirname, "js"),
filename: "[name].bundle.js"
// filename: "[name].[chunkhash].bundle.js"
},
plugins: [
function() {
this.plugin("done", function(stats) {
require("fs").writeFileSync(
path.join(__dirname, "js", "stats.json"),
JSON.stringify(stats.toJson()));
});
},
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new webpack.ProvidePlugin({
_: "underscore",
underscore: "underscore"
}),
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor"], // vendor libs + extracted manifest
minChunks: Infinity
}),
new ManifestPlugin({
filename: "chunk-manifest.json",
manifestVariable: "webpackManifest"
}),
new WebpackMd5Hash(),
new InlineManifestWebpackPlugin({
name: 'webpackManifest'
}),
new HtmlWebpackPlugin({
title: ' Portal',
template: 'index.ejs',
filename:'../index.html'
})
],
devServer: {
inline: true,
headers: { "Access-Control-Allow-Origin": "*" }
},
resolve: {
alias: {
"underscore": node_dir + "/underscore/underscore-min.js"
}
}
};
};

Related

How to load more images in fallbacks image, next-pwa

Versions
next-pwa:
next:
Question
How to load more images in fallbacks.image
for example i neeed two images into fallbacks
file - next.config.js
const withPWA = require('next-pwa');
module.exports = withPWA({
pwa: {
dest: 'public',
fallbacks: {
image: 'static/fallback.svg'
},
}
})

Spread operator not working in Object.assign()

I'm trying to use the spread operator to populate a new object from an old object, without copying the pointer of the old object. But the new object comes out empty. :(
Here's my code:
const obj = {
a: 'a',
b: 'b',
c: 'c'
};
const test1 = Object.assign({}, ...obj);
const test2 = {};
console.log('obj', obj);
console.log('test1', test1);
console.log('test2', test2);
test1 should show up in the console with the same content as obj, but it's empty.
What am I doing wrong? Is there another way of doing it, without using Object.assign()?
(Also have this in a jsbin.)
UPDATE:
I've tried:
const test = {...obj};
But I keep getting Unexpected token on the first dot of the spread. It works in JSBin, but not on my local. So I'm thinking I may have done something wonky with Webpack or Babel.
Here's my webpack.config.js:
var path = require('path');
const DEV = process.env.NODE_ENV === 'dev';
const PROD = process.env.NODE_ENV === 'prod';
module.exports = {
devtool: 'source-map',
entry: './src/index.js',
module: {
loaders: [{
test: /\.js$/,
loaders: ['babel-loader'],
exclude: /node_modules/
},{
test: /\.(png|jpg|gif)$/,
loaders: ['url-loader'],
exclude: /node_modules/
},{
test: /\.(css|sass|scss)$/,
use: ['style-loader', 'css-loader?importLoaders=2', 'sass-loader'],
// exclude: /node_modules/
},{
test: /\.(svg)$/,
use: ['file-loader'],
// exclude: /node_modules/
},
{
test: /\.(otf)(\?.*)?$/,
loader: 'url-loader?limit=10000&mimetype=application/font-sfnt'
}]
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/dist/',
filename: 'bundle.js'
}
}
And here's my .babelrc:
{
"presets": ["env", "react"]
}
When you spread an object you need to wrap it inside an object body (same goes for arrays):
const test1 = Object.assign({}, {...obj});
With that said, i don't see any benefit from combine Object.assign with the object spread.
You could just do:
const test1 = {...obj};
Or this:
const test1 = Object.assign({}, obj);
Edit
I should mention that the object spread syntax is a proposal (in stage 3) and you need the babel plugin babel-plugin-transform-object-rest-spread to support it.
Just do:
npm install --save-dev babel-plugin-transform-object-rest-spread
And add it in your .babelrc file:
{
"plugins": ["transform-object-rest-spread"]
}
The spread operator is not properly used in this case.
You just want: Object.assign({}, obj), alternatively: test1 = { ...obj }. What you are doing is more like Object.assign({}, obj.a, obj.b, obj.c);

foundation-sites 6 replacing panini for jekyll

I'm looking to extend a zurb foundation for sites 6 site and use jekyll instead of panini to render the HTML. I'm using the out of the box ZURB foundation prototype template that includes ES6 + webpack. I want foundation to handle all the SASS and JS compiling and I also want to retain the browsersync functionality. I just want to know the best approach for modifying the gulp file to integrate jekyll, this is so I can work with GitHub Pages.
Here is what the default gulp.babel.js file looks like:
'use strict';
import plugins from 'gulp-load-plugins';
import yargs from 'yargs';
import browser from 'browser-sync';
import gulp from 'gulp';
import panini from 'panini';
import rimraf from 'rimraf';
import sherpa from 'style-sherpa';
import yaml from 'js-yaml';
import fs from 'fs';
import webpackStream from 'webpack-stream';
import webpack2 from 'webpack';
import named from 'vinyl-named';
// Load all Gulp plugins into one variable
const $ = plugins();
// Check for --production flag
const PRODUCTION = !!(yargs.argv.production);
// Load settings from settings.yml
const { COMPATIBILITY, PORT, UNCSS_OPTIONS, PATHS } = loadConfig();
function loadConfig() {
let ymlFile = fs.readFileSync('config.yml', 'utf8');
return yaml.load(ymlFile);
}
// Build the "dist" folder by running all of the below tasks
gulp.task('build',
gulp.series(clean, gulp.parallel(pages, sass, javascript, images, copy), styleGuide));
// Build the site, run the server, and watch for file changes
gulp.task('default',
gulp.series('build', server, watch));
// Delete the "dist" folder
// This happens every time a build starts
function clean(done) {
rimraf(PATHS.dist, done);
}
// Copy files out of the assets folder
// This task skips over the "img", "js", and "scss" folders, which are parsed separately
function copy() {
return gulp.src(PATHS.assets)
.pipe(gulp.dest(PATHS.dist + '/assets'));
}
// Copy page templates into finished HTML files
function pages() {
return gulp.src('src/pages/**/*.{html,hbs,handlebars}')
.pipe(panini({
root: 'src/pages/',
layouts: 'src/layouts/',
partials: 'src/partials/',
data: 'src/data/',
helpers: 'src/helpers/'
}))
.pipe(gulp.dest(PATHS.dist));
}
// Load updated HTML templates and partials into Panini
function resetPages(done) {
panini.refresh();
done();
}
// Generate a style guide from the Markdown content and HTML template in styleguide/
function styleGuide(done) {
sherpa('src/styleguide/index.md', {
output: PATHS.dist + '/styleguide.html',
template: 'src/styleguide/template.html'
}, done);
}
// Compile Sass into CSS
// In production, the CSS is compressed
function sass() {
return gulp.src('src/assets/scss/app.scss')
.pipe($.sourcemaps.init())
.pipe($.sass({
includePaths: PATHS.sass
})
.on('error', $.sass.logError))
.pipe($.autoprefixer({
browsers: COMPATIBILITY
}))
// Comment in the pipe below to run UnCSS in production
//.pipe($.if(PRODUCTION, $.uncss(UNCSS_OPTIONS)))
.pipe($.if(PRODUCTION, $.cleanCss({ compatibility: 'ie9' })))
.pipe($.if(!PRODUCTION, $.sourcemaps.write()))
.pipe(gulp.dest(PATHS.dist + '/assets/css'))
.pipe(browser.reload({ stream: true }));
}
let webpackConfig = {
rules: [
{
test: /.js$/,
use: [
{
loader: 'babel-loader'
}
]
}
]
}
// Combine JavaScript into one file
// In production, the file is minified
function javascript() {
return gulp.src(PATHS.entries)
.pipe(named())
.pipe($.sourcemaps.init())
.pipe(webpackStream({module: webpackConfig}, webpack2))
.pipe($.if(PRODUCTION, $.uglify()
.on('error', e => { console.log(e); })
))
.pipe($.if(!PRODUCTION, $.sourcemaps.write()))
.pipe(gulp.dest(PATHS.dist + '/assets/js'));
}
// Copy images to the "dist" folder
// In production, the images are compressed
function images() {
return gulp.src('src/assets/img/**/*')
.pipe($.if(PRODUCTION, $.imagemin({
progressive: true
})))
.pipe(gulp.dest(PATHS.dist + '/assets/img'));
}
// Start a server with BrowserSync to preview the site in
function server(done) {
browser.init({
server: PATHS.dist, port: PORT
});
done();
}
// Reload the browser with BrowserSync
function reload(done) {
browser.reload();
done();
}
// Watch for changes to static assets, pages, Sass, and JavaScript
function watch() {
gulp.watch(PATHS.assets, copy);
gulp.watch('src/pages/**/*.html').on('all', gulp.series(pages, browser.reload));
gulp.watch('src/{layouts,partials}/**/*.html').on('all', gulp.series(resetPages, pages, browser.reload));
gulp.watch('src/assets/scss/**/*.scss').on('all', sass);
gulp.watch('src/assets/js/**/*.js').on('all', gulp.series(javascript, browser.reload));
gulp.watch('src/assets/img/**/*').on('all', gulp.series(images, browser.reload));
gulp.watch('src/styleguide/**').on('all', gulp.series(styleGuide, browser.reload));
}
I assume as part of the jekyll build/rebuild I would need to use the keep-files config setting so when jekyll clobbers the output directory file don't get overwritten.
Appreciate any help
Thanks
Jekyll is a different solution than Panini and uses Ruby
https://jekyllrb.com/docs/installation/
In general you might need some git hook or Travis config.
https://github.com/DanielRuf/testblog/blob/source/.travis.yml
https://github.com/DanielRuf/testblog/blob/source/Rakefile

Vue.js dynamic component loading + hot reload

I have Laravel 5.3.21 application with Vue.js 1.0.28
I'm using hot-reload workflow with browserify-hmr plugin.
Here is the simple gulpfile.js used to achieve that:
var elixir = require('laravel-elixir');
var gutil = require('gulp-util');
require('laravel-elixir-browserify-official');
require('laravel-elixir-vueify');
// If 'gulp watch' is run
if (gutil.env._.indexOf('watch') > -1) {
// Enable watchify for faster builds
elixir.config.js.browserify.watchify.enabled = true;
// Add the browserify HMR plugin
elixir.config.js.browserify.plugins.push({
name: 'browserify-hmr',
options: {
url: 'http://1.2.3.4:2096',
hostname: '1.2.3.4',
port: 2096
}
})
}
elixir.config.js.browserify.watchify.options.poll = true;
elixir(function (mix) {
mix.copy('node_modules/datatables.net-bs/css/dataTables.bootstrap.css',
'resources/assets/css/vendor/dataTables.bootstrap.css');
mix.styles([
'vendor/dataTables.bootstrap.css'
]);
mix.sass('app.scss');
mix.browserify('app.js');
});
I need to load components dynamically from the resources/assets/js/views/ folder, so I could make my front-end code modular and based on current route name $Laravel->routeName = request()->route()->getName() in Laravel.
For example:
// Global Settings.
Route::get('admin/settings', 'Admin#settings')
->name('admin_global_settings');
Then in resources/assets/js/views/admin/admin_global_settings.js I have code to initialize Vue.js component and register it with Vue.js instance:
var FeaturedOpportunities = require( '../../components/Featured-Opportunities.vue' );
window.Vue.component('FeaturedOpportunities', FeaturedOpportunities);
That is all nice but here is the problem in resources/assets/js/app.js:
window.Vue = require('vue');
require('vue-resource');
Vue.http.interceptors.push((request, next) => {
request.headers.set('X-CSRF-TOKEN', Laravel.csrfToken);
next();
});
// Problem is here, have to keep track of all my routes and their corresponding modules:
var routes = {
'organization_invites_roles': function () {
require('./views/organization/organization_invites_roles');
},
'admin_global_settings': function () {
require('./views/admin/admin_global_settings');
},
};
// Is there a way to load it dynamically?
if (Laravel.routeName) {
if (routes[Laravel.routeName]) {
routes[Laravel.routeName]();
}
}
new Vue({
el: 'body',
components: {
},
ready() {
console.log('Vue and Vueify all set to go!');
}
});
I've found some way that could probably solve this issue: Compiling dynamically required modules with Browserify but not sure if this applicable for my case.

Is there a way to use browserify-shim without package.json?

I need to use browserify-shim for some of my browserify dependencies, but I can't edit my package.json. I'm using browserify inside of gulp. It is possible to specify all of the package.json portion exclusibely form the API? I'm envisioning something like this:
return gulp.src('glob/path/to/my/main/js/file.js')
.pipe(browserify({
debug: false,
transform: ['browserify-shim'],
shim: {
'jquery': {
exports: 'jQuery'
}
}
}));
Then, my output with repalce var $ = require('jquery'); with var $ = jQuery;, since we are now utilizing jQuery as a global. Is this possible? Whne
You could use exposify transform in that case. browserify-shim is actially based on it and is written by the same guy.
E.g.:
return browserify('glob/path/to/my/main/js/file.js', { debug: false })
.transform('exposify', { expose: {'jquery': 'jQuery' }})
gulpfile.js
gulp = require('gulp')
browserify = require('gulp-browserify')
gulp.task('browserify', function(){
var src = 'test.js'
gulp.src(src)
.pipe(browserify({
shim: {
jQuery: {
path: './bowser_components/jquery/dist/jquery.min.js',
exports: '$'
}
}
}))
.pipe(gulp.dest('./build/js'))
})
test.js
$ = require('jQuery')
console.log($);