如何在编译时使用 webpack 替换文件?
Posted
技术标签:
【中文标题】如何在编译时使用 webpack 替换文件?【英文标题】:How can I replace files at compile time using webpack? 【发布时间】:2018-12-22 15:05:35 【问题描述】:我有一个具有多种配置的项目。第一个配置是config.dev.js
文件,其中包含一些开发配置。我在开发模式下使用它。第二个配置是config.js
文件。我在生产模式下使用它。
在我使用导入的代码中:
import * as config from './config.js';
我想在开发中使用第一个配置文件,在生产中使用第二个配置文件而不重写所有导入。如何根据构建模式替换此配置?
【问题讨论】:
【参考方案1】:另一种方法是使用 Webpack.DefinePlugin。如果您想要有条件地包含一个很小的代码块,则特别有用。
示例如下:
// webpack.conf.js
// Code block that should be inserted or left blank
const ServiceWorkerReg = `window.addEventListener('load', () =>
navigator.serviceWorker.register('service-worker.js').then(registration =>
console.log('SW registered: ', registration);
).catch(registrationError =>
console.log('SW registration failed: ', registrationError);
);
);`
appConfig =
plugins: [
new webpack.DefinePlugin(
__SERVICE_WORKER_REG: isDev ? '' : ServiceWorkerReg,
),
]
...
// Some module index.js
__SERVICE_WORKER_REG
... // other non conditional code
【讨论】:
【参考方案2】:这是一个老问题,但我最近偶然发现了同样的问题,webpack.NormalModuleReplacementPlugin
似乎不再起作用(或者至少在我使用 JSON 文件作为配置的情况下不起作用)。相反,我找到了另一个使用别名的解决方案:
const path = require("path");
modules.export =
...
resolve:
...
alias:
[path.resolve(__dirname, "src/conf/config.json")]:
path.resolve(__dirname, "src/conf/config.prod.json")
...
【讨论】:
NormalModuleReplacementPlugin
在我的使用过程中也不起作用,同时它错误“NormalModuleFactory.beforeResolve 不再是瀑布挂钩,而是一个吊钩。”似乎与 webpack 版本变化有关:github.com/webpack/webpack/issues/11647【参考方案3】:
我想模仿 Angular 的 fileReplacements 语法,所以我使用了类似 Angular 的 config.json,如果配置键与我传递给 webpack 的 env 匹配,则循环替换并创建几个 Webpack 模块规则。
这不是有史以来最优雅的东西,但这是我最终得到的:
// config.json
"title": "Some Title",
"configurations":
"production":
"fileReplacements": [
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
]
,
"lan":
"fileReplacements": [
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.lan.ts"
]
// webpack.config.js
const appConfig = require('./config.json');
module.exports = (env, argv) =>
// env.build is like `ng build --prod` as `webpack --env.build=production`
const configuration = appConfig.configurations[env.build];
const fileReplacements = [];
// Safety Check
if(configuration && configuration.fileReplacements)
// Iterate through replacements
for(const replacement of configuration.fileReplacements)
// create Webpack module rule
const replace =
test: path.resolve(replacement.replace),
loader: 'file-replace-loader',
options:
replacement: path.resolve(replacement.with),
async: true
fileReplacements.push(replace);
return
mode: //...
entry: //...
module:
rules: [
//...
,
// Unpack anywhere here
...fileReplacements
]
这样你就不必一直搞乱 webpack 和 regex 测试,只需添加到 config.json 中的数组中
【讨论】:
这基本上也是我想做的。喜欢你的解决方案。不敢相信每个框架都不包含这样的东西。如果没有它,你会想要构建一个应用程序——或者在本地调试一个生产错误吗?【参考方案4】:你也可以像这样使用babel-loader:
//webpack.config.js
const resolve = require('path').resolve;
module.exports =
//...
module:
strictExportPresence: true,
rules: [
test: /\.config\.js$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options:
plugins: [
[
"module-resolver",
resolvePath(sourcePath, currentFile, opts)
if(process.env.NODE_ENV === 'development')
return sourcePath.substr(0, sourcePath.lastIndexOf('/')) + '/config.dev.js';
else
return sourcePath;
]
]
]
这样您甚至可以定义复杂的算法来确定您要使用的文件。
【讨论】:
【参考方案5】:我知道这是一篇旧帖子,但这是 Google 上的首批结果之一,所以我认为更好的答案会更好。
Webpack 有一个内置的“Normal Module Replacement Plugin”。
plugins: [
new webpack.NormalModuleReplacementPlugin(
/some\/path\/config\.development\.js/,
'./config.production.js'
)
]
为了我的使用,我把 env 文件放在了一个变量下面是一个例子:
let envFilePath = './environment.dev.js';
if (env === 'production')
envFilePath = './environment.prod.js';
else if (env === 'staging')
envFilePath = './environment.stg.js';
module.exports =
// other webpack stuff
....
plugins:[
new webpack.NormalModuleReplacementPlugin(
/src\/environment\/environment\.js/,
envFilePath
),
...
]
【讨论】:
也许值得一提的是,第二条路径是相对于第一条的,意思是:如果我的旧路径在./src/config/dev.js
中,那么./prod.js
将引用./src/config/prod.js
,而不是root/prod.js
【参考方案6】:
你可以使用 webpack 文件替换加载器
https://www.npmjs.com/package/file-replace-loader
例子:
//webpack.config.js
const resolve = require('path').resolve;
module.exports =
//...
module:
rules: [
test: /\.config\.js$/,
loader: 'file-replace-loader',
options:
condition: process.env.NODE_ENV === 'development',
replacement: resolve('./config.dev.js'),
async: true,
]
【讨论】:
以上是关于如何在编译时使用 webpack 替换文件?的主要内容,如果未能解决你的问题,请参考以下文章
Vue.js / webpack:当热重载编译它们时,如何清除旧的包 main-*.js 文件?
如何在为服务器开发但不重新编译 webpack 客户端配置时使用 nodemon?