No Login Data Private Local Save

ES Modules in Browser Demo - Online See Import/Export

7
0
0
0

ES Modules Browser Demo

Write, edit & run ES module code directly in your browser. See import / export in action.

module editor
Console Output Ready
// Click Run or press Ctrl+Enter to execute ES module code // Output from console.log / error / warn will appear here // Edit module code in the editor panels on the left

Frequently Asked Questions

ES Modules (ECMAScript Modules) are the official standard for modular JavaScript. In browsers, you use type="module" on a <script> tag to enable module mode. Modules can export functions, objects, or values and import them from other modules using static import statements or dynamic import() expressions. Browsers load modules asynchronously and enforce strict mode by default. Each module has its own scope โ€” variables aren't global unless explicitly attached to window.

Named exports allow you to export multiple values from a module. You import them using curly braces: import { foo, bar } from './module.js'. You can have as many named exports as you want.

Default exports export a single "main" value from a module. You import it without curly braces: import foo from './module.js'. Each module can have at most one default export. You can also mix both styles in the same module โ€” a default export plus multiple named exports.

import() is a function-like expression that returns a Promise resolving to the module's namespace object. Unlike static import (which must be at the top level), import() can be called anywhere โ€” inside functions, conditionals, or event handlers. This enables lazy loading and code splitting, loading modules only when needed. Example: const module = await import('./heavy-module.js');. It's perfect for optimizing performance by deferring non-critical code.

ES Modules are supported in all modern browsers: Chrome (61+), Firefox (60+), Safari (11+), Edge (16+). Dynamic import() is supported in Chrome 63+, Firefox 67+, Safari 11.1+, Edge 79+. Import Maps are supported in Chrome 89+, Edge 89+, Firefox 108+, and Safari 16.4+. For older browsers, bundlers like Webpack, Rollup, or esbuild can compile ES modules down to compatible formats.

1. MIME type error: The server must serve .js files with Content-Type: application/javascript or text/javascript.
2. Missing type="module": Forgetting to add type="module" to the script tag.
3. CORS issues: Modules are fetched with CORS; cross-origin files need proper CORS headers.
4. Bare import specifiers: import 'lodash' doesn't work in browsers without Import Maps โ€” you need full URLs or relative paths.
5. File path errors: Import paths must start with ./, ../, or /.

