sindresorhus / import-fresh

Import a module while bypassing the cache
MIT License
283 stars 24 forks source link

Problem bundling with webpack #21

Open christianvoigt opened 3 years ago

christianvoigt commented 3 years ago

Hi, I just stumbled over bundling import-fresh with webpack. Webpack will not ignore the dynamic require calls and so this package will fail after bundling.

See here for a detailed description of the issue and my workaround.

An easy fix would be to add the "magic comments" to your code:

return parent === undefined ? require(/* webpackIgnore: true */ filePath) : parent.require(/* webpackIgnore: true */ filePath);

Users that want to bundle your package with webpack would still have to activate "magic comments" for require in their webpack config, so maybe there is a better solution for this.

jeremiegirault commented 3 years ago

Hello I used the following patch to make it work.

diff --git a/index.js b/index.js
index 0a4c5d52f6d32274d3032c2c7cf513ac8d1a81af..2a5e387c83a6657d57c96dfce9802facde065abe 100644
--- a/index.js
+++ b/index.js
@@ -3,6 +3,8 @@ const path = require('path');
 const resolveFrom = require('resolve-from');
 const parentModule = require('parent-module');

+const dynamicRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
+
 module.exports = moduleId => {
    if (typeof moduleId !== 'string') {
        throw new TypeError('Expected a string');
@@ -13,7 +15,7 @@ module.exports = moduleId => {
    const cwd = parentPath ? path.dirname(parentPath) : __dirname;
    const filePath = resolveFrom(cwd, moduleId);

-   const oldModule = require.cache[filePath];
+   const oldModule = dynamicRequire.cache[filePath];
    // Delete itself from module parent
    if (oldModule && oldModule.parent) {
        let i = oldModule.parent.children.length;
@@ -25,9 +27,9 @@ module.exports = moduleId => {
        }
    }

-   delete require.cache[filePath]; // Delete module from cache
+   delete dynamicRequire.cache[filePath]; // Delete module from cache

-   const parent = require.cache[parentPath]; // If `filePath` and `parentPath` are the same, cache will already be deleted so we won't get a memory leak in next step
+   const parent = dynamicRequire.cache[parentPath]; // If `filePath` and `parentPath` are the same, cache will already be deleted so we won't get a memory leak in next step

-   return parent === undefined ? require(filePath) : parent.require(filePath); // In case cache doesn't have parent, fall back to normal require
+   return parent === undefined ? dynamicRequire(filePath) : parent.require(filePath); // In case cache doesn't have parent, fall back to normal require
 };
jeremiegirault commented 3 years ago

I also managed to make use of dynamic requires in node by using import { Module } from 'module' and use Module.createRequire in some of my packages to create a require function that is ignored by webpack

jeremiegirault commented 3 years ago

I also managed to write a babel plugin that I apply to this module using babel-loader and proper 'include' rule and managed to make it work through webpack without modification. I expect to make it work with other modules (currently my target is to webpack eslint)

You can look at this gist :

https://gist.github.com/jeremiegirault/11018bc6aec790ca8d3714f5e0a1bd35