-
-
Notifications
You must be signed in to change notification settings - Fork 387
feat(hmr): adding hot module reloading #334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
alexander-akait
merged 58 commits into
webpack-contrib:master
from
ScriptedAlchemy:hot-module-reloading
Apr 9, 2019
Merged
Changes from 3 commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
0830301
feat(hmr): adding hot module reloading
evilebottnawi 875f166
Merge remote-tracking branch 'origin/hot-module-reloading' into hot-m…
ScriptedAlchemy 7f99f5f
fix: remove unused dependency
ScriptedAlchemy 4e72531
refactor: refactors based on PR comments
ScriptedAlchemy 50b3fd8
refactor: move hot loader into base loader
ScriptedAlchemy c2207af
refactor: get hmr working with new context
ScriptedAlchemy 1700774
test: added hmr test case
ScriptedAlchemy 3f975cd
revert: roll back package upgrades
ScriptedAlchemy 4c0c742
fix: updating dependencies
ScriptedAlchemy edf19e1
fix: remove console log
ScriptedAlchemy bac3930
test: fixing tests
ScriptedAlchemy 86134d0
fix: use older version of normalize
ScriptedAlchemy 8e6f14c
fix: remove vulnerabilities in depencencies
ScriptedAlchemy 3979add
test: adding snapshot for hmr
ScriptedAlchemy 3157c84
fix: moved es checker to dev dependencies
ScriptedAlchemy 01126f8
docs: updated readme to detail hmr
ScriptedAlchemy 2cf31af
fix: hmr on global styles
ScriptedAlchemy e5a5afb
fix: lock webpack version to avoid npm acorn issue
ScriptedAlchemy 9ed9a85
fix: patching issue with global css missing source
ScriptedAlchemy 2f94eed
fix: renaming hot to hmr
ScriptedAlchemy 969514f
fix: remove unused method and using locals for css modules
ScriptedAlchemy b06d817
test: updating tests and snapshots
ScriptedAlchemy 0aa328c
fix: using older version of normalize for older node support
ScriptedAlchemy be929ae
fix: removing reloadAll option
ScriptedAlchemy 06e7789
fix: auto detect locals and reloadAll
ScriptedAlchemy a6bdafd
feat: adding order warning option
ScriptedAlchemy 150f858
fix: added default option for orderWarning
ScriptedAlchemy a91857c
test: updating test expectations
ScriptedAlchemy 55b6158
docs: updating readme about order warning flags
ScriptedAlchemy d9ebdc5
docs: updating docs about filtering warnings warningsFilter
ScriptedAlchemy 6e6642a
feat(hmr): adding hot module reloading
evilebottnawi 5a9fc85
fix: remove unused dependency
ScriptedAlchemy 50144a7
refactor: refactors based on PR comments
ScriptedAlchemy 39dd711
refactor: move hot loader into base loader
ScriptedAlchemy 6126e7e
refactor: get hmr working with new context
ScriptedAlchemy cd6df8e
test: added hmr test case
ScriptedAlchemy bf0f745
revert: roll back package upgrades
ScriptedAlchemy d1cbf81
fix: updating dependencies
ScriptedAlchemy 31bfa71
fix: remove console log
ScriptedAlchemy a51d862
test: fixing tests
ScriptedAlchemy 2bd6661
fix: use older version of normalize
ScriptedAlchemy 9803db3
fix: remove vulnerabilities in depencencies
ScriptedAlchemy c190436
test: adding snapshot for hmr
ScriptedAlchemy 0c93cf0
fix: moved es checker to dev dependencies
ScriptedAlchemy c111e9b
docs: updated readme to detail hmr
ScriptedAlchemy 936b8d3
fix: lock webpack version to avoid npm acorn issue
ScriptedAlchemy b08a3ce
fix: renaming hot to hmr
ScriptedAlchemy 9f16d99
fix: remove unused method and using locals for css modules
ScriptedAlchemy 79001b8
test: updating tests and snapshots
ScriptedAlchemy 59797cc
fix: using older version of normalize for older node support
ScriptedAlchemy c149cc2
fix: removing reloadAll option
ScriptedAlchemy 33109c4
fix: auto detect locals and reloadAll
ScriptedAlchemy 6981838
feat: adding order warning option
ScriptedAlchemy 2708a67
fix: added default option for orderWarning
ScriptedAlchemy 4d1c75d
test: updating test expectations
ScriptedAlchemy 15dd658
docs: updating readme about order warning flags
ScriptedAlchemy 7f4159e
docs: updating docs about filtering warnings warningsFilter
ScriptedAlchemy 641bdce
Merge branch 'master' into hot-module-reloading
ScriptedAlchemy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module.exports = { | ||
"parserOptions": { | ||
"ecmaVersion": 5, | ||
"sourceType": "module", | ||
}, | ||
globals: { | ||
document: true | ||
}, | ||
plugins: ['prettier'], | ||
extends: ['@webpack-contrib/eslint-config-webpack'], | ||
rules: { | ||
'prettier/prettier': [ | ||
'error', | ||
{singleQuote: true, trailingComma: 'es5', arrowParens: 'avoid'}, | ||
], | ||
'class-methods-use-this': 'off', | ||
'no-undefined': 'off', | ||
'func-style': ["error", "declaration", {"allowArrowFunctions": false}], | ||
'prefer-rest-params': 0, | ||
'prefer-spread': 0, | ||
'prefer-destructuring': 0 | ||
}, | ||
}; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
const path = require('path'); | ||
|
||
const loaderUtils = require('loader-utils'); | ||
|
||
const defaultOptions = { | ||
fileMap: '{fileName}', | ||
}; | ||
|
||
function hotLoader(content) { | ||
this.cacheable(); | ||
ScriptedAlchemy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const options = Object.assign( | ||
{}, | ||
defaultOptions, | ||
loaderUtils.getOptions(this) | ||
); | ||
|
||
const accept = options.cssModules | ||
? '' | ||
: 'module.hot.accept(undefined, cssReload);'; | ||
return `${content} | ||
if(module.hot) { | ||
// ${Date.now()} | ||
var cssReload = require(${loaderUtils.stringifyRequest( | ||
this, | ||
path.join(__dirname, 'hotModuleReplacement.js') | ||
)})(module.id, ${JSON.stringify(options)}); | ||
module.hot.dispose(cssReload); | ||
${accept}; | ||
} | ||
`; | ||
} | ||
|
||
module.exports = hotLoader; | ||
ScriptedAlchemy marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
const normalizeUrl = require('normalize-url'); | ||
|
||
const srcByModuleId = Object.create(null); | ||
|
||
const noDocument = typeof document === 'undefined'; | ||
|
||
function debounce(fn, time) { | ||
let timeout; | ||
|
||
// eslint-disable-next-line func-names | ||
return function() { | ||
const functionCall = () => fn.apply(this, arguments); | ||
|
||
clearTimeout(timeout); | ||
timeout = setTimeout(functionCall, time); | ||
}; | ||
} | ||
|
||
const forEach = Array.prototype.forEach; | ||
|
||
function noop() {} | ||
|
||
function getCurrentScriptUrl(moduleId) { | ||
let src = srcByModuleId[moduleId]; | ||
|
||
if (!src) { | ||
if (document.currentScript) { | ||
src = document.currentScript.src; | ||
} else { | ||
const scripts = document.getElementsByTagName('script'); | ||
const lastScriptTag = scripts[scripts.length - 1]; | ||
|
||
if (lastScriptTag) { | ||
src = lastScriptTag.src; | ||
} | ||
} | ||
srcByModuleId[moduleId] = src; | ||
} | ||
|
||
return function(fileMap) { | ||
const splitResult = /([^\\/]+)\.js$/.exec(src); | ||
const filename = splitResult && splitResult[1]; | ||
if (!filename) { | ||
return [src.replace('.js', '.css')]; | ||
} | ||
return fileMap.split(',').map(mapRule => { | ||
const reg = new RegExp(`${filename}\\.js$`, 'g'); | ||
return normalizeUrl( | ||
src.replace(reg, `${mapRule.replace(/{fileName}/g, filename)}.css`), | ||
{ stripWWW: false } | ||
); | ||
}); | ||
}; | ||
} | ||
|
||
function updateCss(el, url) { | ||
if (!url) { | ||
url = el.href.split('?')[0]; | ||
} | ||
if (el.isLoaded === false) { | ||
// We seem to be about to replace a css link that hasn't loaded yet. | ||
// We're probably changing the same file more than once. | ||
return; | ||
} | ||
if (!url || !(url.indexOf('.css') > -1)) return; | ||
|
||
el.visited = true; | ||
const newEl = el.cloneNode(); | ||
|
||
newEl.isLoaded = false; | ||
|
||
newEl.addEventListener('load', () => { | ||
newEl.isLoaded = true; | ||
el.parentNode.removeChild(el); | ||
}); | ||
|
||
newEl.addEventListener('error', () => { | ||
newEl.isLoaded = true; | ||
el.parentNode.removeChild(el); | ||
}); | ||
|
||
newEl.href = `${url}?${Date.now()}`; | ||
el.parentNode.appendChild(newEl); | ||
} | ||
|
||
function getReloadUrl(href, src) { | ||
href = normalizeUrl(href, { stripWWW: false }); | ||
let ret; | ||
// eslint-disable-next-line array-callback-return | ||
src.some(url => { | ||
if (href.indexOf(src) > -1) { | ||
ret = url; | ||
} | ||
}); | ||
return ret; | ||
} | ||
|
||
function reloadStyle(src) { | ||
const elements = document.querySelectorAll('link'); | ||
let loaded = false; | ||
|
||
forEach.call(elements, el => { | ||
if (el.visited === true) return; | ||
|
||
const url = getReloadUrl(el.href, src); | ||
if (url) { | ||
updateCss(el, url); | ||
loaded = true; | ||
} | ||
}); | ||
|
||
return loaded; | ||
} | ||
|
||
function reloadAll() { | ||
const elements = document.querySelectorAll('link'); | ||
forEach.call(elements, el => { | ||
if (el.visited === true) return; | ||
updateCss(el); | ||
}); | ||
} | ||
|
||
module.exports = function(moduleId, options) { | ||
if (noDocument) { | ||
return noop; | ||
ScriptedAlchemy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
const getScriptSrc = getCurrentScriptUrl(moduleId); | ||
|
||
function update() { | ||
const src = getScriptSrc(options.fileMap); | ||
const reloaded = reloadStyle(src); | ||
if (reloaded && !options.reloadAll) { | ||
console.log('[HMR] css reload %s', src.join(' ')); | ||
} else { | ||
console.log('[HMR] Reload all css'); | ||
reloadAll(); | ||
} | ||
} | ||
|
||
return debounce(update, 10); | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.