| @@ -0,0 +1,27 @@ | ||
| build: 'off' | ||
|
|
||
| init: | ||
| - git config --global core.autocrlf input | ||
|
|
||
| environment: | ||
| matrix: | ||
| - nodejs_version: '10' | ||
| webpack_version: latest | ||
| - nodejs_version: '8' | ||
| webpack_version: latest | ||
| - nodejs_version: '6' | ||
| webpack_version: latest | ||
|
|
||
| matrix: | ||
| fast_finish: true | ||
|
|
||
| install: | ||
| - ps: Install-Product node $env:nodejs_version x64 | ||
| - npm i -g npm@latest | ||
| - npm i | ||
|
|
||
| before_test: | ||
| - cmd: npm i webpack@%webpack_version% | ||
|
|
||
| test_script: | ||
| - cmd: npm t |
| @@ -0,0 +1,166 @@ | ||
| 'use strict'; | ||
|
|
||
| /* eslint-disable | ||
| global-require, | ||
| multiline-ternary, | ||
| space-before-function-paren | ||
| */ | ||
| const ADVANCED_GROUP = 'Advanced options:'; | ||
| const DISPLAY_GROUP = 'Stats options:'; | ||
| const SSL_GROUP = 'SSL options:'; | ||
| const CONNECTION_GROUP = 'Connection options:'; | ||
| const RESPONSE_GROUP = 'Response options:'; | ||
| const BASIC_GROUP = 'Basic options:'; | ||
|
|
||
| const options = { | ||
| bonjour: { | ||
| type: 'boolean', | ||
| describe: 'Broadcasts the server via ZeroConf networking on start' | ||
| }, | ||
| lazy: { | ||
| type: 'boolean', | ||
| describe: 'Lazy' | ||
| }, | ||
| inline: { | ||
| type: 'boolean', | ||
| default: true, | ||
| describe: 'Inline mode (set to false to disable including client scripts like livereload)' | ||
| }, | ||
| progress: { | ||
| type: 'boolean', | ||
| describe: 'Print compilation progress in percentage', | ||
| group: BASIC_GROUP | ||
| }, | ||
| 'hot-only': { | ||
| type: 'boolean', | ||
| describe: 'Do not refresh page if HMR fails', | ||
| group: ADVANCED_GROUP | ||
| }, | ||
| stdin: { | ||
| type: 'boolean', | ||
| describe: 'close when stdin ends' | ||
| }, | ||
| open: { | ||
| type: 'string', | ||
| describe: 'Open the default browser, or optionally specify a browser name' | ||
| }, | ||
| useLocalIp: { | ||
| type: 'boolean', | ||
| describe: 'Open default browser with local IP' | ||
| }, | ||
| 'open-page': { | ||
| type: 'string', | ||
| describe: 'Open default browser with the specified page', | ||
| requiresArg: true | ||
| }, | ||
| color: { | ||
| type: 'boolean', | ||
| alias: 'colors', | ||
| default: function supportsColor() { | ||
| // Use `require('supports-color').stdout` for supports-color >= 5.0.0. | ||
| // See https://github.com/webpack/webpack-dev-server/pull/1555. | ||
| return require('supports-color').stdout; | ||
| }, | ||
| group: DISPLAY_GROUP, | ||
| describe: 'Enables/Disables colors on the console' | ||
| }, | ||
| info: { | ||
| type: 'boolean', | ||
| group: DISPLAY_GROUP, | ||
| default: true, | ||
| describe: 'Info' | ||
| }, | ||
| quiet: { | ||
| type: 'boolean', | ||
| group: DISPLAY_GROUP, | ||
| describe: 'Quiet' | ||
| }, | ||
| 'client-log-level': { | ||
| type: 'string', | ||
| group: DISPLAY_GROUP, | ||
| default: 'info', | ||
| describe: 'Log level in the browser (info, warning, error or none)' | ||
| }, | ||
| https: { | ||
| type: 'boolean', | ||
| group: SSL_GROUP, | ||
| describe: 'HTTPS' | ||
| }, | ||
| key: { | ||
| type: 'string', | ||
| describe: 'Path to a SSL key.', | ||
| group: SSL_GROUP | ||
| }, | ||
| cert: { | ||
| type: 'string', | ||
| describe: 'Path to a SSL certificate.', | ||
| group: SSL_GROUP | ||
| }, | ||
| cacert: { | ||
| type: 'string', | ||
| describe: 'Path to a SSL CA certificate.', | ||
| group: SSL_GROUP | ||
| }, | ||
| pfx: { | ||
| type: 'string', | ||
| describe: 'Path to a SSL pfx file.', | ||
| group: SSL_GROUP | ||
| }, | ||
| 'pfx-passphrase': { | ||
| type: 'string', | ||
| describe: 'Passphrase for pfx file.', | ||
| group: SSL_GROUP | ||
| }, | ||
| 'content-base': { | ||
| type: 'string', | ||
| describe: 'A directory or URL to serve HTML content from.', | ||
| group: RESPONSE_GROUP | ||
| }, | ||
| 'watch-content-base': { | ||
| type: 'boolean', | ||
| describe: 'Enable live-reloading of the content-base.', | ||
| group: RESPONSE_GROUP | ||
| }, | ||
| 'history-api-fallback': { | ||
| type: 'boolean', | ||
| describe: 'Fallback to /index.html for Single Page Applications.', | ||
| group: RESPONSE_GROUP | ||
| }, | ||
| compress: { | ||
| type: 'boolean', | ||
| describe: 'Enable gzip compression', | ||
| group: RESPONSE_GROUP | ||
| }, | ||
| port: { | ||
| describe: 'The port', | ||
| group: CONNECTION_GROUP | ||
| }, | ||
| 'disable-host-check': { | ||
| type: 'boolean', | ||
| describe: 'Will not check the host', | ||
| group: CONNECTION_GROUP | ||
| }, | ||
| socket: { | ||
| type: 'String', | ||
| describe: 'Socket to listen', | ||
| group: CONNECTION_GROUP | ||
| }, | ||
| public: { | ||
| type: 'string', | ||
| describe: 'The public hostname/ip address of the server', | ||
| group: CONNECTION_GROUP | ||
| }, | ||
| host: { | ||
| type: 'string', | ||
| default: 'localhost', | ||
| describe: 'The hostname/ip address the server will bind to', | ||
| group: CONNECTION_GROUP | ||
| }, | ||
| 'allowed-hosts': { | ||
| type: 'string', | ||
| describe: 'A comma-delimited string of hosts that are allowed to access the dev server', | ||
| group: CONNECTION_GROUP | ||
| } | ||
| }; | ||
|
|
||
| module.exports = options; |
| @@ -0,0 +1,114 @@ | ||
| 'use strict'; | ||
|
|
||
| /* eslint-disable | ||
| no-shadow, | ||
| global-require, | ||
| multiline-ternary, | ||
| array-bracket-spacing, | ||
| space-before-function-paren | ||
| */ | ||
| const open = require('opn'); | ||
|
|
||
| const colors = { | ||
| info (useColor, msg) { | ||
| if (useColor) { | ||
| // Make text blue and bold, so it *pops* | ||
| return `\u001b[1m\u001b[34m${msg}\u001b[39m\u001b[22m`; | ||
| } | ||
|
|
||
| return msg; | ||
| }, | ||
| error (useColor, msg) { | ||
| if (useColor) { | ||
| // Make text red and bold, so it *pops* | ||
| return `\u001b[1m\u001b[31m${msg}\u001b[39m\u001b[22m`; | ||
| } | ||
|
|
||
| return msg; | ||
| } | ||
| }; | ||
|
|
||
| // eslint-disable-next-line | ||
| const defaultTo = (value, def) => { | ||
| return value == null ? def : value; | ||
| }; | ||
|
|
||
| function version () { | ||
| return `webpack-dev-server ${require('../package.json').version}\n` + | ||
| `webpack ${require('webpack/package.json').version}`; | ||
| } | ||
|
|
||
| function status (uri, options, log, useColor) { | ||
| const contentBase = Array.isArray(options.contentBase) | ||
| ? options.contentBase.join(', ') | ||
| : options.contentBase; | ||
|
|
||
| if (options.socket) { | ||
| log.info(`Listening to socket at ${colors.info(useColor, options.socket)}`); | ||
| } else { | ||
| log.info(`Project is running at ${colors.info(useColor, uri)}`); | ||
| } | ||
|
|
||
| log.info( | ||
| `webpack output is served from ${colors.info(useColor, options.publicPath)}` | ||
| ); | ||
|
|
||
| if (contentBase) { | ||
| log.info( | ||
| `Content not from webpack is served from ${colors.info(useColor, contentBase)}` | ||
| ); | ||
| } | ||
|
|
||
| if (options.historyApiFallback) { | ||
| log.info( | ||
| `404s will fallback to ${colors.info(useColor, options.historyApiFallback.index || '/index.html')}` | ||
| ); | ||
| } | ||
|
|
||
| if (options.bonjour) { | ||
| log.info( | ||
| 'Broadcasting "http" with subtype of "webpack" via ZeroConf DNS (Bonjour)' | ||
| ); | ||
| } | ||
|
|
||
| if (options.open) { | ||
| let openOptions = {}; | ||
| let openMessage = 'Unable to open browser'; | ||
|
|
||
| if (typeof options.open === 'string') { | ||
| openOptions = { app: options.open }; | ||
| openMessage += `: ${options.open}`; | ||
| } | ||
|
|
||
| open(uri + (options.openPage || ''), openOptions).catch(() => { | ||
| log.warn( | ||
| `${openMessage}. If you are running in a headless environment, please do not use the --open flag` | ||
| ); | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| function bonjour (options) { | ||
| const bonjour = require('bonjour')(); | ||
|
|
||
| bonjour.publish({ | ||
| name: 'Webpack Dev Server', | ||
| port: options.port, | ||
| type: 'http', | ||
| subtypes: [ 'webpack' ] | ||
| }); | ||
|
|
||
| process.on('exit', () => { | ||
| bonjour.unpublishAll(() => { | ||
| bonjour.destroy(); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| module.exports = { | ||
| status, | ||
| colors, | ||
| version, | ||
| bonjour, | ||
| defaultTo | ||
| }; |
| @@ -0,0 +1,244 @@ | ||
| 'use strict'; | ||
|
|
||
| /* global __resourceQuery WorkerGlobalScope self */ | ||
| /* eslint prefer-destructuring: off */ | ||
|
|
||
| const url = require('url'); | ||
| const stripAnsi = require('strip-ansi'); | ||
| const log = require('loglevel').getLogger('webpack-dev-server'); | ||
| const socket = require('./socket'); | ||
| const overlay = require('./overlay'); | ||
|
|
||
| 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. | ||
| const scriptElements = document.scripts || []; | ||
| const 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.'); | ||
| } | ||
|
|
||
| let urlParts; | ||
| let hotReload = true; | ||
| if (typeof window !== 'undefined') { | ||
| const qs = window.location.search.toLowerCase(); | ||
| hotReload = qs.indexOf('hotreload=false') === -1; | ||
| } | ||
| 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. | ||
| let scriptHost = getCurrentScriptSource(); | ||
| // eslint-disable-next-line no-useless-escape | ||
| scriptHost = scriptHost.replace(/\/[^\/]+$/, ''); | ||
| urlParts = url.parse((scriptHost || '/'), false, true); | ||
| } | ||
|
|
||
| if (!urlParts.port || urlParts.port === '0') { | ||
| urlParts.port = self.location.port; | ||
| } | ||
|
|
||
| let hot = false; | ||
| let initial = true; | ||
| let currentHash = ''; | ||
| let useWarningOverlay = false; | ||
| let useErrorOverlay = false; | ||
| let useProgress = false; | ||
|
|
||
| const INFO = 'info'; | ||
| const WARNING = 'warning'; | ||
| const ERROR = 'error'; | ||
| const NONE = 'none'; | ||
|
|
||
| // Set the default log level | ||
| log.setDefaultLevel(INFO); | ||
|
|
||
| // 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 | ||
| }, '*'); | ||
| } | ||
| } | ||
|
|
||
| const onSocketMsg = { | ||
| hot() { | ||
| hot = true; | ||
| log.info('[WDS] Hot Module Replacement enabled.'); | ||
| }, | ||
| invalid() { | ||
| log.info('[WDS] App updated. Recompiling...'); | ||
| // fixes #1042. overlay doesn't clear if errors are fixed but warnings remain. | ||
| if (useWarningOverlay || useErrorOverlay) overlay.clear(); | ||
| sendMsg('Invalid'); | ||
| }, | ||
| hash(hash) { | ||
| currentHash = hash; | ||
| }, | ||
| 'still-ok': function stillOk() { | ||
| log.info('[WDS] Nothing changed.'); | ||
| if (useWarningOverlay || useErrorOverlay) overlay.clear(); | ||
| sendMsg('StillOk'); | ||
| }, | ||
| 'log-level': function logLevel(level) { | ||
| const hotCtx = require.context('webpack/hot', false, /^\.\/log$/); | ||
| if (hotCtx.keys().indexOf('./log') !== -1) { | ||
| hotCtx('./log').setLogLevel(level); | ||
| } | ||
| switch (level) { | ||
| case INFO: | ||
| case ERROR: | ||
| log.setLevel(level); | ||
| break; | ||
| case WARNING: | ||
| // loglevel's warning name is different from webpack's | ||
| log.setLevel('warn'); | ||
| break; | ||
| case NONE: | ||
| log.disableAll(); | ||
| break; | ||
| default: | ||
| log.error(`[WDS] Unknown clientLogLevel '${level}'`); | ||
| } | ||
| }, | ||
| overlay(value) { | ||
| if (typeof document !== 'undefined') { | ||
| if (typeof (value) === 'boolean') { | ||
| useWarningOverlay = false; | ||
| useErrorOverlay = value; | ||
| } else if (value) { | ||
| useWarningOverlay = value.warnings; | ||
| useErrorOverlay = value.errors; | ||
| } | ||
| } | ||
| }, | ||
| progress(progress) { | ||
| if (typeof document !== 'undefined') { | ||
| useProgress = progress; | ||
| } | ||
| }, | ||
| 'progress-update': function progressUpdate(data) { | ||
| if (useProgress) log.info(`[WDS] ${data.percent}% - ${data.msg}.`); | ||
| sendMsg('Progress', data); | ||
| }, | ||
| ok() { | ||
| sendMsg('Ok'); | ||
| if (useWarningOverlay || useErrorOverlay) overlay.clear(); | ||
| if (initial) return initial = false; // eslint-disable-line no-return-assign | ||
| reloadApp(); | ||
| }, | ||
| 'content-changed': function contentChanged() { | ||
| log.info('[WDS] Content base changed. Reloading...'); | ||
| self.location.reload(); | ||
| }, | ||
| warnings(warnings) { | ||
| log.warn('[WDS] Warnings while compiling.'); | ||
| const strippedWarnings = warnings.map(warning => stripAnsi(warning)); | ||
| sendMsg('Warnings', strippedWarnings); | ||
| for (let i = 0; i < strippedWarnings.length; i++) { log.warn(strippedWarnings[i]); } | ||
| if (useWarningOverlay) overlay.showMessage(warnings); | ||
|
|
||
| if (initial) return initial = false; // eslint-disable-line no-return-assign | ||
| reloadApp(); | ||
| }, | ||
| errors(errors) { | ||
| log.error('[WDS] Errors while compiling. Reload prevented.'); | ||
| const strippedErrors = errors.map(error => stripAnsi(error)); | ||
| sendMsg('Errors', strippedErrors); | ||
| for (let i = 0; i < strippedErrors.length; i++) { log.error(strippedErrors[i]); } | ||
| if (useErrorOverlay) overlay.showMessage(errors); | ||
| initial = false; | ||
| }, | ||
| error(error) { | ||
| log.error(error); | ||
| }, | ||
| close() { | ||
| log.error('[WDS] Disconnected!'); | ||
| sendMsg('Close'); | ||
| } | ||
| }; | ||
|
|
||
| let hostname = urlParts.hostname; | ||
| let 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; | ||
| } | ||
|
|
||
| const socketUrl = url.format({ | ||
| protocol, | ||
| auth: urlParts.auth, | ||
| hostname, | ||
| port: urlParts.port, | ||
| pathname: urlParts.path == null || urlParts.path === '/' ? '/sockjs-node' : urlParts.path | ||
| }); | ||
|
|
||
| socket(socketUrl, onSocketMsg); | ||
|
|
||
| let isUnloading = false; | ||
| self.addEventListener('beforeunload', () => { | ||
| isUnloading = true; | ||
| }); | ||
|
|
||
| function reloadApp() { | ||
| if (isUnloading || !hotReload) { | ||
| return; | ||
| } | ||
| if (hot) { | ||
| log.info('[WDS] App hot update...'); | ||
| // eslint-disable-next-line global-require | ||
| const hotEmitter = require('webpack/hot/emitter'); | ||
| hotEmitter.emit('webpackHotUpdate', currentHash); | ||
| if (typeof self !== 'undefined' && self.window) { | ||
| // broadcast update to window | ||
| self.postMessage(`webpackHotUpdate${currentHash}`, '*'); | ||
| } | ||
| } else { | ||
| let rootWindow = self; | ||
| // use parent window for reload (in case we're in an iframe with no valid src) | ||
| const intervalId = self.setInterval(() => { | ||
| if (rootWindow.location.protocol !== 'about:') { | ||
| // reload immediately if protocol is valid | ||
| applyReload(rootWindow, intervalId); | ||
| } else { | ||
| rootWindow = rootWindow.parent; | ||
| if (rootWindow.parent === rootWindow) { | ||
| // if parent equals current window we've reached the root which would continue forever, so trigger a reload anyways | ||
| applyReload(rootWindow, intervalId); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| function applyReload(rootWindow, intervalId) { | ||
| clearInterval(intervalId); | ||
| log.info('[WDS] App updated. Reloading...'); | ||
| rootWindow.location.reload(); | ||
| } | ||
| } |
| @@ -0,0 +1,129 @@ | ||
| 'use strict'; | ||
|
|
||
| // The error overlay is inspired (and mostly copied) from Create React App (https://github.com/facebookincubator/create-react-app) | ||
| // They, in turn, got inspired by webpack-hot-middleware (https://github.com/glenjamin/webpack-hot-middleware). | ||
|
|
||
| const ansiHTML = require('ansi-html'); | ||
| const Entities = require('html-entities').AllHtmlEntities; | ||
|
|
||
| const entities = new Entities(); | ||
|
|
||
| const colors = { | ||
| reset: ['transparent', 'transparent'], | ||
| black: '181818', | ||
| red: 'E36049', | ||
| green: 'B3CB74', | ||
| yellow: 'FFD080', | ||
| blue: '7CAFC2', | ||
| magenta: '7FACCA', | ||
| cyan: 'C3C2EF', | ||
| lightgrey: 'EBE7E3', | ||
| darkgrey: '6D7891' | ||
| }; | ||
| ansiHTML.setColors(colors); | ||
|
|
||
| function createOverlayIframe(onIframeLoad) { | ||
| const iframe = document.createElement('iframe'); | ||
| iframe.id = 'webpack-dev-server-client-overlay'; | ||
| iframe.src = 'about:blank'; | ||
| iframe.style.position = 'fixed'; | ||
| iframe.style.left = 0; | ||
| iframe.style.top = 0; | ||
| iframe.style.right = 0; | ||
| iframe.style.bottom = 0; | ||
| iframe.style.width = '100vw'; | ||
| iframe.style.height = '100vh'; | ||
| iframe.style.border = 'none'; | ||
| iframe.style.zIndex = 9999999999; | ||
| iframe.onload = onIframeLoad; | ||
| return iframe; | ||
| } | ||
|
|
||
| function addOverlayDivTo(iframe) { | ||
| const div = iframe.contentDocument.createElement('div'); | ||
| div.id = 'webpack-dev-server-client-overlay-div'; | ||
| div.style.position = 'fixed'; | ||
| div.style.boxSizing = 'border-box'; | ||
| div.style.left = 0; | ||
| div.style.top = 0; | ||
| div.style.right = 0; | ||
| div.style.bottom = 0; | ||
| div.style.width = '100vw'; | ||
| div.style.height = '100vh'; | ||
| div.style.backgroundColor = 'rgba(0, 0, 0, 0.85)'; | ||
| div.style.color = '#E8E8E8'; | ||
| div.style.fontFamily = 'Menlo, Consolas, monospace'; | ||
| div.style.fontSize = 'large'; | ||
| div.style.padding = '2rem'; | ||
| div.style.lineHeight = '1.2'; | ||
| div.style.whiteSpace = 'pre-wrap'; | ||
| div.style.overflow = 'auto'; | ||
| iframe.contentDocument.body.appendChild(div); | ||
| return div; | ||
| } | ||
|
|
||
| let overlayIframe = null; | ||
| let overlayDiv = null; | ||
| let lastOnOverlayDivReady = null; | ||
|
|
||
| function ensureOverlayDivExists(onOverlayDivReady) { | ||
| if (overlayDiv) { | ||
| // Everything is ready, call the callback right away. | ||
| onOverlayDivReady(overlayDiv); | ||
| return; | ||
| } | ||
|
|
||
| // Creating an iframe may be asynchronous so we'll schedule the callback. | ||
| // In case of multiple calls, last callback wins. | ||
| lastOnOverlayDivReady = onOverlayDivReady; | ||
|
|
||
| if (overlayIframe) { | ||
| // We're already creating it. | ||
| return; | ||
| } | ||
|
|
||
| // Create iframe and, when it is ready, a div inside it. | ||
| overlayIframe = createOverlayIframe(() => { | ||
| overlayDiv = addOverlayDivTo(overlayIframe); | ||
| // Now we can talk! | ||
| lastOnOverlayDivReady(overlayDiv); | ||
| }); | ||
|
|
||
| // Zalgo alert: onIframeLoad() will be called either synchronously | ||
| // or asynchronously depending on the browser. | ||
| // We delay adding it so `overlayIframe` is set when `onIframeLoad` fires. | ||
| document.body.appendChild(overlayIframe); | ||
| } | ||
|
|
||
| function showMessageOverlay(message) { | ||
| ensureOverlayDivExists((div) => { | ||
| // Make it look similar to our terminal. | ||
| div.innerHTML = `<span style="color: #${ | ||
| colors.red | ||
| }">Failed to compile.</span><br><br>${ | ||
| ansiHTML(entities.encode(message))}`; | ||
| }); | ||
| } | ||
|
|
||
| function destroyErrorOverlay() { | ||
| if (!overlayDiv) { | ||
| // It is not there in the first place. | ||
| return; | ||
| } | ||
|
|
||
| // Clean up and reset internal state. | ||
| document.body.removeChild(overlayIframe); | ||
| overlayDiv = null; | ||
| overlayIframe = null; | ||
| lastOnOverlayDivReady = null; | ||
| } | ||
|
|
||
| // Successful compilation. | ||
| exports.clear = function handleSuccess() { | ||
| destroyErrorOverlay(); | ||
| }; | ||
|
|
||
| // Compilation with errors (e.g. syntax error or missing modules). | ||
| exports.showMessage = function handleMessage(messages) { | ||
| showMessageOverlay(messages[0]); | ||
| }; |
| @@ -0,0 +1,42 @@ | ||
| 'use strict'; | ||
|
|
||
| const SockJS = require('sockjs-client/dist/sockjs'); | ||
|
|
||
| let retries = 0; | ||
| let sock = null; | ||
|
|
||
| const socket = function initSocket(url, handlers) { | ||
| sock = new SockJS(url); | ||
|
|
||
| sock.onopen = function onopen() { | ||
| retries = 0; | ||
| }; | ||
|
|
||
| sock.onclose = function onclose() { | ||
| if (retries === 0) { handlers.close(); } | ||
|
|
||
| // Try to reconnect. | ||
| sock = null; | ||
|
|
||
| // After 10 retries stop trying, to prevent logspam. | ||
| if (retries <= 10) { | ||
| // Exponentially increase timeout to reconnect. | ||
| // Respectfully copied from the package `got`. | ||
| // eslint-disable-next-line no-mixed-operators, no-restricted-properties | ||
| const retryInMs = 1000 * Math.pow(2, retries) + Math.random() * 100; | ||
| retries += 1; | ||
|
|
||
| setTimeout(() => { | ||
| socket(url, handlers); | ||
| }, retryInMs); | ||
| } | ||
| }; | ||
|
|
||
| sock.onmessage = function onmessage(e) { | ||
| // This assumes that all data sent via the websocket is JSON. | ||
| const msg = JSON.parse(e.data); | ||
| if (handlers[msg.type]) { handlers[msg.type](msg.data); } | ||
| }; | ||
| }; | ||
|
|
||
| module.exports = socket; |
| @@ -0,0 +1,18 @@ | ||
| 'use strict'; | ||
|
|
||
| module.exports = { | ||
| mode: 'production', | ||
| module: { | ||
| rules: [ | ||
| { | ||
| test: /\.js$/, | ||
| exclude: /node_modules|web_modules/, | ||
| use: [ | ||
| { | ||
| loader: 'babel-loader' | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| }; |
| @@ -0,0 +1,124 @@ | ||
| 'use strict'; | ||
|
|
||
| /* eslint import/no-extraneous-dependencies: off, global-require: off */ | ||
|
|
||
| const $ = require('jquery'); | ||
| const stripAnsi = require('strip-ansi'); | ||
| const socket = require('../default/socket'); | ||
| require('./style.css'); | ||
|
|
||
| let hot = false; | ||
| let currentHash = ''; | ||
|
|
||
| $(() => { | ||
| $('body').html(require('./page.html')); | ||
| const status = $('#status'); | ||
| const okness = $('#okness'); | ||
| const $errors = $('#errors'); | ||
| const iframe = $('#iframe'); | ||
| const header = $('.header'); | ||
|
|
||
| const contentPage = window.location.pathname.substr('/webpack-dev-server'.length) + window.location.search; | ||
|
|
||
| status.text('Connecting to sockjs server...'); | ||
| $errors.hide(); | ||
| iframe.hide(); | ||
| header.css({ | ||
| borderColor: '#96b5b4' | ||
| }); | ||
|
|
||
| const onSocketMsg = { | ||
| hot() { | ||
| hot = true; | ||
| iframe.attr('src', contentPage + window.location.hash); | ||
| }, | ||
| invalid() { | ||
| okness.text(''); | ||
| status.text('App updated. Recompiling...'); | ||
| header.css({ | ||
| borderColor: '#96b5b4' | ||
| }); | ||
| $errors.hide(); | ||
| if (!hot) iframe.hide(); | ||
| }, | ||
| hash(hash) { | ||
| currentHash = hash; | ||
| }, | ||
| 'still-ok': function stillOk() { | ||
| okness.text(''); | ||
| status.text('App ready.'); | ||
| header.css({ | ||
| borderColor: '' | ||
| }); | ||
| $errors.hide(); | ||
| if (!hot) iframe.show(); | ||
| }, | ||
| ok() { | ||
| okness.text(''); | ||
| $errors.hide(); | ||
| reloadApp(); | ||
| }, | ||
| warnings() { | ||
| okness.text('Warnings while compiling.'); | ||
| $errors.hide(); | ||
| reloadApp(); | ||
| }, | ||
| errors: function msgErrors(errors) { | ||
| status.text('App updated with errors. No reload!'); | ||
| okness.text('Errors while compiling.'); | ||
| $errors.text(`\n${stripAnsi(errors.join('\n\n\n'))}\n\n`); | ||
| header.css({ | ||
| borderColor: '#ebcb8b' | ||
| }); | ||
| $errors.show(); | ||
| iframe.hide(); | ||
| }, | ||
| close() { | ||
| status.text(''); | ||
| okness.text('Disconnected.'); | ||
| $errors.text('\n\n\n Lost connection to webpack-dev-server.\n Please restart the server to reestablish connection...\n\n\n\n'); | ||
| header.css({ | ||
| borderColor: '#ebcb8b' | ||
| }); | ||
| $errors.show(); | ||
| iframe.hide(); | ||
| } | ||
| }; | ||
|
|
||
| socket('/sockjs-node', onSocketMsg); | ||
|
|
||
| iframe.on('load', () => { | ||
| status.text('App ready.'); | ||
| header.css({ | ||
| borderColor: '' | ||
| }); | ||
| iframe.show(); | ||
| }); | ||
|
|
||
| function reloadApp() { | ||
| if (hot) { | ||
| status.text('App hot update.'); | ||
| try { | ||
| iframe[0].contentWindow.postMessage(`webpackHotUpdate${currentHash}`, '*'); | ||
| } catch (e) { | ||
| console.warn(e); // eslint-disable-line | ||
| } | ||
| iframe.show(); | ||
| } else { | ||
| status.text('App updated. Reloading app...'); | ||
| header.css({ | ||
| borderColor: '#96b5b4' | ||
| }); | ||
| try { | ||
| let old = `${iframe[0].contentWindow.location}`; | ||
| if (old.indexOf('about') === 0) old = null; | ||
| iframe.attr('src', old || (contentPage + window.location.hash)); | ||
| if (old) { | ||
| iframe[0].contentWindow.location.reload(); | ||
| } | ||
| } catch (e) { | ||
| iframe.attr('src', contentPage + window.location.hash); | ||
| } | ||
| } | ||
| } | ||
| }); |
| @@ -0,0 +1,7 @@ | ||
| <div class="header"> | ||
| <span id="okness"></span> | ||
| <span id="status"></span> | ||
| </div> | ||
| <pre id="errors"></pre> | ||
| <div id="warnings"></div> | ||
| <iframe id="iframe" src="javascript:;" allowfullscreen="allowfullscreen"></iframe> |
| @@ -0,0 +1,38 @@ | ||
| 'use strict'; | ||
|
|
||
| const path = require('path'); | ||
| const CopyPlugin = require('copy-webpack-plugin'); | ||
|
|
||
| module.exports = { | ||
| mode: 'production', | ||
| module: { | ||
| rules: [ | ||
| { | ||
| test: /\.js$/, | ||
| exclude: /node_modules|web_modules/, | ||
| use: [ | ||
| { | ||
| loader: 'babel-loader' | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| test: /\.html$/, | ||
| use: ['html-loader'] | ||
| }, | ||
| { | ||
| test: /\.css$/, | ||
| use: [ | ||
| 'style-loader', | ||
| 'css-loader' | ||
| ] | ||
| } | ||
| ] | ||
| }, | ||
| plugins: [ | ||
| new CopyPlugin([{ | ||
| from: path.resolve(__dirname, 'live.html'), | ||
| to: path.resolve(__dirname, '../../client/live.html') | ||
| }]) | ||
| ] | ||
| }; |
| @@ -0,0 +1,3 @@ | ||
| 'use strict'; | ||
|
|
||
| module.exports = require('sockjs-client'); |
| @@ -0,0 +1,9 @@ | ||
| 'use strict'; | ||
|
|
||
| module.exports = { | ||
| mode: 'production', | ||
| output: { | ||
| library: 'SockJS', | ||
| libraryTarget: 'umd' | ||
| } | ||
| }; |
| @@ -0,0 +1 @@ | ||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600"><title>icon-square-small</title><path fill="#FFF" d="M300 .1L565 150v299.9L300 599.8 35 449.9V150z"/><path fill="#8ED6FB" d="M517.7 439.5L308.8 557.8v-92L439 394.1l78.7 45.4zm14.3-12.9V179.4l-76.4 44.1v159l76.4 44.1zM81.5 439.5l208.9 118.2v-92l-130.2-71.6-78.7 45.4zm-14.3-12.9V179.4l76.4 44.1v159l-76.4 44.1zm8.9-263.2L290.4 42.2v89l-137.3 75.5-1.1.6-75.9-43.9zm446.9 0L308.8 42.2v89L446 206.8l1.1.6 75.9-44z"/><path fill="#1C78C0" d="M290.4 444.8L162 374.1V234.2l128.4 74.1v136.5zm18.4 0l128.4-70.6v-140l-128.4 74.1v136.5zM299.6 303zm-129-85l129-70.9L428.5 218l-128.9 74.4-129-74.4z"/></svg> |
| @@ -0,0 +1,26 @@ | ||
| <!doctype html> | ||
| <html> | ||
| <head> | ||
| <title>WDS ▻ <%= htmlWebpackPlugin.options.title %></title> | ||
| <meta charset="utf-8"/> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| <link rel="shortcut icon" href="/.assets/favicon.ico"/> | ||
| <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400,600|Source+Sans+Pro:400,400i,500,600"/> | ||
| <link rel="stylesheet" href="/.assets/style.css"/> | ||
| </head> | ||
| <body> | ||
| <main> | ||
| <header> | ||
| <h1> | ||
| <img src="/.assets/icon-square.svg" style="width: 35px; height: 35px;"/> | ||
| webpack-dev-server | ||
| </h1> | ||
| </header> | ||
| <section> | ||
| <h2><%= htmlWebpackPlugin.options.title %></h2> | ||
| <div id="target"></div> | ||
| </section> | ||
| </main> | ||
| <script src="/bundle.js" type="text/javascript" charset="utf-8"></script> | ||
| </body> | ||
| </html> |
| @@ -0,0 +1,104 @@ | ||
| @font-face { | ||
| font-family: 'Geomanist'; | ||
| font-style: normal; | ||
| font-weight: 600; | ||
| src: url('assets/geomanist-medium.woff2') format('woff2'), | ||
| url('assets/geomanist-medium.woff') format('woff'); | ||
| } | ||
|
|
||
| html, | ||
| body { | ||
| background-color: #f3f3f3; | ||
| color: #2B3A42; | ||
| font: 400 10px "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; | ||
| height: 100%; | ||
| margin: 0; | ||
| padding: 0; | ||
| -webkit-font-smoothing: antialiased; | ||
| -moz-osx-font-smoothing: grayscale; | ||
| } | ||
|
|
||
| a { | ||
| color: #2086d7; | ||
| text-decoration: none; | ||
| transition: color 250ms; | ||
| } | ||
|
|
||
| a:hover { | ||
| color: #1a6aab; | ||
| } | ||
|
|
||
| main { | ||
| width: 100%; | ||
| max-width: 94.2rem; | ||
| margin: 0px auto; | ||
| padding: 8rem 2.4rem; | ||
| } | ||
|
|
||
| h1 { | ||
| font-size: 3.4rem; | ||
| font-weight: 600; | ||
| line-height: 3.4rem; | ||
| margin-top: 0; | ||
| padding-top: 0; | ||
| } | ||
|
|
||
| h1 img { | ||
| height: 3.4rem; | ||
| width: 3.4rem; | ||
| vertical-align: middle; | ||
| } | ||
|
|
||
| h2 { | ||
| font-size: 2.8rem; | ||
| } | ||
|
|
||
| section { | ||
| padding: 0 0 0 4.2rem; | ||
| } | ||
|
|
||
| div, p, table { | ||
| font-size: 1.6rem; | ||
| } | ||
|
|
||
| code { | ||
| background-color: rgba(70, 94, 105, 0.06); | ||
| border-radius: 3px; | ||
| font-family: "Source Code Pro", Consolas, "Liberation Mono", Menlo, Courier, monospace; | ||
| font-size: 1.44rem; | ||
| margin: 0; | ||
| max-width: 100%; | ||
| line-height: initial; | ||
| overflow: auto; | ||
| padding: 2px 6px; | ||
| text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6); | ||
| vertical-align: middle; | ||
| white-space: normal; | ||
| } | ||
|
|
||
| #target { | ||
| background: #DCF2FD; | ||
| border: 0.1rem solid #618ca0; | ||
| border-radius: 0.3rem; | ||
| color: #618ca0; | ||
| margin: 2rem 0; | ||
| padding: 2rem; | ||
| } | ||
|
|
||
| #target.warn { | ||
| background: #fcf8e3; | ||
| border: 0.1rem solid #8a6d3b; | ||
| color: #8a6d3b; | ||
| } | ||
|
|
||
| #target.pass { | ||
| background: #f2f9f4; | ||
| border: 0.1rem solid #4db277; | ||
| color: #4db277; | ||
| } | ||
|
|
||
| #target.fail { | ||
| background: #f2dede; | ||
| border: 0.1rem solid #a94442; | ||
| color: #a94442; | ||
| } |
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "rules": { | ||
| "no-console": "off" | ||
| } | ||
| } |
| @@ -1,9 +1,29 @@ | ||
| # Examples | ||
|
|
||
| Each example showcases a feature. You can use this to learn how to use that feature, but also use it to test if something still works when making a Pull Request. | ||
| Each example showcases a particular feature of `webpack-dev-server`. You can use | ||
| these examples to learn how to use certain features, or as a means to test features | ||
| when working on a Pull Request. | ||
|
|
||
| An example should be as minimal as possible, and consists of: | ||
| An example should be as minimal as possible and consists of at least: | ||
|
|
||
| - The code that is necessary | ||
| - Instructions on how to run | ||
| - A description of what should happen | ||
| - An `app.js` file - the entry point for an example app. | ||
| - A `README.md` file containing information about, and how to run the example app. | ||
| - A description of what should happen when running the example. | ||
| - A `webpack.config.js` file containing the `webpack` configuration for the example app. | ||
|
|
||
| ## API versus CLI | ||
|
|
||
| API examples can be found in the `api` directory. These examples demonstrate how | ||
| to access and run `webpack-dev-server` directly in your application / script. | ||
|
|
||
| CLI examples can be found in the `cli` directory. These examples demonstrate how | ||
| to run `webpack-dev-server` from the command line in your console / terminal. | ||
|
|
||
| ## Notes | ||
|
|
||
| - Each example's `webpack` config is wrapped with `util.setup`; a helper function | ||
| that adds plugins and configuration needed by each example to render in a consistent | ||
| and visually pleasing way. | ||
| - Examples' `bundle.js` and `index.html` files are compiled and served from memory. | ||
| You won't actually see these files written to disk, but if you examine the `webpack` | ||
| output, you should see their file indicators. |
| @@ -0,0 +1,20 @@ | ||
| # API: Custom Middleware | ||
|
|
||
| While it's recommended to run `webpack-dev-server` via the CLI, you may also | ||
| choose to start a server via the API. This example demonstrates using one of the | ||
| few custom middleware options; `before`. | ||
|
|
||
| ```console | ||
| node server.js | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. Open `http://localhost:8080/` in your preferred browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In the console/terminal, you should see the following for each refresh in | ||
| the browser: | ||
| ``` | ||
| Using middleware for / | ||
| Using middleware for /bundle.js | ||
| ``` |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,23 @@ | ||
| 'use strict'; | ||
|
|
||
| const Webpack = require('webpack'); | ||
| const WebpackDevServer = require('../../../lib/Server'); | ||
| const webpackConfig = require('./webpack.config'); | ||
|
|
||
| const compiler = Webpack(webpackConfig); | ||
| const devServerOptions = Object.assign({}, webpackConfig.devServer, { | ||
| stats: { | ||
| colors: true | ||
| }, | ||
| before(app) { | ||
| app.use((req, res, next) => { | ||
| console.log(`Using middleware for ${req.url}`); | ||
| next(); | ||
| }); | ||
| } | ||
| }); | ||
| const server = new WebpackDevServer(compiler, devServerOptions); | ||
|
|
||
| server.listen(8080, '127.0.0.1', () => { | ||
| console.log('Starting server on http://localhost:8080'); | ||
| }); |
| @@ -0,0 +1,13 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: ['./app.js', '../../../client/index.js?http://localhost:8080/'], | ||
| output: { | ||
| filename: 'bundle.js' | ||
| } | ||
| }); |
| @@ -0,0 +1,17 @@ | ||
| # API: Simple Server | ||
|
|
||
| While it's recommended to run `webpack-dev-server` via the CLI, you may also | ||
| choose to start a server via the API. This example starts a simple server setup. | ||
|
|
||
| ```console | ||
| node server.js | ||
| ``` | ||
|
|
||
| ## What should happen | ||
|
|
||
| 1. Open `http://localhost:8080/` in your preferred browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In `app.js`, uncomment the code that results in an error and save. This error | ||
| should be visible in the console/terminal and in browser devtools. | ||
| 4. In `app.js`, uncomment the code that results in a warning. This warning should | ||
| be visible in the console/terminal and in browser devtools. |
| @@ -0,0 +1,17 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; | ||
|
|
||
| // This results in a warning: | ||
| if (!window) { | ||
| // eslint-disable-next-line | ||
| require(`./${window}parseable.js`); | ||
| } | ||
|
|
||
| // This results in an error: | ||
| // if(!window) { | ||
| // require("test"); | ||
| // } |
| @@ -0,0 +1,17 @@ | ||
| 'use strict'; | ||
|
|
||
| const Webpack = require('webpack'); | ||
| const WebpackDevServer = require('../../../lib/Server'); | ||
| const webpackConfig = require('./webpack.config'); | ||
|
|
||
| const compiler = Webpack(webpackConfig); | ||
| const devServerOptions = Object.assign({}, webpackConfig.devServer, { | ||
| stats: { | ||
| colors: true | ||
| } | ||
| }); | ||
| const server = new WebpackDevServer(compiler, devServerOptions); | ||
|
|
||
| server.listen(8080, '127.0.0.1', () => { | ||
| console.log('Starting server on http://localhost:8080'); | ||
| }); |
| @@ -0,0 +1,13 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: ['./app.js', '../../../client/index.js?http://localhost:8080/'], | ||
| output: { | ||
| filename: 'bundle.js' | ||
| } | ||
| }); |
| @@ -0,0 +1,15 @@ | ||
| # Bonjour (ZeroConf) | ||
|
|
||
| The Bonjour capability broadcasts server information via ZeroConf when the Server | ||
| is started. | ||
|
|
||
| To run this example, run this command in your console or terminal: | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --bonjour | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| A Zeroconf broadcast should occur, containing data with a type of `http` and a | ||
| subtype of `webpack`. |
| @@ -0,0 +1,5 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.innerHTML = 'Please check your Zeroconf service.'; |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,25 @@ | ||
| # Gzip Compression | ||
|
|
||
| Website gzip compression makes it possible to reduce the file size of a file | ||
| to roughly 30% of its original size before the files are sent to the browser. | ||
|
|
||
| To run this example, run this command in your console or terminal: | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open --compress | ||
| ``` | ||
|
|
||
| ## What should happen | ||
|
|
||
| 1. The script should open `https://localhost:8080/`. | ||
| 2. Files being sent to the browser from the `webpack` bundle should be gzipped. | ||
| 3. Open the console in your browser's devtools and select the _Network_ tab. | ||
| 4. Find `bundle.js`. The response headers should contain `Content-Encoding: gzip`. | ||
|
|
||
| ## Notes | ||
|
|
||
| Some browsers, such as Chrome, won't show the `Content-Encoding: gzip` within | ||
| the _Response Headers_. This has been documented [here](https://github.com/expressjs/compression/issues/96). | ||
|
|
||
| To enable `Content-Encoding` for _Response Headers_ in Chrome, you can follow | ||
| [this tutorial](https://www.youtube.com/watch?v=47R6uv0RKCk). |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,25 @@ | ||
| # CLI: Default State | ||
|
|
||
| This example demonstrates how to use `webpack-dev-server` in its default, inline | ||
| state. | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open | ||
| ``` | ||
|
|
||
| To run your app using an alternative config, use: | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open --config alternative.config.js | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In `app.js` uncomment the code that results in an error and save. | ||
| 4. This error should be visible in the console/terminal and in the browser's devtools. | ||
| 5. In `app.js` uncomment the code that results in a warning. This warning should | ||
| be visible in the console/terminal and in the browser's devtools. | ||
| 6. Try changing something in `style.less`. The browser should refresh, and the | ||
| change should be visible in the app. |
| @@ -0,0 +1,20 @@ | ||
| 'use strict'; | ||
|
|
||
| require('./style.less'); | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; | ||
|
|
||
| const img = document.createElement('img'); | ||
| img.src = '/svg.svg'; | ||
| img.style = 'width: 200px;'; | ||
|
|
||
| document.body.appendChild(img); | ||
|
|
||
| // This results in a warning: | ||
| // if(!window) require("./" + window + "parseable.js"); | ||
|
|
||
| // This results in an error: | ||
| // if(!window) require("test"); |
| @@ -0,0 +1,27 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js', | ||
| module: { | ||
| rules: [ | ||
| { | ||
| test: /\.less$/, | ||
| use: [ | ||
| 'style-loader', | ||
| 'css-loader', | ||
| 'less-loader' | ||
| ] | ||
| }, | ||
| { | ||
| test: /\.png$/, | ||
| loader: 'file-loader', | ||
| options: { prefix: 'img/' } | ||
| } | ||
| ] | ||
| } | ||
| }); |
| @@ -0,0 +1,20 @@ | ||
| # CLI: History API Fallback Option | ||
|
|
||
| This option enables [History API Fallback](https://github.com/bripkens/connect-history-api-fallback) | ||
| support in `webpack-dev-server`, effectively asking the server to fallback to | ||
| `index.html` in the event that a requested resource cannot be found. | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --open --history-api-fallback | ||
| ``` | ||
|
|
||
| _Note: some URLs don't work by default. For example; if the url contains a dot. | ||
| Be sure to checkout the [connect-history-api-fallback](https://github.com/bripkens/connect-history-api-fallback) | ||
| options._ | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://0.0.0.0:8080/` in your default browser. | ||
| 2. You should see text on the page that reads 'Current Path: /'. | ||
| 3. Navigate to `http://localhost:8080/foo/bar`. | ||
| 4. You should see text on the page that reads 'Current Path: /foo/background'. |
| @@ -0,0 +1,75 @@ | ||
| 'use strict'; | ||
|
|
||
| /* global XMLHttpRequest */ | ||
|
|
||
| const path = document.location.pathname; | ||
| const target = document.querySelector('#target'); | ||
| const style = document.createElement('style'); | ||
| const css = `table { | ||
| border-radius: 0.3rem; | ||
| border: 0.1rem solid #474747; | ||
| border-spacing: 0; | ||
| padding: 0; | ||
| width: 50%; | ||
| } | ||
| table td { | ||
| border-right: 0.1rem solid #474747; | ||
| padding: 0.5rem 1rem; | ||
| } | ||
| table tr td:last-child { | ||
| border-right: 0; | ||
| text-align: center; | ||
| } | ||
| table td.pass { | ||
| background: #f2f9f4; | ||
| color: #4db277; | ||
| } | ||
| table td.fail { | ||
| background: #f2dede; | ||
| color: #a94442; | ||
| }`; | ||
|
|
||
| style.appendChild(document.createTextNode(css)); | ||
| document.head.appendChild(style); | ||
| target.innerHTML = `Current Path: <code>${path}</code>`; | ||
|
|
||
| document.addEventListener('DOMContentLoaded', () => { | ||
| if (document.querySelector('#files')) { | ||
| return; | ||
| } | ||
|
|
||
| const tests = [ | ||
| { url: '/', name: 'index', re: /^<!doctype html>/i }, | ||
| { url: '/test', name: 'non-existent path', re: /^<!doctype html>/i }, | ||
| { url: '/file.txt', name: 'existing path', re: /^file/ } | ||
| ]; | ||
| const table = document.createElement('table'); | ||
| const tbody = document.createElement('tbody'); | ||
|
|
||
| table.id = 'files'; | ||
| table.appendChild(tbody); | ||
| target.parentNode.appendChild(table); | ||
|
|
||
| tests.forEach((test) => { | ||
| const tr = document.createElement('tr'); | ||
| tbody.appendChild(tr); | ||
| check(test.url, test.re, (res) => { | ||
| tr.innerHTML = `<td>${test.name}</td>`; | ||
| tr.innerHTML += `<td><a href="${test.url}">${test.url}</a></td>`; | ||
| tr.innerHTML += `<td class="${res}">${res}</td>`; | ||
| }); | ||
| }); | ||
| }, true); | ||
|
|
||
| function check(url, re, cb) { | ||
| const xhr = new XMLHttpRequest(); | ||
| xhr.addEventListener('load', () => { | ||
| cb(re.test(xhr.responseText) ? 'pass' : 'fail'); | ||
| }); | ||
| xhr.open('GET', url); | ||
| xhr.send(); | ||
| } |
| @@ -0,0 +1,15 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js', | ||
| devServer: { | ||
| historyApiFallback: { | ||
| disableDotRule: true | ||
| } | ||
| } | ||
| }); |
| @@ -0,0 +1,30 @@ | ||
| # Hot Module Reloading | ||
|
|
||
| Hot Module Replacement (HMR) exchanges, adds, or removes modules while an | ||
| application is running, without a full reload of the page. | ||
|
|
||
| To run this example, run this command in your console or terminal: | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open --hot | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. In your editor, open `example.js` and change any part of the `innerHTML` string. | ||
| 3. Open the console in your browser's devtools. | ||
|
|
||
| In the devtools console you should see: | ||
|
|
||
| ``` | ||
| [WDS] App updated. Recompiling... | ||
| [WDS] App hot update... | ||
| [HMR] Checking for updates on the server... | ||
| [HMR] Updated modules: | ||
| [HMR] - ./example.js | ||
| [HMR] App is up to date. | ||
| ``` | ||
|
|
||
| You should also see the text on the page itself change to match your edits in | ||
| `example.js`. |
| @@ -0,0 +1,11 @@ | ||
| 'use strict'; | ||
|
|
||
| require('./example'); | ||
|
|
||
| if (module.hot) { | ||
| module.hot.accept((err) => { | ||
| if (err) { | ||
| console.error('Cannot apply HMR update.', err); | ||
| } | ||
| }); | ||
| } |
| @@ -0,0 +1,5 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.innerHTML = 'Modify and save <code>/examples/hmr/example.js</code> to update this element without reloading the page.'; |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,24 @@ | ||
| # CLI: Host and Port Options | ||
|
|
||
| You may choose to wish to change the host and port on which `webpack-dev-server` | ||
| will run. The `host` and `port` options allow for that. | ||
|
|
||
| ## IPv4 | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open --port 5000 --host 0.0.0.0 | ||
| ``` | ||
|
|
||
| ## IPv6 | ||
|
|
||
| _This also works with IPv4_ | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open --port 5000 --host :: | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://0.0.0.0:5000/` if specifying the IPv4 option, | ||
| or `http://[::]:5000/` for IPv6, in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,48 @@ | ||
| # CLI: Https Option | ||
|
|
||
| By default webpack-dev-server will generate a self-signed, 2048 bit, sha256 SSL | ||
| Certificate, which is used to enable https. The certificate will be located in the | ||
| `ssl` directory after the server is started for the first time. The generated | ||
| certificate is only good for 30 days, at which point it'll be regenerated. | ||
|
|
||
| We highly recommend creating and managing your own certificates. Please see the | ||
| following resources for doing so: | ||
|
|
||
| ### MacOS | ||
| https://certsimple.com/blog/localhost-ssl-fix | ||
|
|
||
| ### Windows 10 | ||
| https://technet.microsoft.com/itpro/powershell/windows/pkiclient/new-selfsignedcertificate | ||
|
|
||
| ### Windows 7 | ||
| https://msdn.microsoft.com/en-us/library/aa386968.aspx | ||
|
|
||
| Example (the .pfx file generated the following way can be used without `--pfx-passphrase`): | ||
| ``` | ||
| makecert -r -pe -sky exchange -sv makecert.pvk makecert.cer | ||
| pvk2pfx -pvk makecert.pvk -spc makecert.cer -pfx makecert.pfx | ||
| ``` | ||
|
|
||
| ## Getting Started | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --open --https | ||
| ``` | ||
|
|
||
| ## Using Your Certificate | ||
|
|
||
| Options are available for using your own SSL Certificate in your preferred or | ||
| OS-required format. | ||
|
|
||
| Given the base command `npm run webpack-dev-server -- --open --https`, append | ||
| one of the following: | ||
|
|
||
| * (PEM Files) `--cert=../../ssl/server.pem --key=../../ssl/server.pem` | ||
| * (PFX and Passphrase) `--pfx=./test_cert.pfx --pfx-passphrase=sample` | ||
|
|
||
| ## What To Expect | ||
|
|
||
| The script should open `https://localhost:8080/`in your default browser. If your | ||
| browser displays a warning about a non-trusted certificate, follow the procedure | ||
| for your browser of choice to continue. After doing so you should see "It's Working" | ||
| displayed on the page. |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,19 @@ | ||
| # CLI: Inline Iframe | ||
|
|
||
| The `--no-inline` option instructs `webpack-dev-server` to open the app in an | ||
| iframe. The page then contains the client script to connect to the server. | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --no-inline --open | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/webpack-dev-server/` in your | ||
| default browser. | ||
| 2. There should be a bar at the top of the page that reads `App ready`. | ||
| 3. In `app.js`, uncomment the code that results in an error and save. | ||
| 4. The bar at the top should read `Errors while compiling. App updated with errors. | ||
| No reload!` along with a stack trace. | ||
| 5. In `app.js`, uncomment the code that results in a warning. The bar at the top | ||
| should read `Warnings while compiling`. |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,19 @@ | ||
| # CLI: Lazy Option | ||
|
|
||
| With the `lazy` option enabled, `webpack-dev-server` does **not** watch the | ||
| bundle files, nor does it automatically recompile them or refresh the browser. | ||
| Instead, it only compiles after you manually refresh the page. | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --open --lazy --no-inline | ||
| ``` | ||
|
|
||
| ## What should happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. Change something in `app.js` and save. | ||
| 4. You should not see any changes in the console/terminal output. | ||
| 5. You should not see any changes in the browser. | ||
| 6. Refresh the page. | ||
| 7. You should see compilation in the console/terminal and changes in the browser. |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,9 @@ | ||
| 'use strict'; | ||
|
|
||
| const net = require('net'); | ||
|
|
||
| const client = net.createConnection('./webpack.sock'); | ||
| client.on('connect', () => { | ||
| console.log('Successfully connected to socket, exiting'); | ||
| process.exit(1); // eslint-disable-line | ||
| }); |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,15 @@ | ||
| # CLI: Multi Compiler | ||
|
|
||
| `webpack-dev-server` should be able to compile multiple webpack configs. | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --open | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In `app.js` write code containing a syntax error and save the file. | ||
| 4. The page should now refresh and show a full screen error overlay, displaying | ||
| the syntax error. |
| @@ -0,0 +1,9 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; | ||
|
|
||
| // This results in an error: | ||
| // if(!window) require("test"); |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = [setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| })]; |
| @@ -0,0 +1,10 @@ | ||
| # CLI: Webpack `node` Option | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --open | ||
| ``` | ||
|
|
||
| ## What should happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,11 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js', | ||
| node: false | ||
| }); |
| @@ -0,0 +1,14 @@ | ||
| # CLI: Open Page Option | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open-page example.html#page1 | ||
| ``` | ||
|
|
||
| Some applications may consist of multiple pages. During development it may | ||
| be useful to directly open a particular page. The page to open may be specified | ||
| as the argument to the `open-page` option. | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| The script should open `http://localhost:8080/` in your default browser. | ||
| You should see the text on the page itself change to read `Success!`. |
| @@ -0,0 +1,11 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| if (window.location.href.endsWith('example.html#page1')) { | ||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; | ||
| } else { | ||
| target.classList.add('fail'); | ||
| target.innerHTML = 'Houston, we have a problem.'; | ||
| } |
| @@ -0,0 +1,18 @@ | ||
| 'use strict'; | ||
|
|
||
| const HtmlWebpackPlugin = require('html-webpack-plugin'); | ||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js', | ||
| plugins: [ | ||
| new HtmlWebpackPlugin({ | ||
| filename: 'example.html', | ||
| template: '../../.assets/layout.html', | ||
| title: 'Open Page / Example' | ||
| }) | ||
| ] | ||
| }); |
| @@ -0,0 +1,18 @@ | ||
| # CLI: Overlay Option | ||
|
|
||
| `webpack-dev-server` can display an overlay for warnings and errors. | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --open --overlay | ||
| ``` | ||
|
|
||
| _Note: To view additional options for the overlay visit | ||
| [https://webpack.js.org/configuration/dev-server/#devserver-overlay](https://webpack.js.org/configuration/dev-server/#devserver-overlay)._ | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In `app.js` write code containing a syntax error and save the file. | ||
| 4. The page should now refresh and show a full screen error overlay, displaying | ||
| the syntax error. |
| @@ -0,0 +1,9 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; | ||
|
|
||
| // This results in an error: | ||
| // if(!window) require("test"); |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,12 @@ | ||
| # CLI: Progress Option | ||
|
|
||
| ```shell | ||
| npm run webpack-dev-server -- --open | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In `app.js` change the text and save. | ||
| 4. You should see the compilation progress in the browser console. |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,13 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js', | ||
| devServer: { | ||
| progress: true | ||
| } | ||
| }); |
| @@ -0,0 +1,18 @@ | ||
| # CLI: Public Option Protocol | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server | ||
| ``` | ||
|
|
||
| _NOTE: replace `<insert local ip>` with your local IP Address._ | ||
|
|
||
| You're now able to explicitly define the protocol used with the `public` option | ||
| (have a look to the config provided in `webpack.config.js`). | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| The script should open `http://localhost:8080/` in your default browser. | ||
|
|
||
| You should see a failed attempt to establish a connection to `/sockjs-node` | ||
| via the explicitly defined `https://localhost:8080`. This fails of course since | ||
| we're not hosting https. |
| @@ -0,0 +1,5 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.innerHTML = 'Please check the sockjs-info request in devtools, it should try to connect to the protocol + server defined in the public setting.'; |
| @@ -0,0 +1,15 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js', | ||
| devServer: { | ||
| host: '0.0.0.0', | ||
| public: 'https://localhost:8080', | ||
| disableHostCheck: true | ||
| } | ||
| }); |
| @@ -0,0 +1,21 @@ | ||
| # CLI: Public Option | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --open --host 0.0.0.0 --public <insert local ip>:8080 | ||
| ``` | ||
|
|
||
| _NOTE: replace `<insert local ip>` with your local IP Address._ | ||
|
|
||
| In order to make the server publicly accessible the client needs to know with | ||
| what host to connect to the server. If `--host 0.0.0.0` is given, the client | ||
| would try to connect to `0.0.0.0`. With the `--public` options it is possible to | ||
| override this. | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The script should open `http://0.0.0.0:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. Open the console in your browser's devtools. | ||
| 4. Select the 'Network' tab. | ||
| 5. Select the 'WS' or 'WebSockets' sub-tab. | ||
| 6. Verify that the WebSocket is connecting to `<insert local ip>:8080`. |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,10 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }); |
| @@ -0,0 +1,16 @@ | ||
| # CLI: Stdin Option | ||
|
|
||
| Specifying this option instructs the server to close when `stdin` ends. | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --stdin | ||
| ``` | ||
|
|
||
| ## What Should Happen | ||
|
|
||
| 1. The server should begin running. | ||
| 2. Press `CTL+D` on your keyboard. | ||
| 3. The server should close. | ||
|
|
||
| _Note: the keyboard shortcut for terminating `stdin` can vary depending on the | ||
| operating systems._ |
| @@ -0,0 +1,5 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.innerHTML = 'Press <code>CTL+D</code> on your keyboard to close the server.'; |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| module.exports = { | ||
| context: __dirname, | ||
| entry: './app.js' | ||
| }; |
| @@ -0,0 +1,42 @@ | ||
| # CLI: Watch Content Base | ||
|
|
||
| ## Watching a single directory | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --content-base assets --watch-content-base --open | ||
| ``` | ||
|
|
||
| ### What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In your editor, edit `assets/index.html` and save your changes. | ||
| 4. The app should reload in the browser. | ||
|
|
||
| ## Watching an Array of Directories | ||
|
|
||
| ```js | ||
| // webpack.conf.js | ||
| module.exports = { | ||
| /* ... */ | ||
| devServer: { | ||
| contentBase: [ | ||
| "assets", | ||
| "css", | ||
| ] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ```console | ||
| npm run webpack-dev-server -- --watch-content-base --open | ||
| ``` | ||
|
|
||
| ### What Should Happen | ||
|
|
||
| 1. The script should open `http://localhost:8080/` in your default browser. | ||
| 2. You should see the text on the page itself change to read `Success!`. | ||
| 3. In your editor, edit `assets/index.html` and save your changes. | ||
| 4. The app should reload. | ||
| 5. In your editor, edit `css/styles.css` and save your changes. | ||
| 6. The app should reload. |
| @@ -0,0 +1,6 @@ | ||
| 'use strict'; | ||
|
|
||
| const target = document.querySelector('#target'); | ||
|
|
||
| target.classList.add('pass'); | ||
| target.innerHTML = 'Success!'; |
| @@ -0,0 +1,16 @@ | ||
| 'use strict'; | ||
|
|
||
| // our setup function adds behind-the-scenes bits to the config that all of our | ||
| // examples need | ||
| const { setup } = require('../../util'); | ||
|
|
||
| module.exports = setup({ | ||
| context: __dirname, | ||
| entry: './app.js', | ||
| devServer: { | ||
| contentBase: [ | ||
| 'assets', | ||
| 'css' | ||
| ] | ||
| } | ||
| }); |