См. Https://github.com/firebase/firebase-functions/issues/172
3.17.3
Кажется, это работает в моей настройке, т.е. deploy
забирает пакеты из корня node_modules
, даже если package.json
для этого находится в рабочем пространстве api/
( Я использовал другое имя папки вместо functions/
). Здесь есть что-нибудь еще, что нужно исправить?
РЕДАКТИРОВАТЬ: Кроме того, я копирую package.json
в api/dist
для использования deploy
.
// firebase.json
...
"functions": {
"source": "api/dist"
},
...
Итак, 2 уровня вложенности по-прежнему успешно разрешают корень node_modules
.
@dinvlad не могли бы вы поделиться репо?
@orouz, к сожалению, еще нет, пока это закрытый код.
Кому-нибудь удалось решить эту проблему? Было бы очень полезно поделиться простым примером проекта.
@audkar В настоящее время я просто использую lerna.js.org и run
для выполнения сценария npm в каждой подпапке с такой структурой папок:
- service1/
| - .firebaserc
| - firebase.json
- service2/
| - .firebaserc
| - firebase.json
- app1/
| - .firebaserc
| - firebase.json
- app2/
| - .firebaserc
| - firebase.json
- firestore/
| - firestore.rules
| - firestore.indexes.json
- etc...
Обеспечение того, чтобы файлы firebase.json
для каждой службы не перекрывали друг друга, оставлено на усмотрение пользователя. Простые соглашения об использовании функциональных групп и таргетинга на несколько сайтов означают, что это решено для облачных функций и хостинга. До сих пор нет решения для правил Firestore / GCS, хотя их разделение может быть не идеальным ...
обсуждалось здесь ранее - https://github.com/firebase/firebase-tools/issues/1116
@jthegedus благодарим за ответ. Но я думаю, что у этого билета другой выпуск. Я пытаюсь использовать рабочие пространства пряжи. И кажется, что инструменты firebase не выбирают зависимости символических ссылок при загрузке функций.
Ах, честно, я сам избежал этой кроличьей норы
Не могли бы вы пояснить, в чем проблема? Как упоминалось выше, я просто использую чистый Yarn с рабочими пространствами api
и app
в нем, и я создаю их, используя yarn workspace api build && yarn workspace app build
(со сценарием build
специфичным для каждого рабочая среда). Скрипты сборки
1) скомпилируйте код TS с outDir
в api/dist
и app/dist
соответственно
2) скопировать соответствующий package.json
файлов в dist
каталогов
3) скопируйте yarn.lock
из папки _root_ в каталоги dist
Затем я просто запускаю yarn firebase deploy
из папки _root_, и он без сбоев обнаруживает и api/dist
и app/dist
. Мой firebase.json
выглядит как
"functions": {
"source": "api/dist"
},
"hosting": {
"public": "app/dist",
К сожалению, я до сих пор не могу поделиться полным кодом, но важна только эта настройка, черт возьми.
Кроме того, я могу ошибаться, но я думаю, что сценарий firebase deploy
самом деле не использует ваш каталог node_modules
. Я думаю, он просто берет код, package.json
и yarn.lock
из каталогов dist
и делает все остальное.
Это правда. Значение по умолчанию для functions.ignore в firebase.json -
["node_modules"], поэтому он не загружен. Я верю, что ты можешь это преодолеть
хотя, если вы хотите отправить некоторые локальные модули.
В пн, 17.06.2019, 18:58 Денис Логинов [email protected]
написал:
Кроме того, я могу ошибаться, но я думаю, что сценарий развертывания firebase не
на самом деле используйте ваш каталог node_modules. Я думаю, он просто забирает
cod, package.json и yarn.lock из каталогов dist и выполняет
отдыхать.-
Вы получаете это, потому что подписаны на эту ветку.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/firebase/firebase-tools/issues/653?email_source=notifications&email_token=ACATB2U73VS2KIILUVRFFB3P3P3A6NPA5CNFSM4EOR24GKYY3PNVWWK3TREBORM4EOR24GKYY3PNVWWK3TREFWXG4DVMWWWK3TREXW2X4DFVMXWWMXWWMXX4DFVMXWWMXX4DFWMXWWM6
или отключить поток
https://github.com/notifications/unsubscribe-auth/ACATB2U3Q2TLVBICRJ3B5OLP3A6NPANCNFSM4EOR24GA
.
@dinvlad Да, для этого требуется package.json
и любой файл блокировки, который вы используете при установке deps в развертывании облачной почты.
Я считаю, что сценарий, изначально описанный в другом выпуске, заключался в использовании общего пакета в рабочей области и некоторых проблемах с поднятием области видимости. Поскольку я не использовал пряжу таким образом, я могу только предполагать, исходя из того, что я там прочитал.
@samtstern @jthegedus спасибо, приятно знать!
Кажется, мы все говорим о разных проблемах. Постараюсь описать yarn workspaces
проблему.
макет проекта
- utilities/
| - package.json
- functions/
| - package.json
- package.json
_./package.json_
{
"private": true,
"workspaces": ["functions", "utilities"]
}
_functions / package.json_
{
<...>
"dependencies": {
"utilities": "1.0.0",
<...>
}
}
Ошибка при развертывании функции:
Deployment error.
Build failed: {"error": {"canonicalCode": "INVALID_ARGUMENT", "errorMessage": "`gen_package_lock` had stderr output:\nnpm WARN deprecated [email protected]: use String.prototype.padStart()\nnpm ERR! code E404\nnpm ERR! 404 Not Found: [email protected]\n\nnpm ERR! A complete log of this run can be found in:\nnpm ERR! /builder/home/.npm/_logs/2019-06-18T07_10_42_472Z-debug.log\n\nerror: `gen_package_lock` returned code: 1", "errorType": "InternalError", "errorId": "1971BEF9"}}
Функции отлично работают локально на эмуляторе.
Загрузка node_modules
(с использованием functions.ignore
в _firebase.json_). Результат такой же.
Я предполагаю, что это потому, что utilities
создается как syslink в _node-modules_ node_modules/utilities -> ../../utilities
Может быть, firebase-tools не включает содержимое модулей с символическими ссылками при загрузке (без разыменования)?
Извините, не могли бы вы уточнить, в какой папке находится ваш firebase.json
(и показать его раздел конфигурации для functions
)?
_firebase.json_ находился в корневой папке. Комплектация была стандартной. Что-то вроде этого:
"functions": {
"predeploy": [
"yarn --cwd \"$RESOURCE_DIR\" run lint",
"yarn --cwd \"$RESOURCE_DIR\" run build"
],
"source": "functions",
"ignore": []
},
<...>
все было развернуто, как ожидалось (включая _node_modules_), за исключением node_modules/utilities
который является символической ссылкой.
Мне удалось обойти эту проблему, написав несколько скриптов, которые:
yarn pack
). например, это создает _utilities.tgz_.dependencies { "utilities": "1.0.0"
-> dependencies { "utilities": "file:./utilities.tgz"
вывести содержимое каталога перед загрузкой:
- dist
| - lib
| | -index.js
| - utilities.tgz
| - package.json <---------- This is modified to use *.tgz for workspaces
@audkar Сегодня я столкнулся с той же проблемой, что и вы.
Я новичок в рабочих пространствах Lerna и Yarn. Насколько я понимаю, можно просто использовать Лерну. Это хоть как-то поможет?
Ваш обходной путь кажется мне немного сложным 🤔
Также интересно, для чего нужен `--cwd" $ RESOURCE_DIR "?
--cwd
означает «текущий рабочий каталог», а $RESOURCE_DIR
содержит значение для исходного каталога (в данном случае functions
). Добавление этого флага заставит yarn
выполняться в functions
dir вместо root
@audkar А, понятно. Таким образом, вы можете сделать то же самое с yarn workspace functions lint
и yarn workspace functions build
@dinvlad Мне непонятно, почему вы нацеливаетесь на папку dist и копируете туда вещи. Если вы выполните сборку на dist, но оставите package.json там, где он есть, и укажете main на dist/index.js
тогда все должно работать так же, нет? Затем вы должны установить для источника api вместо api / dist.
@dinvlad Я узнал команду yarn workspace
из ваших комментариев, но по какой-то причине не могу заставить ее работать. Смотрите здесь . Любая идея?
Извините за то, что здесь немного не по теме. Возможно, прокомментируйте в SO, чтобы минимизировать шум.
@ 0x80 Я package.json
в api/dist
и указываю firebase.json
на api/dist
поэтому внутри облачной функции упаковываются только «встроенные» файлы. Я не уверен, что произойдет, если я укажу firebase.json
на api
- возможно, он будет достаточно умен, чтобы упаковать только то, что находится внутри api/dist
(на основе main
атрибут package.json
). Но я подумал, что будет проще просто указать на api/dist
.
Re yarn workspace
, я ответил на SO ;)
@dinvlad он
Теперь я использовал аналогичный обходной путь для @audkar.
{
"functions": {
"source": "packages/cloud-functions",
"predeploy": ["./scripts/pre-deploy-cloud-functions"],
"ignore": [
"src",
"node_modules"
]
}
}
Тогда сценарий pre-deploy-cloud-functions следующий:
#!/usr/bin/env bash
set -e
yarn workspace @gemini/common lint
yarn workspace @gemini/common build
cd packages/common
yarn pack --filename gemini-common.tgz
mv gemini-common.tgz ../cloud-functions/
cd -
cp yarn.lock packages/cloud-functions/
yarn workspace @gemini/cloud-functions lint
yarn workspace @gemini/cloud-functions build
А у пакетов / облачных функций есть дополнительный файл gitignore:
yarn.lock
*.tgz
вот что сработало для меня
- root/
| - .firebaserc
| - firebase.json
- packages/
| - package1/
| - functions/
| - dist/
| - src/
| packages.json
и в root/firebase.json
:
`` ''
{
"functions": {
"predploy": "npm --prefix" $ RESOURCE_DIR "run build",
"источник": "пакеты / функции"
}
}
`` ''
@kaminskypavel - это ваши пакеты / функции в зависимости от пакетов / package1 (или какого-либо другого родственного пакета)?
@ 0x80 положительный.
Я думаю, что было что-то фундаментальное, что я неправильно понял в монорепозитории. Я предполагал, что вы можете поделиться пакетом и развернуть приложение, используя этот пакет, без фактической публикации общего пакета в NPM.
Кажется, что это невозможно, потому что развертывания, такие как Firebase или Now.sh, обычно загружают код, а затем в облаке выполняют установку и сборку. Я прав?
@kaminskypavel Я попробовал ваш подход, и он работает, но только после публикации моего пакета в NPM. Поскольку в моем случае пакет является частным, я изначально получил ошибку «не найден», поэтому мне также пришлось добавить свой файл .npmrc в корень пакета облачных функций, как описано здесь.
@audkar Вы публикуете свой общий пакет в NPM, или вы, как и я, пытаетесь развернуть с общим кодом, который не опубликован?
@ 0x80 Я
Поскольку настройки рабочего пространства yarn становятся все более популярными, я полагаю, что все больше людей будут удивлены тем, что они не могут использовать пакеты с символическими ссылками в функциях Firebase - тем более, что они отлично работают до тех пор, пока вы не развернете.
Благодаря добавлению поддержки рабочих областей в npm у нас появился стандарт экосистемы, определяющий, как должны работать локальные пакеты.
Поскольку этой проблеме больше года, есть ли здесь какие-либо обновления со стороны Firebase о планах (или отсутствии планов)?
Я думаю, что это довольно крутая возможность - множество сервисов Firebase требует хорошей настройки монорепозитория.
+1 к этому, облачные функции обычно должны будут совместно использовать некоторый общий код (например, интерфейсы) с другими приложениями, и хороший способ справиться с этим - монорепорация (например, lerna) или прямое использование символических ссылок. Я взял последнее и решил, создав несколько скриптов. Идея довольно проста: я копирую то, что нужно, в каталог функций, и удаляю его после
Вот как я сделал это с этой структурой каталогов:
`` ''
content of `pre-deploy.js`
const fs = require ("fs-extra");
const packageJsonPath = "./package.json";
const packageJson = требуется (packageJsonPath);
(async () => {
ждать fs.remove ( ./shared
);
await fs.copy ( ../shared
, ./shared
);
packageJson.dependencies["@project/shared"] = "file:./shared";
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
}) ();
content of `post-deploy.js`
const packageJsonPath = "./package.json";
const packageJson = требуется (packageJsonPath);
const fs = require ("fs-extra");
(async () => {
ждать fs.remove ( ./shared
);
packageJson.dependencies["@project/shared"] = "file:../shared";
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
}) ();
Then update `firebase.json` like this (add the build script if you need, I build before in my pipeline)
"functions": {
"источник": "функции",
"Preploy": [
"npm --prefix" $ RESOURCE_DIR "выполнить предварительное развертывание"
],
"postdeploy": [
"npm --prefix" $ RESOURCE_DIR "запустить после развертывания"
]
},
`` ''
Если вы выполняете сборку, то внутри каталога dist
или lib
вас должно быть два брата и сестры: функции и общий доступ (это произошло из-за общей зависимости). Обязательно обновите функции package.json
main
чтобы они указывали на lib/functions/src/index.js
чтобы развертывание работало.
На данный момент это решено, но это обходной путь, а не решение. Я думаю, что инструменты firebase действительно должны поддерживать символические ссылки
@michelepatrassi, вдохновленный тем, что вы мне напомнили, я создал библиотеку firelink
для управления этим делом. Он использует внутренне rsync
для копирования рекурсивных файлов.
https://github.com/rxdi/firelink
npm i -g @rxdi/firelink
Основное использование
Предполагая, что у вас есть подход monorepo, и ваши пакеты расположены на 2 уровня ниже текущего каталога, в котором находится package.json
.
package.json
"fireDependencies": {
"@graphql/database": "../../packages/database",
"@graphql/shared": "../../packages/shared",
"@graphql/introspection": "../../packages/introspection"
},
При выполнении firelink
он скопирует пакеты, связанные с папками, затем сопоставит существующие пакеты с локальным модулем install "@graphql/database": "file:./.packages/database",
затем выполнит команду firebase
и передаст остальные аргументы из firelink
команда.
По сути, firelink
- это замена firebase
CLI, поскольку он порождает firebase
в конце, когда завершает свою работу, копируя packages
и изменяя package.json
!
С Уважением!
Нас это только что укусило, я думаю, что монорепозитории станут стандартом, и это должно поддерживаться по умолчанию.
Ребята, простое решение этой проблемы - использовать webpack для объединения ваших облачных функций и развертывания из связанного каталога. К этому приложению прилагается базовый файл веб-пакета, который я использую. Во время сборки он упакует весь код функций, включая зависимости, разрешенные в монорепозитории, в папку верхнего уровня (в данном случае это webpack/cloud-functions
, это может быть все, что вы настроите)
const path = require('path');
module.exports = {
target: 'node',
mode: 'production',
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json']
},
output: {
filename: 'index.js',
path: path.resolve(__dirname, '../../webpack/cloud-functions/dist'),
libraryTarget: 'commonjs'
},
externals: {
'firebase-admin': 'firebase-admin',
'firebase-functions': 'firebase-functions'
}
};
И, наконец, в вашем файле firebase.json
обратитесь к этой папке для развертывания.
{
"functions": {
"source": "webpack/cloud-functions"
}
}
Не забудьте также иметь файл package.json
папке webpack/cloud-functions
.
{
"name": "cloud-functions",
"version": "1.0.0",
"scripts": {
"deploy": "firebase deploy --only functions"
},
"engines": {
"node": "10"
},
"main": "dist/index.js",
"dependencies": {
"firebase-admin": "8.9.1",
"firebase-functions": "3.3.0"
},
"devDependencies": {},
"private": true
}
Это проверено и работает. Я использую сборку Google Cloud. При необходимости запросите дополнительную информацию.
Спасибо,
@sowdri Спасибо, что поделились! Запускаете ли вы сборку веб-пакета из шага firebase.json functions.predeploy
или запускаете его из сценария сборки облака перед вызовом развертывания firebase?
@ 0x80 Я создаю его на шаге cloud build
. Итак, согласно firebase cli
это просто набор функций, созданных с помощью JS.
@sowdri Спасибо за пример. Мы закончили тем, что использовали тот же подход в прошлом проекте для AWS Lambdas / Serverless: было проще загрузить пакет (Webpack), чем заставить инструменты работать с yarn monorepo.
Я тоже застрял в этом .... все работало нормально (даже эмулятор firebase), пока я не попытался развернуть функции (сборка веб-приложения в реакции развертывается нормально). :( Надеюсь, команда firebase скоро добавит поддержку монорепозиториев.
Я использую babel для других пакетов в моем монорепозитории, поэтому я бы предпочел остаться с ним. Если ничего другого, я могу попробовать веб-пакет ... который, похоже, для некоторых работает.
РЕДАКТИРОВАТЬ: Я решил это с помощью реестра пакетов GitHub. Поэтому я публикую все свои пакеты здесь, а затем для сервера travis
и functions
Мне нужно настроить реестр и предоставить токен для аутентификации (выполняется через .npmrc
). ... кажется элегантным решением. Идея этого подхода у меня появилась здесь: https://medium.com/gdgeurope/how-to-use-firebase-cloud-functions-and-yarn-workspaces-24ca35e941eb
Да, это тоже укусило. Все работало отлично в firebase serve --only functions
но при развертывании не смог найти модуль.
В итоге я написал небольшой скрипт для сборки пакетов для меня. Хотя это отражает особенности моей среды, такие как использование модулей и имен моих пакетов, совпадающих с именами моих каталогов, я надеюсь, что это будет полезно для других.
`` импортировать фс из фс;
импортировать child_process из "child_process";
const internalPackagesFull = новая карта ();
// Находим все значения для пакета
const getDepsForPackage = (packageName) => {
const packageDir = packageName.split ("/") [1]; // МОЖЕТ НЕОБХОДИМО ИЗМЕНИТЬ ДЛЯ ВАС
const packageSpecFileName = ../${packageDir}/package.json
;
const packageSpecFile = fs.readFileSync (packageSpecFileName);
const packageSpec = JSON.parse (packageSpecFile);
const packageInternalDeps = Object.keys (
packageSpec.dependencies
) .filter ((ключ) => key.includes ("тьюринг")); // ЭТО НЕОБХОДИМО ИЗМЕНИТЬ ДЛЯ ВАС
const packageTgzName = ${packageName.replace("@", "").replace("/", "-")}-v${
packageSpec.version
}.tgz
;
internalPackagesFull.set (имя_пакета, {
packageSpecFileName,
packageSpec,
packageDir,
packageInternalDeps,
packageTgzName,
});
const packagesToProcess = packageInternalDeps.filter (
(internalDepName) =>! internalPackagesFull.has (internalDepName)
);
packagesToProcess.forEach ((internalPackageName) =>
getDepsForPackage (internalPackageName)
);
};
const packageName = JSON.parse (fs.readFileSync ("./ package.json")). name;
child_process.execSync ( cp ./package.json ./package.json.org
);
getDepsForPackage (имя_пакета);
// пишем обновленные пакеты - используйте обычные js, а ссылки - это локальные файлы tgz
[... internalPackagesFull.values ()]. forEach ((internalDep) => {
const {packageSpec, packageSpecFileName, packageInternalDeps} = internalDep;
// меняем тип пакета
packageSpec.type = "commonjs"; // МОЖЕТ НЕОБХОДИМО ИЗМЕНИТЬ ДЛЯ ВАС
// указываем расположение депа, который будет упакованным zip-файлом
packageInternalDeps.forEach ((internalDepOfPackage) => {
const {packageTgzName} = internalPackagesFull.get (internalDepOfPackage);
packageSpec.dependencies [internalDepOfPackage] = ./${packageTgzName}
;
});
fs.writeFileSync (
packageSpecFileName,
JSON.stringify (packageSpec, null, "")
);
});
// запускаем сборку и упаковку пряжи
[... internalPackagesFull.values ()]. forEach ((internalDep) => {
пытаться {
console.log ( Buliding ${internalDep.packageDir}
);
child_process.execSync ("сборка пряжи", {
cwd: ../${internalDep.packageDir}
,
});
console.log ( Packaging ${internalDep.packageDir}
);
child_process.execSync ("пакет пряжи", {
cwd: ../${internalDep.packageDir}
,
});
if (packageName !== internalDep.packageSpec.name) {
console.log(`Move to current directory ${internalDep.packageDir}`);
child_process.execSync(
`cp ../${internalDep.packageDir}/${internalDep.packageTgzName} .`,
{
cwd: ".",
}
);
}
} catch (e) {
console.log (e);
}
});
// возвращаемся к стандартной структуре пакетов
[... internalPackagesFull.values ()]
.filter ((internalDep) => packageName! == internalDep.packageSpec.name)
.forEach ((internalDep) => {
const {
packageSpec,
packageSpecFileName,
packageInternalDeps,
} = internalDep;
// change the package type
packageSpec.type = "module"; // THIS MAY NEED TO CHANGE FOR YOU
// specify the location of the dep to be the packaged zip file
packageInternalDeps.forEach((internalDepOfPackage) => {
packageSpec.dependencies[internalDepOfPackage] = "*";
});
fs.writeFileSync(
packageSpecFileName,
JSON.stringify(packageSpec, null, " ")
);
});
`` ''
Я использовал решение, предоставленное @sowdri (спасибо за это!), С небольшой настройкой, чтобы я мог свободно удалять и восстанавливать весь каталог dist/
, включая вторичный package.json
:
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
...,
plugins: [
new CopyPlugin({
patterns: [{ from: 'package.dist.json', to: 'package.json' }],
}),
],
};
И затем я сохраняю следующие package.dist.json
в корне пакета:
{
"name": "@package/name",
"version": "0.0.1",
"engines": {
"node": "10"
},
"main": "index.js",
"dependencies": {
"firebase-admin": "8.9.1",
"firebase-functions": "3.3.0"
},
"private": true
}
Возможно, удастся удалить зависимости из этого файла и полагаться на Webpack, чтобы объединить их (устраняя необходимость синхронизировать эти зависимости с вашим основным package.json
), но я не пробовал.
Я использую один репозиторий со сценарием для копирования .firebaserc
& firebase.json
для всех соответствующих каталогов или проектов firebase с использованием пакета npm
Я создаю package.json
из исходного package.json для развертывания функций.
вот сценарий copyFiles.js
:
const cpy = require('cpy');
const fs = require('fs');
const package = require('./package.json');
(async () => {
await cpy(['./../package.json', './**/*.json', './**/.firebaserc'], '../out/', {
parents: true,
cwd: 'src'
});
const dirs = fs.readdirSync('./out/');
const newPkg = {
main: package.main,
dependencies: package.dependencies,
engines: package.engines,
}
dirs.forEach(dir => {
fs.writeFileSync(`./out/${dir}/package.json`, JSON.stringify({ name: dir, ...newPkg }));
})
console.log('Files copied!', dirs);
})();
для развертывания перейдите к ./out/[project-name]/firebase deploy --only=functions
или напишите для него сценарий.
Я сталкиваюсь с некоторыми предупреждениями Webpack, подобными этому:
ПРЕДУПРЕЖДЕНИЕ в /Users/me/Development/myproject/node_modules/firebase-functions/lib/config.js 61: 23-42
Критическая зависимость: запрос зависимости - это выражение
Вы нашли способ решить эти проблемы или игнорируете / подавляете их?
Мне удалось заставить все работать без предупреждений 🥳 Я получил конфигурацию ниже. В частности, использование шаблонов регулярных выражений для внешних элементов имело значение, потому что, если у вас есть просто «firebase-functions» во внешних элементах, любой импорт, который вы делаете из подмодуля, не будет сопоставлен, и библиотека все равно будет включена в ваш пакет.
В результате проблем со сборкой я также столкнулся с некоторыми загадочными ошибками
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
target: "node",
mode: "production",
entry: "./src/index.ts",
devtool: "inline-source-map",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".json"],
alias: {
"~": path.resolve(__dirname, "src"),
},
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist/bundled"),
libraryTarget: "commonjs",
},
externals: ["express", /^firebase.+$/, /^@google.+$/],
plugins: [
new CopyPlugin({
patterns: [{ from: "package.dist.json", to: "package.json" }],
}),
],
};
Оказывается, отдельный package.dist.json не нужен. Раздражает наличие этого файла, конечно, то, что вам нужно вручную обновлять его каждый раз, когда вы обновляете любую из зависимостей, перечисленных в нем. Так что об этом очень легко забыть.
Вместо этого переместите все пакеты, которые вы _would not_ перечислить в вашем package.dist.json, в список devDependencies и просто используйте этот файл в подключаемом модуле копирования webpack. Теперь вам нужно иметь дело только с одним package.json 🎉
Кроме того, я не хочу, чтобы моя локальная версия nodejs обязательно совпадала с версией развернутого узла функций. Я обнаружил, что теперь вы можете указать functions.runtime
в файле firebase.json. Так что выньте поле engines
из package.json и вместо этого установите functions.runtime
на "10" или "12" в конфигурации firebase.
Для меня это выглядит так:
{
"functions": {
"source": "packages/cloud-functions/dist/bundled",
"runtime": "12"
},
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"emulators": {
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"pubsub": {
"port": 8085
}
}
}
Как у вас дела с исходными картами? Если я связываю свои функции с веб-пакетом, используя devtool: "inline-source-map"
он не попадает в отчеты об ошибках stackdriver. @sowdri
Я столкнулся с тем же самым в своем проекте, и это был довольно большой облом, так как я не хочу публиковать каждый пакет для побочного проекта. Было неприятно работать с несколькими файлами package.json
или создавать вне пакета. Оказывается, если вы включите свои deps в качестве необязательных, Lerna все равно их заберет, и Firebase не будет жаловаться при загрузке.
Приведенная ниже конфигурация предоставит вам поддержку с символической ссылкой dep с помощью одного package.json!
package.json
{
"name": "@your-package-name/functions",
"version": "0.1.0",
"scripts": {
"build": "webpack"
},
"engines": {
"node": "10"
},
"main": "dist/index.js",
"dependencies": {
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.6.1"
},
"optionalDependencies": {
"@your-package-name/shared": "^0.1.0",
"@your-package-name/utils": "^0.1.0"
}
}
webpack.config.js
const path = require('path')
// The cost of being fancy I suppose
// https://github.com/firebase/firebase-tools/issues/653
module.exports = {
target: 'node',
mode: 'production',
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
configFile: 'tsconfig.build.json',
},
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json'],
},
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'commonjs',
},
externals: {
'firebase-admin': 'firebase-admin',
'firebase-functions': 'firebase-functions',
},
}
firebase.json
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": {
"source": "packages/functions"
},
"emulators": {
"functions": {
"port": 5476
},
"firestore": {
"port": 4565
},
"ui": {
"enabled": true
}
}
}
Я использую рабочие области yarn, но мне также не нужно упоминать имена моих локальных пакетов в других файлах package.json. Я успешно развертываю и Firebase, и Vercel без него.
Я не уверен, что заставляет его работать. Просто добавьте эту стандартную конфигурацию в мой пакет верхнего уровня package.json:
"workspaces": {
"packages": [
"packages/*"
]
},
Я не против иметь package.json в каждой из папок / packages / *, поскольку запуск yarn upgrade-interactive
просто обработает их все за один раз. В некоторых пакетах я считаю полезным добавить скрипт специально для этой области.
---- редактировать ----
Я забыл упомянуть, что использую Typescript со ссылками на проекты. Возможно, это как-то связано с этим. Для Vercel я использую next-transpile-modules, чтобы включить свой общий код в пакет.
Я использую аналогичную настройку для @ 0x80 и @sowdri, чтобы заставить эту работу, но вместо того, чтобы перемещать мои локальные зависимости в devDependencies (что на самом деле не сработало для меня, думаю, я пропустил шаг) и использую copy-webpack-plugin
, Я использую generate-package-json-webpack-plugin
для создания моего package.json в папке dist. Это строит мой список зависимостей из того, что на самом деле требует результирующий код, поэтому, если он связан или является зависимостью разработчика, он не включается в результирующий package.json.
Я также настроил свои внешние элементы, используя webpack-node-externals
чтобы сделать все внешнее, за исключением моих пакетов монорепозитория с символическими ссылками, которые я использую регулярное выражение для соответствия префиксу имени проекта. Я также добавил регулярные выражения для пакетов firebase @ 0x80, размещенных как дополнительные внешние.
Это мой конфиг
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require("path");
const nodeExternals = require("webpack-node-externals");
const GeneratePackageJsonPlugin = require("generate-package-json-webpack-plugin");
const basePackage = {
name: "@project/functions",
version: "1.0.0",
main: "./index.js",
scripts: {
start: "yarn run shell"
},
engines: {
node: "12"
}
};
module.exports = {
target: "node",
mode: "production",
entry: "./src/index.ts",
devtool: "inline-source-map",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".json"],
alias: {
"@": path.resolve(__dirname, "src"),
"@root": path.resolve(__dirname, "./"),
"@types": path.resolve(__dirname, "src/@types"),
"@utils": path.resolve(__dirname, "src/utils")
}
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "commonjs"
},
externals: [
/^firebase.+$/,
/^@google.+$/,
nodeExternals({
allowlist: [/^@project/]
})
],
plugins: [new GeneratePackageJsonPlugin(basePackage)]
};
Еще одно преимущество использования webpack для объединения кода - я наконец могу использовать псевдонимы модулей :)
Самый полезный комментарий
+1 к этому, облачные функции обычно должны будут совместно использовать некоторый общий код (например, интерфейсы) с другими приложениями, и хороший способ справиться с этим - монорепорация (например, lerna) или прямое использование символических ссылок. Я взял последнее и решил, создав несколько скриптов. Идея довольно проста: я копирую то, что нужно, в каталог функций, и удаляю его после
Вот как я сделал это с этой структурой каталогов:
`` ''
| - .firebaserc
| - firebase.json
| - ...
| - src /
| - package.json
| - pre-deploy.js
| - post-deploy.js
| - ....
| - src /
| - package.json
| - ....
const fs = require ("fs-extra");
const packageJsonPath = "./package.json";
const packageJson = требуется (packageJsonPath);
(async () => {
ждать fs.remove (
./shared
);await fs.copy (
../shared
,./shared
);}) ();
const packageJsonPath = "./package.json";
const packageJson = требуется (packageJsonPath);
const fs = require ("fs-extra");
(async () => {
ждать fs.remove (
./shared
);}) ();
"functions": {
"источник": "функции",
"Preploy": [
"npm --prefix" $ RESOURCE_DIR "выполнить предварительное развертывание"
],
"postdeploy": [
"npm --prefix" $ RESOURCE_DIR "запустить после развертывания"
]
},
`` ''
Если вы выполняете сборку, то внутри каталога
dist
илиlib
вас должно быть два брата и сестры: функции и общий доступ (это произошло из-за общей зависимости). Обязательно обновите функцииpackage.json
main
чтобы они указывали наlib/functions/src/index.js
чтобы развертывание работало.На данный момент это решено, но это обходной путь, а не решение. Я думаю, что инструменты firebase действительно должны поддерживать символические ссылки