Import Maps allow you to control how bare import specifiers are resolved in the browser. You define a <script type="importmap"> block with a JSON object mapping import names to URLs. For example: { "imports": { "lodash": "/node_modules/lodash/lodash.js" } }. This lets you write clean import lodash from 'lodash' without bundlers. This demo tool uses Import Maps internally to resolve module filenames to Blob URLs.
`; // Set up message listener const messageHandler = function(event) { if (event.data && event.data.type === 'console') { logToConsole(event.data.level, event.data.message); } else if (event.data && event.data.type === 'ready') { // Module script has been parsed and is executing } }; // Remove old listener and add new $(window).off('message.esdemo').on('message.esdemo', messageHandler); // Set a timeout for execution completion const executionTimeout = setTimeout(() => { finishExecution('success'); }, 800); // Handle iframe load $runnerFrame.off('load.esdemo').on('load.esdemo', function() { // The iframe has loaded. Module execution may still be in progress // (especially for dynamic imports). Give it some time. clearTimeout(executionTimeout); const extendedTimeout = setTimeout(() => { finishExecution('success'); }, 1500); // Store for cleanup $runnerFrame.data('extTimeout', extendedTimeout); }); // Set srcdoc to trigger execution $runnerFrame.attr('srcdoc', runnerHtml); // Fallback: if iframe doesn't trigger load quickly, finish anyway setTimeout(() => { if (isRunning) { finishExecution('success'); } }, 3000); } function finishExecution(status) { isRunning = false; $btnRun.prop('disabled', false); $statusDot.removeClass('running idle success error').addClass(status === 'error' ? 'error' : 'success'); $execStatus.text(status === 'error' ? 'Error' : 'Completed'); // Reset status dot after a moment setTimeout(() => { if (!isRunning) { $statusDot.removeClass('success error').addClass('idle'); $execStatus.text('Ready'); } }, 2500); } // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Load preset into editors // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ function loadPreset(presetName) { const preset = presets[presetName]; if (!preset) return; currentPreset = presetName; $codeMain.val(preset.main); $codeDep1.val(preset.dep1 || ''); $dep1Filename.val(preset.dep1Filename || 'module-a.js'); $dep1TabLabel.text(preset.dep1Filename || 'module-a.js'); $codeDep2.val(preset.dep2 || ''); $dep2Filename.val(preset.dep2Filename || 'module-b.js'); $dep2TabLabel.text(preset.dep2Filename || 'module-b.js'); showDep2 = preset.showDep2 || false; if (showDep2) { $dep2TabItem.show(); } else { $dep2TabItem.hide(); // If dep2 tab is active, switch to main if ($('#tab-dep2').hasClass('active')) { $moduleTabList.find('[data-module="main"]').tab('show'); } } // Switch to main tab $moduleTabList.find('[data-module="main"]').tab('show'); clearConsole(); logToConsole('info', 'Preset loaded: "' + $presetSelect.find('option:selected').text() + '" โ€” Click Run to execute', 'demo'); logToConsole('info', 'Edit the code in the editor panels, then press Run or Ctrl+Enter', 'demo'); $statusDot.removeClass('success error running').addClass('idle'); $execStatus.text('Ready'); cleanupBlobs(); } // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Add module handler // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ function addModule() { if (!showDep2) { showDep2 = true; $dep2TabItem.show(); $dep2Filename.val('module-b.js'); $dep2TabLabel.text('module-b.js'); if (!$codeDep2.val().trim()) { $codeDep2.val('// Additional module - add your exports here\nexport const greeting = "Hello from module-b!";\n'); } $moduleTabList.find('[data-module="dep2"]').tab('show'); logToConsole('info', 'Module 3 added. Use it in main.js with: import {...} from "./module-b.js"', 'demo'); } else { logToConsole('warn', 'Maximum of 3 modules (main + 2 dependencies) supported in this demo.', 'demo'); } } // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Event bindings // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ $btnRun.on('click', function() { clearConsole(); executeModules(); }); $btnClearConsole.on('click', function() { clearConsole(); logToConsole('info', 'Console cleared.', 'demo'); }); $presetSelect.on('change', function() { loadPreset($(this).val()); }); $btnAddModule.on('click', addModule); // Module tab switching $moduleTabList.on('click', '[data-module]', function(e) { e.preventDefault(); const module = $(this).data('module'); const tabMap = { main: '#tab-main', dep1: '#tab-dep1', dep2: '#tab-dep2' }; const target = tabMap[module]; if (!target) return; // Deactivate all tabs $moduleTabList.find('.nav-link').removeClass('active'); $(this).addClass('active'); // Show target pane $('#editorTabContent .tab-pane').removeClass('show active'); $(target).addClass('show active'); }); // Filename update handlers $dep1Filename.on('input', function() { const name = $(this).val().trim() || 'module-a.js'; $dep1TabLabel.text(name); }); $dep2Filename.on('input', function() { const name = $(this).val().trim() || 'module-b.js'; $dep2TabLabel.text(name); }); // Ctrl+Enter to run $(document).on('keydown', function(e) { if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); // Check if focus is within our demo if ($('#es-module-demo').has(document.activeElement).length || $(document.activeElement).closest('#es-module-demo').length) { clearConsole(); executeModules(); } } }); // Tab key handling in textareas (insert spaces instead of moving focus) $('#es-module-demo').on('keydown', 'textarea.code-textarea', function(e) { if (e.key === 'Tab') { e.preventDefault(); const textarea = this; const start = textarea.selectionStart; const end = textarea.selectionEnd; const value = textarea.value; const indent = ' '; // 2 spaces textarea.value = value.substring(0, start) + indent + value.substring(end); textarea.selectionStart = textarea.selectionEnd = start + indent.length; // Trigger input event for any listeners $(textarea).trigger('input'); } }); // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Initialize // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ function init() { loadPreset('named'); $presetSelect.val('named'); } // Run init when DOM is ready if (document.readyState === 'loading') { $(document).ready(init); } else { init(); } // Cleanup on page unload $(window).on('beforeunload', function() { cleanupBlobs(); }); })();