@@ -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