如何根据环境变量自定义 Service Worker?
How can I customize my Service Worker based on environment variables?
编辑:这看起来像是 Unresolved Question 的副本。
我是将其标记为已回答还是删除?
我在 Vue CLI 3 应用程序中使用来自 workbox-webpack-plugin 的 InjectManifest。我要注入的自定义服务工作者具有 Firebase 云消息传递 (FCM) 的处理能力。我需要根据我的环境(本地、暂存和生产)侦听来自不同发件人的消息。
理想情况下,service-worker.js 应该是这样的:
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js');
firebase.initializeApp({
'messagingSenderId': process.env.VUE_APP_FCM_SENDER_ID
});
然而,这段代码似乎没有被 webpack 触及,因为输出服务工作者仍然读取 process.env.VUE_APP_FCM_SENDER_ID
而不是硬编码密钥。
如何通过 webpack 运行 我的 service worker 来解析环境变量?
现在对你来说可能太晚了,但对其他人来说,这就是我继续解决这个问题的方法。
此过程仍将 .env
文件用于您的环境相关变量。
这个想法是创建一个新脚本来加载 .env
文件,该文件创建一个新文件,其中填充了 .env
文件中的变量。
在构建过程之后,我们只需将新生成的文件导入 sw.js
即可使用。
步骤如下。
首先创建一个名为 swEnvbuild.js
的文件,这将是您在 webpack
之后运行的脚本
//swEnvBuild.js - script that is separate from webpack
require('dotenv').config(); // make sure you have '.env' file in pwd
const fs = require('fs');
fs.writeFileSync('./dist/public/swenv.js',
`
const process = {
env: {
VUE_APP_FCM_SENDER_ID: conf.VUE_APP_FCM_SENDER_ID
}
}
`);
其次,我们将 swEnvBuild.js
生成的名为 swenv.js
的文件导入 sw.js
.
// sw.js
importScripts('swenv.js'); // this file should have all the vars declared
console.log(process.env.VUE_APP_FCM_SENDER_ID);
最后,要使其与一个命令一起使用,只需在您的 npm 脚本中添加以下内容(假设您是 运行 或者 Linux/Mac)。
scripts: {
"start": "webpack && node swEnvBuild.js"
}
希望这能解决问题。我希望有更简洁的方法来做到这一点,所以我很乐意知道其他人的解决方案。
我遇到了同样的问题,关键是让 webpack 构建过程输出它使用的环境变量,这样它们就可以导入到服务工作者中。这使您不必将 env var 定义复制到 pre-processes 您的 service worker 的其他内容中(无论如何这都很混乱,因为该文件在源代码管理中)。
创建一个新的 Webpack 插件
// <project-root>/vue-config/DumpVueEnvVarsWebpackPlugin.js
const path = require('path')
const fs = require('fs')
const pluginName = 'DumpVueEnvVarsWebpackPlugin'
/**
* We to configure the service-worker to cache calls to both the API and the
* static content server but these are configurable URLs. We already use the env var
* system that vue-cli offers so implementing something outside the build
* process that parses the service-worker file would be messy. This lets us
* dump the env vars as configured for the rest of the app and import them into
* the service-worker script to use them.
*
* We need to do this as the service-worker script is NOT processed by webpack
* so we can't put any placeholders in it directly.
*/
module.exports = class DumpVueEnvVarsWebpackPlugin {
constructor(opts) {
this.filename = opts.filename || 'env-vars-dump.js'
}
apply(compiler) {
const fileContent = Object.keys(process.env)
.filter(k => k.startsWith('VUE_APP_'))
.reduce((accum, currKey) => {
const val = process.env[currKey]
accum += `const ${currKey} = '${val}'\n`
return accum
}, '')
const outputDir = compiler.options.output.path
if (!fs.existsSync(outputDir)) {
// TODO ideally we'd let Webpack create it for us, but not sure how to
// make this run later in the lifecycle
fs.mkdirSync(outputDir)
}
const fullOutputPath = path.join(outputDir, this.filename)
console.debug(
`[DumpVueEnvVarsWebpackPlugin] dumping env vars to file=${fullOutputPath}`,
)
fs.writeFileSync(fullOutputPath, fileContent)
}
}
在您的 vue-cli 配置中使用该插件(vue.config.js
或 vue-config/config.default.js
如果您的配置分为几个文件)
// import our plugin (change the path to where you saved the plugin script)
const DumpVueEnvVarsWebpackPlugin = require('./DumpVueEnvVarsWebpackPlugin.js')
module.exports = {
// other stuff...
configureWebpack: {
plugins: [
// We add our plugin here
new DumpVueEnvVarsWebpackPlugin({ filename: 'my-env-vars.js' })
],
},
}
在我们的 service worker 脚本中,我们现在可以导入我们用 Webpack 插件编写的文件(它会在构建发生后存在,而 service workers 不会 运行 在开发模式下,所以我们应该是安全的)
importScripts('./my-env-vars.js') // written by DumpVueEnvVarsWebpackPlugin
const fcmSenderId = VUE_APP_FCM_SENDER_ID // comes from script imported above
console.debug(`Using sender ID = ${fcmSenderId}`)
// use the variable
firebase.initializeApp({
'messagingSenderId': fcmSenderId
})
它并不完美,但确实可以完成工作。它是 D-R-Y,因为您只需在一个位置定义所有环境变量,并且整个应用程序使用相同的值。另外,它不处理源代码管理中的任何文件。我不喜欢插件 运行 在 Webpack 生命周期中太早,所以我们必须创建 dist
目录,但希望比我聪明的人能解决这个问题。
编辑:这看起来像是 Unresolved Question 的副本。 我是将其标记为已回答还是删除?
我在 Vue CLI 3 应用程序中使用来自 workbox-webpack-plugin 的 InjectManifest。我要注入的自定义服务工作者具有 Firebase 云消息传递 (FCM) 的处理能力。我需要根据我的环境(本地、暂存和生产)侦听来自不同发件人的消息。
理想情况下,service-worker.js 应该是这样的:
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js');
firebase.initializeApp({
'messagingSenderId': process.env.VUE_APP_FCM_SENDER_ID
});
然而,这段代码似乎没有被 webpack 触及,因为输出服务工作者仍然读取 process.env.VUE_APP_FCM_SENDER_ID
而不是硬编码密钥。
如何通过 webpack 运行 我的 service worker 来解析环境变量?
现在对你来说可能太晚了,但对其他人来说,这就是我继续解决这个问题的方法。
此过程仍将 .env
文件用于您的环境相关变量。
这个想法是创建一个新脚本来加载 .env
文件,该文件创建一个新文件,其中填充了 .env
文件中的变量。
在构建过程之后,我们只需将新生成的文件导入 sw.js
即可使用。
步骤如下。
首先创建一个名为 swEnvbuild.js
的文件,这将是您在 webpack
//swEnvBuild.js - script that is separate from webpack
require('dotenv').config(); // make sure you have '.env' file in pwd
const fs = require('fs');
fs.writeFileSync('./dist/public/swenv.js',
`
const process = {
env: {
VUE_APP_FCM_SENDER_ID: conf.VUE_APP_FCM_SENDER_ID
}
}
`);
其次,我们将 swEnvBuild.js
生成的名为 swenv.js
的文件导入 sw.js
.
// sw.js
importScripts('swenv.js'); // this file should have all the vars declared
console.log(process.env.VUE_APP_FCM_SENDER_ID);
最后,要使其与一个命令一起使用,只需在您的 npm 脚本中添加以下内容(假设您是 运行 或者 Linux/Mac)。
scripts: {
"start": "webpack && node swEnvBuild.js"
}
希望这能解决问题。我希望有更简洁的方法来做到这一点,所以我很乐意知道其他人的解决方案。
我遇到了同样的问题,关键是让 webpack 构建过程输出它使用的环境变量,这样它们就可以导入到服务工作者中。这使您不必将 env var 定义复制到 pre-processes 您的 service worker 的其他内容中(无论如何这都很混乱,因为该文件在源代码管理中)。
创建一个新的 Webpack 插件
// <project-root>/vue-config/DumpVueEnvVarsWebpackPlugin.js const path = require('path') const fs = require('fs') const pluginName = 'DumpVueEnvVarsWebpackPlugin' /** * We to configure the service-worker to cache calls to both the API and the * static content server but these are configurable URLs. We already use the env var * system that vue-cli offers so implementing something outside the build * process that parses the service-worker file would be messy. This lets us * dump the env vars as configured for the rest of the app and import them into * the service-worker script to use them. * * We need to do this as the service-worker script is NOT processed by webpack * so we can't put any placeholders in it directly. */ module.exports = class DumpVueEnvVarsWebpackPlugin { constructor(opts) { this.filename = opts.filename || 'env-vars-dump.js' } apply(compiler) { const fileContent = Object.keys(process.env) .filter(k => k.startsWith('VUE_APP_')) .reduce((accum, currKey) => { const val = process.env[currKey] accum += `const ${currKey} = '${val}'\n` return accum }, '') const outputDir = compiler.options.output.path if (!fs.existsSync(outputDir)) { // TODO ideally we'd let Webpack create it for us, but not sure how to // make this run later in the lifecycle fs.mkdirSync(outputDir) } const fullOutputPath = path.join(outputDir, this.filename) console.debug( `[DumpVueEnvVarsWebpackPlugin] dumping env vars to file=${fullOutputPath}`, ) fs.writeFileSync(fullOutputPath, fileContent) } }
在您的 vue-cli 配置中使用该插件(
vue.config.js
或vue-config/config.default.js
如果您的配置分为几个文件)// import our plugin (change the path to where you saved the plugin script) const DumpVueEnvVarsWebpackPlugin = require('./DumpVueEnvVarsWebpackPlugin.js') module.exports = { // other stuff... configureWebpack: { plugins: [ // We add our plugin here new DumpVueEnvVarsWebpackPlugin({ filename: 'my-env-vars.js' }) ], }, }
在我们的 service worker 脚本中,我们现在可以导入我们用 Webpack 插件编写的文件(它会在构建发生后存在,而 service workers 不会 运行 在开发模式下,所以我们应该是安全的)
importScripts('./my-env-vars.js') // written by DumpVueEnvVarsWebpackPlugin const fcmSenderId = VUE_APP_FCM_SENDER_ID // comes from script imported above console.debug(`Using sender ID = ${fcmSenderId}`) // use the variable firebase.initializeApp({ 'messagingSenderId': fcmSenderId })
它并不完美,但确实可以完成工作。它是 D-R-Y,因为您只需在一个位置定义所有环境变量,并且整个应用程序使用相同的值。另外,它不处理源代码管理中的任何文件。我不喜欢插件 运行 在 Webpack 生命周期中太早,所以我们必须创建 dist
目录,但希望比我聪明的人能解决这个问题。