Skip to content

Instantly share code, notes, and snippets.

@adamay000
Created October 18, 2018 09:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamay000/a52c9bac7070ec3b61a9623c5efaa55c to your computer and use it in GitHub Desktop.
Save adamay000/a52c9bac7070ec3b61a9623c5efaa55c to your computer and use it in GitHub Desktop.
css hot reload with webpack-dev-server
var url = require('url');
var socket = require('webpack-dev-server/client/socket');
function getCurrentScriptSource() {
// `document.currentScript` is the most accurate way to find the current script,
// but is not supported in all browsers.
if (document.currentScript) {
return document.currentScript.getAttribute('src');
}
// Fall back to getting all scripts in the document.
var scriptElements = document.scripts || [];
var currentScript = scriptElements[scriptElements.length - 1];
if (currentScript) {
return currentScript.getAttribute('src');
}
// Fail as there was no script to use.
throw new Error('[WDS] Failed to get current script source.');
}
// Send messages to the outside, so plugins can consume it.
function sendMsg(type, data) {
if (typeof self !== 'undefined' && (typeof WorkerGlobalScope === 'undefined' || !(self instanceof WorkerGlobalScope))) {
self.postMessage({
type: 'webpack' + type,
data: data
}, '*');
}
}
var urlParts = void 0;
if (typeof __resourceQuery === 'string' && __resourceQuery) {
// If this bundle is inlined, use the resource query to get the correct url.
urlParts = url.parse(__resourceQuery.substr(1));
} else {
// Else, get the url from the <script> this file was called with.
var scriptHost = getCurrentScriptSource();
// eslint-disable-next-line no-useless-escape
scriptHost = scriptHost.replace(/\/[^\/]+$/, '');
urlParts = url.parse(scriptHost || '/', false, true);
}
var hostname = urlParts.hostname;
var protocol = urlParts.protocol;
// check ipv4 and ipv6 `all hostname`
if (hostname === '0.0.0.0' || hostname === '::') {
// why do we need this check?
// hostname n/a for file protocol (example, when using electron, ionic)
// see: https://github.com/webpack/webpack-dev-server/pull/384
// eslint-disable-next-line no-bitwise
if (self.location.hostname && !!~self.location.protocol.indexOf('http')) {
hostname = self.location.hostname;
}
}
// `hostname` can be empty when the script path is relative. In that case, specifying
// a protocol would result in an invalid URL.
// When https is used in the app, secure websockets are always necessary
// because the browser doesn't accept non-secure websockets.
if (hostname && (self.location.protocol === 'https:' || urlParts.hostname === '0.0.0.0')) {
protocol = self.location.protocol;
}
var socketUrl = url.format({
protocol: protocol,
auth: urlParts.auth,
hostname: hostname,
port: urlParts.port,
pathname: urlParts.path == null || urlParts.path === '/' ? '/sockjs-node' : urlParts.path
});
socket(socketUrl, {
'css-changed': function cssChanged() {
var $links = document.querySelectorAll('link');
$links.forEach(function ($link) {
var next$Link = $link.cloneNode();
next$Link.href = $link.href + '';
next$Link.addEventListener('load', function () {
$link.parentNode.removeChild($link);
});
$link.parentNode.insertBefore(next$Link, $link.nextSibling);
});
},
close: function close() {
sendMsg('Close');
}
});
const webpack = require('webpack');
const chokidar = require('chokidar');
const WebpackDevServer = require('webpack-dev-server');
const webpackConfig = require('./webpack.config.dev');
startDevServer(webpackConfig);
function startDevServer(webpackOptions) {
const compiler = webpack(webpackOptions);
Object.keys(webpackOptions.entry).forEach((entryName) => {
webpackOptions.entry[entryName].push('./devserver.css.client.js?http://localhost:8901/sockjs-node');
});
const server = new WebpackDevServer(compiler, webpackOptions.devServer);
server.listen(webpackOptions.devServer.port, webpackOptions.devServer.host, () => {
const options = {
ignoreInitial: true,
persistent: true,
followSymlinks: false,
depth: 99,
atomic: false,
alwaysStat: true,
ignorePermissionErrors: true,
ignored: server.watchOptions.ignored,
usePolling: server.watchOptions.poll ? true : undefined,
interval: typeof server.watchOptions.poll === 'number' ? server.watchOptions.poll : undefined
};
chokidar.watch('./.tmp', options).on('change', (changed) => {
if (/\.css$/.test(changed)) {
server.sockWrite(server.sockets, 'css-changed');
} else {
server.sockWrite(server.sockets, 'content-changed');
}
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment