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
19 changes: 17 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,25 @@ permissions:

jobs:
test:
name: Test - ${{ matrix.os }} - Node ${{ matrix.node-version }}, Webpack ${{ matrix.webpack-version }}
name: Test - ${{ matrix.os }} - Node ${{ matrix.node-version }}, Babel ${{ matrix.babel-version }}, Webpack ${{ matrix.webpack-version }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 20, 22]
node-version: [20, 22, 24]
babel-version: ["7", "8"]
webpack-version: ["5"]
include:
- node-version: "18"
webpack-version: "5"
babel-version: "7"
os: ubuntu-latest
- node-version: "18"
webpack-version: "5"
babel-version: "7"
os: windows-latest
- node-version: "18.20.0" # The minimum supported node version
webpack-version: "5.61.0" # The minimum supported webpack version
babel-version: "7"
os: ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -29,6 +39,9 @@ jobs:
run: yarn
- name: Install webpack ${{ matrix.webpack-version }}
run: yarn add -D webpack@${{ matrix.webpack-version }}
- name: Downgrade to Babel 7
if: matrix.babel-version == '7'
run: yarn up @babel/*@^7
- name: Build babel-loader
run: yarn run build
- name: Run tests for webpack version ${{ matrix.webpack-version }}
Expand All @@ -50,6 +63,8 @@ jobs:
cache: "yarn"
- name: Install dependencies
run: yarn
- name: Run tsc
run: yarn tsc
- name: Run lint and coverage tests
run: yarn test
- name: Submit coverage data to codecov
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ test/output
.pnp.*
.vscode
scripts/test-legacy-source/output
tsconfig.tsbuildinfo
1 change: 0 additions & 1 deletion babel.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
[
"@babel/preset-env",
{
"bugfixes": true,
"modules": false
}
]
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
"find-up": "^5.0.0"
},
"peerDependencies": {
"@babel/core": "^7.12.0",
"@babel/core": "^7.12.0 || ^8.0.0-beta.1",
"webpack": ">=5.61.0"
},
"devDependencies": {
"@babel/cli": "^7.23.0",
"@babel/core": "^7.23.3",
"@babel/eslint-parser": "^7.23.3",
"@babel/preset-env": "^7.23.3",
"@babel/cli": "^8.0.0-beta.1",
"@babel/core": "^8.0.0-beta.1",
"@babel/eslint-parser": "^8.0.0-beta.1",
"@babel/preset-env": "^8.0.0-beta.1",
"c8": "^10.1.2",
"eslint": "^9.6.0",
"eslint-config-prettier": "^9.1.0",
Expand All @@ -29,6 +29,7 @@
"husky": "^9.1.5",
"lint-staged": "^15.2.9",
"prettier": "^3.0.0",
"typescript": "^5.8.3",
"webpack": "^5.93.0"
},
"scripts": {
Expand All @@ -38,7 +39,7 @@
"lint": "eslint src test",
"precommit": "lint-staged",
"prepublish": "yarn run clean && yarn run build",
"preversion": "yarn run test",
"preversion": "yarn tsc && yarn run test",
"test": "yarn run lint && yarn run build --source-maps && c8 yarn run test-only",
"test-only": "node --test test/**/*.test.js"
},
Expand Down
12 changes: 12 additions & 0 deletions src/Error.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
// @ts-check
const STRIP_FILENAME_RE = /^[^:]+: /;

/**
* @typedef { Error & { hideStack?: boolean, codeFrame?: string } } BabelLoaderError
*/
/**
* Format the error for display.
* @param {BabelLoaderError} err
* @returns {BabelLoaderError}
*/
const format = err => {
if (err instanceof SyntaxError) {
err.name = "SyntaxError";
Expand All @@ -17,6 +26,9 @@ const format = err => {
};

class LoaderError extends Error {
/**
* @param {BabelLoaderError} err
*/
constructor(err) {
super();

Expand Down
108 changes: 84 additions & 24 deletions src/cache.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-check
/**
* Filesystem Cache
*
Expand All @@ -17,6 +18,27 @@ const { sync: findUpSync } = require("find-up");
const { env } = process;
const transform = require("./transform");
const serialize = require("./serialize");
/**
* @typedef {object} FileSystemInfoEntry
* @property {number} safeTime
* @property {number} timestamp
*/
/**
* @typedef {object} WebpackLogger
* @property {function(string): void} debug
* @property {function(string): void} info
* @property {function(string): void} warn
* @property {function(string): void} error
*/
/**
* @typedef {object} WebpackHash
* @property {(data: string | Buffer, inputEncoding?: string) => WebpackHash} update
* @property {(encoding?: string) => string | Buffer} digest
*/

/**
* @type {string | null}
*/
let defaultCacheDirectory = null;

const gunzip = promisify(zlib.gunzip);
Expand All @@ -35,8 +57,8 @@ const findRootPackageJSON = () => {
* Read the contents from the compressed file.
*
* @async
* @params {String} filename
* @params {Boolean} compress
* @param {string} filename
* @param {boolean} compress
*/
const read = async function (filename, compress) {
const data = await readFile(filename + (compress ? ".gz" : ""));
Expand All @@ -47,11 +69,10 @@ const read = async function (filename, compress) {

/**
* Write contents into a compressed file.
*
* @async
* @params {String} filename
* @params {Boolean} compress
* @params {String} result
* @param {string} filename
* @param {boolean} compress
* @param {any} result
*/
const write = async function (filename, compress, result) {
const content = JSON.stringify(result);
Expand All @@ -62,18 +83,24 @@ const write = async function (filename, compress, result) {

/**
* Build the filename for the cached file
*
* @params {String} source File source code
* @params {Object} options Options used
*
* @return {String}
* @param {string} source File source code
* @param {string} identifier Unique identifier to bust cache
* @param {Object} options Options used
* @param {WebpackHash} hash Hash function returned by `LoaderContext.utils.createHash`
* @return {string}
*/
const filename = function (source, identifier, options, hash) {
hash.update(serialize([options, source, identifier]));

return hash.digest("hex") + ".json";
};

/**
* Add timestamps to external dependencies.
* @async
* @param {import("./transform").TransformResult["externalDependencies"]} externalDependencies
* @param {(filename: string) => Promise<FileSystemInfoEntry>} getFileTimestamp
*/
const addTimestamps = async function (externalDependencies, getFileTimestamp) {
for (const depAndEmptyTimestamp of externalDependencies) {
try {
Expand All @@ -86,6 +113,13 @@ const addTimestamps = async function (externalDependencies, getFileTimestamp) {
}
};

/**
* Check if any external dependencies have been modified.
* @async
* @param {import("./transform").TransformResult["externalDependencies"]} externalDepsWithTimestamp
* @param {(filename: string) => Promise<FileSystemInfoEntry>} getFileTimestamp
* @returns {Promise<boolean>}
*/
const areExternalDependenciesModified = async function (
externalDepsWithTimestamp,
getFileTimestamp,
Expand All @@ -107,9 +141,18 @@ const areExternalDependenciesModified = async function (

/**
* Handle the cache
*
* @params {String} directory
* @params {Object} params
* @async
* @param {string} directory
* @param {Object} params
* @param {string} params.source The source code to transform.
* @param {import(".").NormalizedOptions} [params.options] Options used for transformation.
* @param {string} params.cacheIdentifier Unique identifier to bust cache.
* @param {string} [params.cacheDirectory] Directory to store cached files.
* @param {boolean} [params.cacheCompression] Whether to compress cached files.
* @param {WebpackHash} params.hash Hash function to use for the cache filename.
* @param {(filename: string) => Promise<FileSystemInfoEntry>} params.getFileTimestamp - Function to get file timestamps.
* @param {WebpackLogger} params.logger
* @returns {Promise<null | import("./transform").TransformResult>}
*/
const handleCache = async function (directory, params) {
const {
Expand Down Expand Up @@ -170,6 +213,10 @@ const handleCache = async function (directory, params) {
// return it to the user asap and write it in cache
logger.debug(`applying Babel transform`);
const result = await transform(source, options);
if (!result) {
logger.debug(`no result from Babel transform, skipping cache write`);
return null;
}
await addTimestamps(result.externalDependencies, getFileTimestamp);

try {
Expand All @@ -189,14 +236,17 @@ const handleCache = async function (directory, params) {

/**
* Retrieve file from cache, or create a new one for future reads
*
* @async
* @param {Object} params
* @param {String} params.cacheDirectory Directory to store cached files
* @param {String} params.cacheIdentifier Unique identifier to bust cache
* @param {Boolean} params.cacheCompression Whether compressing cached files
* @param {String} params.source Original contents of the file to be cached
* @param {Object} params.options Options to be given to the transform fn
* @param {object} params
* @param {string} params.cacheDirectory Directory to store cached files.
* @param {string} params.cacheIdentifier Unique identifier to bust cache.
* @param {boolean} params.cacheCompression Whether compressing cached files.
* @param {string} params.source Original contents of the file to be cached.
* @param {import(".").NormalizedOptions} params.options Options to be given to the transform function.
* @param {function} params.transform Transform function to apply to the file.
* @param {WebpackHash} params.hash Hash function to use for the cache filename.
* @param {function(string): Promise<FileSystemInfoEntry>} params.getFileTimestamp Function to get file timestamps.
* @param {WebpackLogger} params.logger Logger instance.
*
* @example
*
Expand All @@ -212,7 +262,7 @@ const handleCache = async function (directory, params) {
* });
*/

module.exports = async function (params) {
module.exports = async function cache(params) {
let directory;

if (typeof params.cacheDirectory === "string") {
Expand All @@ -225,13 +275,23 @@ module.exports = async function (params) {
return await handleCache(directory, params);
};

/**
* Find the cache directory for babel-loader.
* @param {string} name "babel-loader"
* @returns {string}
*/
function findCacheDir(name) {
if (env.CACHE_DIR && !["true", "false", "1", "0"].includes(env.CACHE_DIR)) {
return path.join(env.CACHE_DIR, name);
}
const rootPkgJSONPath = path.dirname(findRootPackageJSON());
const rootPkgJSONPath = findRootPackageJSON();
if (rootPkgJSONPath) {
return path.join(rootPkgJSONPath, "node_modules", ".cache", name);
return path.join(
path.dirname(rootPkgJSONPath),
"node_modules",
".cache",
name,
);
}
return os.tmpdir();
}
Loading