Skip to content

Commit 37e13a5

Browse files
authored
Merge pull request #214 from PepsRyuu/HMRChanges
HMR Auto Require
2 parents 9d05d5a + f948110 commit 37e13a5

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

docs/hmr.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ The object contains the following:
2626

2727
* ```disposed``` - Contains list of module ids disposed when bubbling to this accept handler.
2828

29+
Note that in order for the module to be resolved, you must call ```require(module.id)``` inside the callback.
30+
This is slightly different from the way that other bundlers operates, which auto-requires before calling the accept handler.
31+
Due to backwards compatibility, this cannot be changed at the moment.
32+
33+
However, if you call this function without passing a callback, it will auto-require the module.
34+
2935
***void* dispose(*Function* callback)**
3036

3137
Executes when the module is about to be replaced.

lib/plugin-hmr.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ module.exports = function (options = { bundleId: '' }) {
187187
data: ${hotGlobal}.dataCache[module.id] || undefined,
188188
189189
accept: function (callback) {
190-
this._accept = callback;
190+
this._accept = callback || function () { _require(null, module.id) };
191191
},
192192
193193
dispose: function (callback) {

test/cases/plugin-hmr.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ function createEnv (input, options = {}, env_options = {}) {
8585
let modules = input.map(m => m.code);
8686
let globals = createGlobals(env_options);
8787
let { window, console, WebSocket, __nollup__global__, globalThis } = globals;
88+
let _require = (parent, mod) => {};
8889

8990
let plugin_instance = plugin(options);
9091
eval(plugin_instance.nollupBundleInit());
@@ -1453,6 +1454,101 @@ describe('plugin-hmr', () => {
14531454
fs.reset();
14541455
});
14551456

1457+
it ('should not execute modules twice once changed', async () => {
1458+
fs.stub('./src/main.js', () => `
1459+
import message from './message';
1460+
`);
1461+
1462+
fs.stub('./src/message.js', () => `
1463+
if (!window.counter) {
1464+
window.counter = 0;
1465+
}
1466+
module.hot.accept(() => require(module.id));
1467+
window.counter++;
1468+
`);
1469+
1470+
let env = await createNollupEnv();
1471+
fs.reset();
1472+
1473+
fs.stub('./src/message.js', () => `
1474+
module.hot.accept(() => require(module.id));
1475+
window.counter++;
1476+
window.invalidated = true;
1477+
`);
1478+
1479+
env.bundle.invalidate('./src/message.js');
1480+
let { changes } = await env.bundle.generate({ format: 'esm' });
1481+
env.ws.send({ changes });
1482+
expect(env.window.counter).to.equal(2);
1483+
expect(env.window.invalidated).to.be.true;
1484+
fs.reset();
1485+
});
1486+
1487+
it ('should allow empty accept to auto-require', async () => {
1488+
fs.stub('./src/main.js', () => `
1489+
import message from './message';
1490+
`);
1491+
1492+
fs.stub('./src/message.js', () => `
1493+
if (!window.counter) {
1494+
window.counter = 0;
1495+
}
1496+
module.hot.dispose(() => console.log('dispose'));
1497+
window.counter++;
1498+
module.hot.accept();
1499+
`);
1500+
1501+
let env = await createNollupEnv();
1502+
fs.reset();
1503+
1504+
fs.stub('./src/message.js', () => `
1505+
window.counter++;
1506+
window.invalidated = true;
1507+
module.hot.accept();
1508+
`);
1509+
1510+
env.bundle.invalidate('./src/message.js');
1511+
let { changes } = await env.bundle.generate({ format: 'esm' });
1512+
env.ws.send({ changes });
1513+
expect(env.stdout.length).to.equal(1);
1514+
expect(env.stdout[0]).to.equal('dispose');
1515+
expect(env.window.counter).to.equal(2);
1516+
expect(env.window.invalidated).to.be.true;
1517+
fs.reset();
1518+
});
1519+
1520+
it ('should not auto-require for accept if handler is given', async () => {
1521+
// Note: This is not compatible with other bundlers.
1522+
// Ideally Nollup should auto-require to be inline with other bundlers,
1523+
// but there are projects which rely on the fact that it doesn't and use the accept
1524+
// handler to dispose, require and accept at once in the one callback.
1525+
fs.stub('./src/main.js', () => `
1526+
import message from './message';
1527+
window.counter = 0;
1528+
`);
1529+
1530+
fs.stub('./src/message.js', () => `
1531+
module.hot.dispose(() => console.log('dispose'));
1532+
module.hot.accept(() => {});
1533+
`);
1534+
1535+
let env = await createNollupEnv();
1536+
fs.reset();
1537+
1538+
fs.stub('./src/message.js', () => `
1539+
window.counter = 1;
1540+
module.hot.accept(() => {});
1541+
`);
1542+
1543+
env.bundle.invalidate('./src/message.js');
1544+
let { changes } = await env.bundle.generate({ format: 'esm' });
1545+
env.ws.send({ changes });
1546+
expect(env.stdout.length).to.equal(1);
1547+
expect(env.stdout[0]).to.equal('dispose');
1548+
expect(env.window.counter).to.equal(0);
1549+
fs.reset();
1550+
});
1551+
14561552
it ('should allow new import meta to work via HMR after first bundle');
14571553

14581554
it ('should allow new external imports to work via HMR after first bundle');

0 commit comments

Comments
 (0)