Как я могу настроить мой Service Worker на основе переменных среды?
Изменить: это выглядит как дубликат этого нерешенного вопроса. Могу ли я отметить это как ответ или удалить?
Я использую InjectManifest из workbox-webpack-plugin внутри приложения Vue CLI 3. У работника таможенной службы, в который я вливаю, есть обработка для Firebase Cloud Messaging (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
});
Однако этот код, похоже, не затрагивается веб-пакетом, поскольку работник службы вывода все еще читает process.env.VUE_APP_FCM_SENDER_ID
вместо жестко закодированного ключа.
Как я могу запустить моего сервисного работника через веб-пакет для разрешения переменных среды?
3 ответа
Вероятно, сейчас слишком поздно для вас, но для других я продолжал обходить это. Этот процесс все еще использует .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 vars, которые он использует, чтобы их можно было импортировать в сервис-воркер. Это избавляет вас от необходимости дублировать определения env var во что-то еще, что предварительно обрабатывает вашего сервис-воркера (что в любом случае просто беспорядочно, потому что этот файл находится в системе управления версиями).
создать новый плагин 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' }) ], }, }
в нашем сценарии сервисного воркера мы теперь можем импортировать файл, который мы написали с помощью нашего плагина Webpack (он будет там после завершения сборки, а сервисные воркеры не будут работать в режиме разработки, поэтому мы должны быть в безопасности)
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 })
Это не идеально, но, безусловно, выполняет свою работу. Это СУХОЙ, так как вам нужно только определить все ваши env vars в одном месте, и все приложение использует одни и те же значения. Кроме того, он не обрабатывает файлы, находящиеся в системе контроля версий. Мне не нравится, что плагин запускается слишком рано в жизненном цикле Webpack, поэтому мы должны создатьdist
dir, но, надеюсь, кто-то еще умнее меня найдет решение для этого.
Я пытался сделать это в Nuxt для обмена облачными сообщениями Firebase, и я адаптировал ответ @shreek выше, чтобы делать то, что мне нужно.
Сначала создайте файл с именем swEnvbuild.js в корневом каталоге, как показано ниже:
require('dotenv').config(); // make sure you have '.env' file in pwd
const fs = require('fs');
fs.writeFileSync('./public/swenv.js',
`
const process = {
env: {
FB_API_KEY: '${process.env.FIREBASE_API_KEY}',
FB_AUTHDOMAIN: '${process.env.FIREBASE_AUTHDOMAIN}',
FB_PROJECTID: '${process.env.FIREBASE_PROJECTID}',
FB_STORAGEBUCKET: '${process.env.FIREBASE_STORAGEBUCKET}',
FB_MESSAGINGSENDERID: '${process.env.FIREBASE_MESSAGINGSENDERID}',
FB_APPID: '${process.env.FIREBASE_APPID}',
FB_MEASUREMENTID: '${process.env.FIREBASE_MEASUREMENTID}',
FB_PUSHNOTETOKEN: '${process.env.FIREBASE_PUSHNOTETOKEN}'
}
}
`);
Затем обновите файл сервисного работника с помощью:
importScripts('https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/9.0.0/firebase-messaging-compat.js');
importScripts('swenv.js'); // this file should have all the vars declared, allowing you to use process.env.ANY_KEY_YOU_DEFINED
firebase.initializeApp({
apiKey: process.env.FB_API_KEY,
authDomain: process.env.FB_AUTHDOMAIN,
projectId: process.env.FB_PROJECTID,
storageBucket: process.env.FB_STORAGEBUCKET,
messagingSenderId: process.env.FB_MESSAGINGSENDERID,
appId: process.env.FB_APPID,
measurementId: process.env.FB_MEASUREMENTID
});
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../firebase-messaging-sw.js', { type: 'module', scope: '__' })
.then(function(registration) {
console.log('Registration successful, scope is:', registration.scope);
}).catch(function(err) {
console.log('Service worker registration failed, error:', err);
});
}
const isSupported = firebase.messaging.isSupported();
if (isSupported) {
const messaging = firebase.messaging();
messaging.onBackgroundMessage(({ notification: { title, body, image } }) => {
self.registration.showNotification(title, { body, icon: image || '/assets/icons/icon-72x72.png' });
});
}
Наконец, обновите ваш package.json, чтобы создать необходимый файл.
// add 'node swEnvBuild.js' to build and start script
"scripts": {
"build": "nuxt build && node swEnvBuild.js",
"dev": "node swEnvBuild.js && nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"start": "node .output/server/index.
}
Это сделало это для меня