file-replace-loader
v1.4.3
Published
file-replace-loader is webpack loader that allows you replace files in compile time
Maintainers
Readme
file-replace-loader
file-replace-loader is a webpack loader that allows you to replace files at compile time based on conditions.
file-replace-loader is free and will always remain free A simple and quick way to support the project is to buy me a coffee. It will take no more than 5 minutes and will allow the project to keep going
Table of contents
- Features
- Installation
- Usage
- Multiple replace
- Using with binary files
- Using with other loaders
- Loader options
- Contributing
- License
Features
- Compatibility with webpack 3.x, 4.x, 5.x;
- Supports webpack watch mode;
- Replace files at compile time without changing source files;
- Multiple replacement;
- Sync and async modes;
- Compatibility with other loaders;
- Support binary files.
Installation
NPM
npm install --save-dev file-replace-loader
Yarn
yarn add file-replace-loader
Usage
const { resolve } = require('path');
module.exports = {
//...
module: {
rules: [{
test: /\.config\.js$/,
loader: 'file-replace-loader',
options: {
condition: 'if-replacement-exists',
replacement: resolve('./config.local.js'),
async: true,
}
}]
}
}This rule replaces matching /\.config\.js$/ files with config.local.js, if replacement exists (condition if-replacement-exists).
After the build, the bundle will contain code from config.local.js, while original sources
won't be changed.
Multiple replace
To describe replace rules for two or more files you can use function as replacement value.
How does it work?
- Webpack runs file-replace-loader according to
testrule,includeandexcluderule options; - file-replace-loader checks the
replacementoption. If it is a string, the loader replaces the file. If it is a function, then file-replace-loader checks what it returns. If the function returns a file path, the loader replaces the file; if it returns nothing, the current match is skipped. - If the
replacementfunction returns a path, file-replace-loader checkscondition. If condition isalways, it replaces every match. Ifconditionisif-replacement-exists, the loader checks whether the file exists, etc;
For example:
const { resolve } = require('path');
module.exports = {
//...
module: {
rules: [{
test: /\.js$/,
loader: 'file-replace-loader',
options: {
condition: 'always', // <-- Note that the rule applies for all files!
replacement(resourcePath) {
if (resourcePath.endsWith('foo.js')) {
return resolve('./bar.js');
}
if (resourcePath.endsWith('foo-a.js')) {
return resolve('./bar-a.js');
}
},
async: true,
}
}]
}
}file-replace-loader passes resourcePath to the replacement function for every matched file.
file-replace-loader does not enforce how this path is processed, but if the replacement function returns a new path, file-replace-loader replaces the file.
If the replacement function returns nothing, file-replace-loader skips replacement for the current resourcePath.
Example with mapping:
const { resolve } = require('path');
module.exports = {
//...
module: {
rules: [{
test: /\.js$/,
loader: 'file-replace-loader',
options: {
condition: 'always', // <-- Note that the rule applies for all files! But you can use other conditions too
replacement(resourcePath) {
const mapping = {
[resolve('./src/foo-a.js')]: resolve('./src/bar-a.js'),
[resolve('./src/foo-b.js')]: resolve('./src/bar-b.js'),
[resolve('./src/foo-c.js')]: resolve('./src/bar-c.js'),
};
return mapping[resourcePath];
},
async: true,
}
}]
}
}NOTE: Make sure that all replacement files contain the necessary imports and exports that other files are expecting.
Using with binary files
file-replace-loader allows replacing binary files. For example:
//webpack.config.js
const { resolve } = require('path');
module.exports = {
//...
module: {
rules: [{
test: /\.png$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
}, {
loader: 'file-replace-loader',
options: {
condition: 'if-replacement-exists',
replacement: resolve('./src/replacement.png')
}
}]
}]
}
}Using with other loaders
file-replace-loader must execute before other loaders. This means that in a webpack config file the loader must be last in the list. For example:
//webpack.config.js
const { resolve } = require('path');
// Correct
module.exports = {
//...
module: {
rules: [{
test: /\.config\.js$/,
use: [{
loader: 'babel-loader',
}, {
loader: 'file-replace-loader',
options: {
condition: 'if-replacement-exists',
replacement: resolve('./config.local.js'),
async: true,
}
}]
}]
},
}The example above is correct. file-replace-loader will be executed before other loaders. Let's see incorrect usage:
//webpack.config.js
const { resolve } = require('path');
// Error, because file-replace-loader will be executed after other loaders
module.exports = {
//...
module: {
rules: [{
test: /\.config\.js$/,
use: [{
loader: 'file-replace-loader',
options: {
condition: 'if-replacement-exists',
replacement: resolve('./config.local.js'),
async: true,
}
}, {
loader: 'babel-loader',
}]
}]
},
}In the incorrect example above, file-replace-loader is first in the rule list. This case throws an error because file-replace-loader should be last in the list.
Loader options
| Option | Type | Required | Default | Possible values
| ------------ | ------------- | ------------- | ------------- | -------------
| conditionCondition to replace | string|boolean | no | 'if-replacement-exists' | true,false,'always','never','if-replacement-exists','if-source-is-empty'
| replacementReplacement file | string|function (resourcePath, options) | yes | — | Full path to file or function returning full path to file
| asyncAsynchronous file reading | boolean | no | true | true,false
| progressProgress output | boolean | no | IS_DEBUG_MODE == true or IS_PROGRESS_MODE == true | true,false
Contributing
See the contributing guideline.
