Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,19 @@ const handleCache = async function (directory, params) {
// return it to the user asap and write it in cache
const result = await transform(source, options);

try {
await write(file, cacheCompression, result);
} catch (err) {
if (fallback) {
// Fallback to tmpdir if node_modules folder not writable
return handleCache(os.tmpdir(), params);
// Do not cache if there are external dependencies,
// since they might change and we cannot control it.
if (!result.externalDependencies.length) {
try {
await write(file, cacheCompression, result);
} catch (err) {
if (fallback) {
// Fallback to tmpdir if node_modules folder not writable
return handleCache(os.tmpdir(), params);
}

throw err;
}

throw err;
}

return result;
Expand Down
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,9 @@ async function loader(source, inputSourceMap, overrides) {
});
}

const { code, map, metadata } = result;
const { code, map, metadata, externalDependencies } = result;

externalDependencies?.forEach(dep => this.addDependency(dep));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we use optional chaining here because we can't control the return type of overrides.result? If so we might consider convert babel-loader to ts and publish typings.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I added ? because current overrides.result functions probably don't return externalDependencies, if they replace the result object.

metadataSubscribers.forEach(subscriber => {
subscribe(subscriber, metadata, this);
});
Expand Down
12 changes: 10 additions & 2 deletions src/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,21 @@ module.exports = async function (source, options) {
// https://github.com/babel/babel/blob/main/packages/babel-core/src/transformation/index.js
// For discussion on this topic see here:
// https://github.com/babel/babel-loader/pull/629
const { ast, code, map, metadata, sourceType } = result;
const { ast, code, map, metadata, sourceType, externalDependencies } = result;

if (map && (!map.sourcesContent || !map.sourcesContent.length)) {
map.sourcesContent = [source];
}

return { ast, code, map, metadata, sourceType };
return {
ast,
code,
map,
metadata,
sourceType,
// Convert it from a Set to an Array to make it JSON-serializable.
externalDependencies: Array.from(externalDependencies || []),
};
};

module.exports.version = babel.version;
35 changes: 35 additions & 0 deletions test/loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,38 @@ test.cb("should load ESM config files", t => {
t.end();
});
});

test.cb("should track external dependencies", t => {
const dep = path.join(__dirname, "fixtures/metadata.js");
const config = Object.assign({}, globalConfig, {
entry: path.join(__dirname, "fixtures/constant.js"),
output: {
path: t.context.directory,
},
module: {
rules: [
{
test: /\.js$/,
loader: babelLoader,
options: {
babelrc: false,
configFile: false,
plugins: [
api => {
api.cache.never();
api.addExternalDependency(dep);
return { visitor: {} };
},
],
},
},
],
},
});

webpack(config, (err, stats) => {
t.true(stats.compilation.fileDependencies.has(dep));
t.deepEqual(stats.compilation.warnings, []);
t.end();
});
});