diff --git a/packages/commonjs/src/generate-imports.js b/packages/commonjs/src/generate-imports.js index d624ab25c..7fb85393d 100644 --- a/packages/commonjs/src/generate-imports.js +++ b/packages/commonjs/src/generate-imports.js @@ -1,7 +1,3 @@ -import { dirname, resolve } from 'path'; - -import { sync as nodeResolveSync } from 'resolve'; - import { DYNAMIC_MODULES_ID, EXPORTS_SUFFIX, @@ -12,9 +8,8 @@ import { MODULE_SUFFIX, wrapId } from './helpers'; -import { normalizePathSlashes } from './utils'; -export function isRequireStatement(node, scope) { +export function isRequireExpression(node, scope) { if (!node) return false; if (node.type !== 'CallExpression') return false; @@ -24,7 +19,7 @@ export function isRequireStatement(node, scope) { return isRequire(node.callee, scope); } -function isRequire(node, scope) { +export function isRequire(node, scope) { return ( (node.type === 'Identifier' && node.name === 'require' && !scope.contains('require')) || (node.type === 'MemberExpression' && isModuleRequire(node, scope)) @@ -41,12 +36,7 @@ export function isModuleRequire({ object, property }, scope) { ); } -export function isStaticRequireStatement(node, scope) { - if (!isRequireStatement(node, scope)) return false; - return !hasDynamicArguments(node); -} - -function hasDynamicArguments(node) { +export function hasDynamicArguments(node) { return ( node.arguments.length > 1 || (node.arguments[0].type !== 'Literal' && @@ -60,41 +50,12 @@ export function isNodeRequirePropertyAccess(parent) { return parent && parent.property && reservedMethod[parent.property.name]; } -export function isIgnoredRequireStatement(requiredNode, ignoreRequire) { - return ignoreRequire(requiredNode.arguments[0].value); -} - export function getRequireStringArg(node) { return node.arguments[0].type === 'Literal' ? node.arguments[0].value : node.arguments[0].quasis[0].value.cooked; } -export function hasDynamicModuleForPath(source, id, dynamicRequireModules) { - if (!/^(?:\.{0,2}[/\\]|[A-Za-z]:[/\\])/.test(source)) { - try { - const resolvedPath = normalizePathSlashes(nodeResolveSync(source, { basedir: dirname(id) })); - if (dynamicRequireModules.has(resolvedPath)) { - return true; - } - } catch (ex) { - // Probably a node.js internal module - return false; - } - - return false; - } - - for (const attemptExt of ['', '.js', '.json']) { - const resolvedPath = normalizePathSlashes(resolve(dirname(id), source + attemptExt)); - if (dynamicRequireModules.has(resolvedPath)) { - return true; - } - } - - return false; -} - export function getRequireHandlers() { const requireExpressions = []; diff --git a/packages/commonjs/src/index.js b/packages/commonjs/src/index.js index cf68d552b..337f41830 100644 --- a/packages/commonjs/src/index.js +++ b/packages/commonjs/src/index.js @@ -67,7 +67,6 @@ export default function commonjs(options = {}) { typeof options.dynamicRequireRoot === 'string' ? resolve(options.dynamicRequireRoot) : process.cwd(); - // TODO Lukas throw if require from outside commondir const { commonDir, dynamicRequireModules } = getDynamicRequireModules( options.dynamicRequireTargets, dynamicRequireRoot diff --git a/packages/commonjs/src/transform-commonjs.js b/packages/commonjs/src/transform-commonjs.js index 509685256..e4147d4cd 100644 --- a/packages/commonjs/src/transform-commonjs.js +++ b/packages/commonjs/src/transform-commonjs.js @@ -20,12 +20,11 @@ import { rewriteExportsAndGetExportsBlock, wrapCode } from './generate-exports'; import { getRequireHandlers, getRequireStringArg, - hasDynamicModuleForPath, - isIgnoredRequireStatement, + hasDynamicArguments, isModuleRequire, isNodeRequirePropertyAccess, - isRequireStatement, - isStaticRequireStatement + isRequire, + isRequireExpression } from './generate-imports'; import { IS_WRAPPED_COMMONJS } from './helpers'; import { tryParse } from './parse'; @@ -77,12 +76,6 @@ export default async function transformCommonjs( // unconditional require elsewhere. let currentConditionalNodeEnd = null; const conditionalNodes = new Set(); - - // TODO Lukas fix this at last, we are close - // TODO technically wrong since globals isn't populated yet, but ¯\_(ツ)_/¯ - const helpersName = deconflict([scope], globals, 'commonjsHelpers'); - const dynamicRequireName = deconflict([scope], globals, 'commonjsRequire'); - const { addRequireStatement, rewriteRequireExpressionsAndGetImportBlock } = getRequireHandlers(); // See which names are assigned to. This is necessary to prevent @@ -98,6 +91,8 @@ export default async function transformCommonjs( const exportsAssignmentsByName = new Map(); const topLevelAssignments = new Set(); const topLevelDefineCompiledEsmExpressions = []; + const replacedGlobal = []; + const replacedDynamicRequires = []; walk(ast, { enter(node, parent) { @@ -198,12 +193,12 @@ export default async function transformCommonjs( // Transform require.resolve if ( + isDynamicRequireModulesEnabled && node.callee.object && - node.callee.object.name === 'require' && - node.callee.property.name === 'resolve' && - hasDynamicModuleForPath(id, '/', dynamicRequireModules) + isRequire(node.callee.object, scope) && + node.callee.property.name === 'resolve' ) { - // TODO Lukas reimplement? + checkDynamicRequire(); uses.require = true; const requireNode = node.callee.object; magicString.appendLeft( @@ -212,25 +207,38 @@ export default async function transformCommonjs( dirname(id) === '.' ? null /* default behavior */ : virtualDynamicRequirePath )}` ); - magicString.overwrite(requireNode.start, requireNode.end, dynamicRequireName, { - storeName: true - }); + replacedDynamicRequires.push(requireNode); return; } - // Ignore call expressions of dynamic requires, the callee will be transformed within Identifier - if (!isStaticRequireStatement(node, scope)) { + if (!isRequireExpression(node, scope)) { return; } - // Otherwise we do not want to replace "require" with the internal helper skippedNodes.add(node.callee); uses.require = true; - if (!isIgnoredRequireStatement(node, ignoreRequire)) { + if (hasDynamicArguments(node)) { + if (isDynamicRequireModulesEnabled) { + magicString.appendLeft( + node.end - 1, + `, ${JSON.stringify( + dirname(id) === '.' ? null /* default behavior */ : virtualDynamicRequirePath + )}` + ); + } + if (!ignoreDynamicRequires) { + checkDynamicRequire(); + replacedDynamicRequires.push(node.callee); + } + return; + } + + const requireStringArg = getRequireStringArg(node); + if (!ignoreRequire(requireStringArg)) { const usesReturnValue = parent.type !== 'ExpressionStatement'; addRequireStatement( - getRequireStringArg(node), + requireStringArg, node, scope, usesReturnValue, @@ -275,35 +283,14 @@ export default async function transformCommonjs( case 'require': uses.require = true; if (isNodeRequirePropertyAccess(parent)) { - // TODO Lukas reimplement? - if (hasDynamicModuleForPath(id, '/', dynamicRequireModules)) { - if (parent.property.name === 'cache') { - magicString.overwrite(node.start, node.end, dynamicRequireName, { - storeName: true - }); - } - } - return; } - - if (isDynamicRequireModulesEnabled && isRequireStatement(parent, scope)) { - magicString.appendLeft( - parent.end - 1, - `, ${JSON.stringify( - dirname(id) === '.' ? null /* default behavior */ : virtualDynamicRequirePath - )}` - ); - } if (!ignoreDynamicRequires) { checkDynamicRequire(); if (isShorthandProperty(parent)) { - magicString.appendRight(node.end, `: ${dynamicRequireName}`); - } else { - magicString.overwrite(node.start, node.end, dynamicRequireName, { - storeName: true - }); + magicString.prependRight(node.start, 'require: '); } + replacedDynamicRequires.push(node); } return; case 'module': @@ -314,9 +301,7 @@ export default async function transformCommonjs( case 'global': uses.global = true; if (!ignoreGlobal) { - magicString.overwrite(node.start, node.end, `${helpersName}.commonjsGlobal`, { - storeName: true - }); + replacedGlobal.push(node); } return; case 'define': @@ -348,9 +333,7 @@ export default async function transformCommonjs( case 'MemberExpression': if (!isDynamicRequireModulesEnabled && isModuleRequire(node, scope)) { uses.require = true; - magicString.overwrite(node.start, node.end, dynamicRequireName, { - storeName: true - }); + replacedDynamicRequires.push(node); skippedNodes.add(node.object); skippedNodes.add(node.property); } @@ -366,9 +349,7 @@ export default async function transformCommonjs( if (lexicalDepth === 0) { uses.global = true; if (!ignoreGlobal) { - magicString.overwrite(node.start, node.end, `${helpersName}.commonjsGlobal`, { - storeName: true - }); + replacedGlobal.push(node); } } return; @@ -376,6 +357,9 @@ export default async function transformCommonjs( if (currentTryBlockEnd === null) { currentTryBlockEnd = node.block.end; } + if (currentConditionalNodeEnd === null) { + currentConditionalNodeEnd = node.end; + } return; case 'UnaryExpression': // rewrite `typeof module`, `typeof module.exports` and `typeof exports` (https://github.com/rollup/rollup-plugin-commonjs/issues/151) @@ -415,11 +399,25 @@ export default async function transformCommonjs( const moduleName = deconflict([...moduleAccessScopes], globals, `${nameBase}Module`); const requireName = deconflict([scope], globals, `require${capitalize(nameBase)}`); const isRequiredName = deconflict([scope], globals, `hasRequired${capitalize(nameBase)}`); + const helpersName = deconflict([scope], globals, 'commonjsHelpers'); + const dynamicRequireName = deconflict([scope], globals, 'commonjsRequire'); const deconflictedExportNames = Object.create(null); for (const [exportName, { scopes }] of exportsAssignmentsByName) { deconflictedExportNames[exportName] = deconflict([...scopes], globals, exportName); } + for (const node of replacedGlobal) { + magicString.overwrite(node.start, node.end, `${helpersName}.commonjsGlobal`, { + storeName: true + }); + } + for (const node of replacedDynamicRequires) { + magicString.overwrite(node.start, node.end, dynamicRequireName, { + contentOnly: true, + storeName: true + }); + } + // We cannot wrap ES/mixed modules shouldWrap = !isEsModule && (shouldWrap || (uses.exports && moduleExportsAssignments.length > 0)); const detectWrappedDefault = diff --git a/packages/commonjs/test/fixtures/function/dynamic-module-require/_config.js b/packages/commonjs/test/fixtures/function/dynamic-module-require/_config.js index be6712858..0693ea19d 100755 --- a/packages/commonjs/test/fixtures/function/dynamic-module-require/_config.js +++ b/packages/commonjs/test/fixtures/function/dynamic-module-require/_config.js @@ -1,6 +1,4 @@ module.exports = { - // TODO Lukas think about a way to re-implement - skip: true, description: 'supports dynamic require', pluginOptions: { dynamicRequireTargets: ['fixtures/function/dynamic-module-require/submodule.js'] diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/_config.js b/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/_config.js deleted file mode 100755 index c72a299c4..000000000 --- a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/_config.js +++ /dev/null @@ -1,15 +0,0 @@ -const { nodeResolve } = require('@rollup/plugin-node-resolve'); - -module.exports = { - // TODO Lukas re-enable cache-handling in some way - skip: true, - description: 'accesses commonjsRequire.cache', - options: { - plugins: [nodeResolve()] - }, - pluginOptions: { - dynamicRequireTargets: [ - 'fixtures/function/dynamic-require-cache-reference/node_modules/{custom-module,custom-module2}{,/*.js}' - ] - } -}; diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/main.js b/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/main.js deleted file mode 100755 index b60c0f9dd..000000000 --- a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/main.js +++ /dev/null @@ -1,5 +0,0 @@ -const a = require('custom-module2'); -const b = require('custom-module'); - -t.is(a.foo, 'baz'); -t.is(b.foo, 'bar'); diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/custom-module/index.js b/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/custom-module/index.js deleted file mode 100755 index 5b4c8fd7a..000000000 --- a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/custom-module/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - foo: 'bar', -}; diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/custom-module2/index.js b/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/custom-module2/index.js deleted file mode 100755 index 1e06b7638..000000000 --- a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/custom-module2/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const stealthRequire = require('stealthy'); - -module.exports = stealthRequire(require.cache, () => { - let m = require('custom-module'); - m.foo = 'baz'; - return m; -}); diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/stealthy/index.js b/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/stealthy/index.js deleted file mode 100644 index 20b1da1c0..000000000 --- a/packages/commonjs/test/fixtures/function/dynamic-require-cache-reference/node_modules/stealthy/index.js +++ /dev/null @@ -1,25 +0,0 @@ -function mv(from, to) { - for (let [key, value] of Object.entries(from)) { - to[key] = value; - } -} - -function clear(obj) { - for (let key of Array.from(Object.keys(obj))) { - delete obj[key]; - } -} - -module.exports = function stealth(cacheObject, cb) { - let orig = Object.create(null); - - mv(cacheObject, orig) - clear(cacheObject) - - let res = cb(); - - clear(cacheObject) - mv(orig, cacheObject) - - return res; -}; diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/main.js b/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/main.js index a30e03d98..90dd10156 100755 --- a/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/main.js +++ b/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/main.js @@ -1,3 +1,7 @@ +t.is( + require('custom-module')(), + '/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2' +); t.is( require('custom-module2')(), '/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module' diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module/index.js b/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module/index.js index 5b4c8fd7a..7eabc0d90 100755 --- a/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module/index.js +++ b/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module/index.js @@ -1,3 +1 @@ -module.exports = { - foo: 'bar', -}; +module.exports = () => module.require.resolve('custom-module2'); diff --git a/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2/index.js b/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2/index.js index 4ffedfe58..f7ec4a019 100755 --- a/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2/index.js +++ b/packages/commonjs/test/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2/index.js @@ -1,3 +1 @@ -module.exports = () => { - return require.resolve('custom-module'); -}; +module.exports = () => require.resolve('custom-module'); diff --git a/packages/commonjs/test/fixtures/function/try-catch-internal/main.js b/packages/commonjs/test/fixtures/function/try-catch-internal/main.js index df773bb29..5d3875d55 100644 --- a/packages/commonjs/test/fixtures/function/try-catch-internal/main.js +++ b/packages/commonjs/test/fixtures/function/try-catch-internal/main.js @@ -5,3 +5,9 @@ try { } catch (err) { throw new Error(`Could not require: ${err}`); } + +try { + require('./throws.js'); +} catch (err) { + t.is(err.message, 'Expected error'); +} diff --git a/packages/commonjs/test/fixtures/function/try-catch-internal/throws.js b/packages/commonjs/test/fixtures/function/try-catch-internal/throws.js new file mode 100644 index 000000000..dcf80a10e --- /dev/null +++ b/packages/commonjs/test/fixtures/function/try-catch-internal/throws.js @@ -0,0 +1 @@ +throw new Error('Expected error'); diff --git a/packages/commonjs/test/snapshots/function.js.md b/packages/commonjs/test/snapshots/function.js.md index 574c79cc3..b30e1811d 100644 --- a/packages/commonjs/test/snapshots/function.js.md +++ b/packages/commonjs/test/snapshots/function.js.md @@ -390,6 +390,140 @@ Generated by [AVA](https://avajs.dev). `, } +## dynamic-module-require + +> Snapshot 1 + + { + 'main.js': `'use strict';␊ + ␊ + var submodule;␊ + var hasRequiredSubmodule;␊ + ␊ + function requireSubmodule () {␊ + if (hasRequiredSubmodule) return submodule;␊ + hasRequiredSubmodule = 1;␊ + submodule = function () {␊ + return 'Hello there';␊ + };␊ + return submodule;␊ + }␊ + ␊ + var dynamicModules;␊ + ␊ + function getDynamicModules() {␊ + return dynamicModules || (dynamicModules = {␊ + "/fixtures/function/dynamic-module-require/submodule.js": requireSubmodule␊ + });␊ + }␊ + ␊ + function commonjsRequire(path, originalModuleDir) {␊ + var resolvedPath = commonjsResolveImpl(path, originalModuleDir);␊ + if (resolvedPath !== null) {␊ + return getDynamicModules()[resolvedPath]();␊ + }␊ + throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');␊ + }␊ + ␊ + function commonjsResolve (path, originalModuleDir) {␊ + const resolvedPath = commonjsResolveImpl(path, originalModuleDir);␊ + if (resolvedPath !== null) {␊ + return resolvedPath;␊ + }␊ + return require.resolve(path);␊ + }␊ + ␊ + commonjsRequire.resolve = commonjsResolve;␊ + ␊ + function commonjsResolveImpl (path, originalModuleDir) {␊ + var shouldTryNodeModules = isPossibleNodeModulesPath(path);␊ + path = normalize(path);␊ + var relPath;␊ + if (path[0] === '/') {␊ + originalModuleDir = '';␊ + }␊ + var modules = getDynamicModules();␊ + var checkedExtensions = ['', '.js', '.json'];␊ + while (true) {␊ + if (!shouldTryNodeModules) {␊ + relPath = normalize(originalModuleDir + '/' + path);␊ + } else {␊ + relPath = normalize(originalModuleDir + '/node_modules/' + path);␊ + }␊ + ␊ + if (relPath.endsWith('/..')) {␊ + break; // Travelled too far up, avoid infinite loop␊ + }␊ + ␊ + for (var extensionIndex = 0; extensionIndex < checkedExtensions.length; extensionIndex++) {␊ + var resolvedPath = relPath + checkedExtensions[extensionIndex];␊ + if (modules[resolvedPath]) {␊ + return resolvedPath;␊ + }␊ + }␊ + if (!shouldTryNodeModules) break;␊ + var nextDir = normalize(originalModuleDir + '/..');␊ + if (nextDir === originalModuleDir) break;␊ + originalModuleDir = nextDir;␊ + }␊ + return null;␊ + }␊ + ␊ + function isPossibleNodeModulesPath (modulePath) {␊ + var c0 = modulePath[0];␊ + if (c0 === '/' || c0 === '\\\\') return false;␊ + var c1 = modulePath[1], c2 = modulePath[2];␊ + if ((c0 === '.' && (!c1 || c1 === '/' || c1 === '\\\\')) ||␊ + (c0 === '.' && c1 === '.' && (!c2 || c2 === '/' || c2 === '\\\\'))) return false;␊ + if (c1 === ':' && (c2 === '/' || c2 === '\\\\')) return false;␊ + return true;␊ + }␊ + ␊ + function normalize (path) {␊ + path = path.replace(/\\\\/g, '/');␊ + var parts = path.split('/');␊ + var slashed = parts[0] === '';␊ + for (var i = 1; i < parts.length; i++) {␊ + if (parts[i] === '.' || parts[i] === '') {␊ + parts.splice(i--, 1);␊ + }␊ + }␊ + for (var i = 1; i < parts.length; i++) {␊ + if (parts[i] !== '..') continue;␊ + if (i > 0 && parts[i - 1] !== '..' && parts[i - 1] !== '.') {␊ + parts.splice(--i, 2);␊ + i--;␊ + }␊ + }␊ + path = parts.join('/');␊ + if (slashed && path[0] !== '/') path = '/' + path;␊ + else if (path.length === 0) path = '.';␊ + return path;␊ + }␊ + ␊ + var main = {};␊ + ␊ + /* eslint-disable import/no-dynamic-require, global-require */␊ + ␊ + let message;␊ + ␊ + function takeModule(withName) {␊ + return commonjsRequire(`./${withName}`, "/fixtures/function/dynamic-module-require");␊ + }␊ + ␊ + try {␊ + const submodule = takeModule('submodule');␊ + message = submodule();␊ + } catch (err) {␊ + ({ message } = err);␊ + }␊ + ␊ + t.is(message, 'Hello there');␊ + ␊ + module.exports = main;␊ + `, + } + ## dynamic-require > Snapshot 1 @@ -2139,16 +2273,17 @@ Generated by [AVA](https://avajs.dev). { 'main.js': `'use strict';␊ ␊ - var customModule;␊ + var customModule = {exports: {}};␊ + ␊ var hasRequiredCustomModule;␊ ␊ function requireCustomModule () {␊ - if (hasRequiredCustomModule) return customModule;␊ + if (hasRequiredCustomModule) return customModule.exports;␊ hasRequiredCustomModule = 1;␊ - customModule = {␊ - foo: 'bar',␊ - };␊ - return customModule;␊ + (function (module) {␊ + module.exports = () => commonjsRequire.resolve('custom-module2',"/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module");␊ + } (customModule));␊ + return customModule.exports;␊ }␊ ␊ var customModule2;␊ @@ -2157,9 +2292,7 @@ Generated by [AVA](https://avajs.dev). function requireCustomModule2 () {␊ if (hasRequiredCustomModule2) return customModule2;␊ hasRequiredCustomModule2 = 1;␊ - customModule2 = () => {␊ - return commonjsRequire.resolve('custom-module',"/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2");␊ - };␊ + customModule2 = () => commonjsRequire.resolve('custom-module',"/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2");␊ return customModule2;␊ }␊ ␊ @@ -2260,6 +2393,10 @@ Generated by [AVA](https://avajs.dev). ␊ var main = {};␊ ␊ + t.is(␊ + requireCustomModule()(),␊ + '/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module2'␊ + );␊ t.is(␊ requireCustomModule2()(),␊ '/fixtures/function/dynamic-require-resolve-reference/node_modules/custom-module'␊ @@ -6996,16 +7133,39 @@ Generated by [AVA](https://avajs.dev). ␊ var dep = {};␊ ␊ - dep.foo = 'foo';␊ + var hasRequiredDep;␊ + ␊ + function requireDep () {␊ + if (hasRequiredDep) return dep;␊ + hasRequiredDep = 1;␊ + dep.foo = 'foo';␊ + return dep;␊ + }␊ + ␊ + var throws = {};␊ + ␊ + var hasRequiredThrows;␊ + ␊ + function requireThrows () {␊ + if (hasRequiredThrows) return throws;␊ + hasRequiredThrows = 1;␊ + throw new Error('Expected error');␊ + }␊ ␊ /* eslint-disable global-require */␊ ␊ try {␊ - t.is(dep.foo, 'foo');␊ + t.is(requireDep().foo, 'foo');␊ } catch (err) {␊ throw new Error(`Could not require: ${err}`);␊ }␊ ␊ + try {␊ + requireThrows();␊ + } catch (err) {␊ + t.is(err.message, 'Expected error');␊ + }␊ + ␊ module.exports = main;␊ `, } diff --git a/packages/commonjs/test/snapshots/function.js.snap b/packages/commonjs/test/snapshots/function.js.snap index ac9d53cf6..a4ae4968c 100644 Binary files a/packages/commonjs/test/snapshots/function.js.snap and b/packages/commonjs/test/snapshots/function.js.snap differ