Firebase-tools: デプロイメントでモノリポジトリをサポートする

作成日 2018年01月31日  ·  47コメント  ·  ソース: firebase/firebase-tools

参照: https

バージョン情報

3.17.3

再現する手順

予想される行動

実際の動作

feature request

最も参考になるコメント

これに+1すると、クラウド機能は通常、他のアプリといくつかの共通コード(インターフェースなど)を共有する必要があります。これに対処する良い方法は、モノレポ(lernaなど)またはシンボリックリンクを直接使用することです。 私は後者を採用し、いくつかのスクリプトを作成することで解決しました。 概念は非常に簡単です。必要なものをfunctionsディレクトリ内にコピーし、後で削除します。

これが私がこのディレクトリ構造でそれをした方法です:
`` `

  • 根/
    | -.firebaserc
    | --firebase.json
    | -..。
  • 関数/
    | --src /
    | --package.json
    | --pre-deploy.js
    | --post-deploy.js
    | -...。
  • 共有/
    | --src /
    | --package.json
    | -...。
content of `pre-deploy.js`

const fs = require( "fs-extra");

const packageJsonPath = "./package.json";
const packageJson = require(packageJsonPath);

(非同期()=> {
fs.remove( ./shared );を待つ
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 = require(packageJsonPath);
const fs = require( "fs-extra");

(非同期()=> {
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)

"関数": {
「ソース」:「関数」、
「事前デプロイ」:[
"npm --prefix" $ RESOURCE_DIR "run pre-deploy"
]、
"postdeploy":[
"npm --prefix" $ RESOURCE_DIR "run post-deploy"
]
}、
`` `

ビルドを行う場合、 distまたはlibディレクトリ内に、関数と共有の2つの兄弟があります(これは共有の依存関係のために発生しました)。 デプロイを機能させるには、関数package.json mainlib/functions/src/index.jsを指すように更新してください。

今のところ解決されていますが、これは回避策であり、解決策ではありません。 Firebaseツールは本当にシンボリックリンクをサポートする必要があると思います

全てのコメント47件

これは私のセットアップでは機能しているようです。つまり、 package.jsonapi/ワークスペースの下にある場合でも、 deployはルートnode_modulesからパッケージを取得します( functions/代わりに別のフォルダ名を使用しました)。 ここで修正が必要なものは他にありますか?

編集:さらに、 package.jsonapi/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ツールは関数をアップロードするときにシンボリックリンクの依存関係を取得しないようです

ああ、まあまあ、私はそのウサギの穴を自分で避けました

問題は何か詳しく教えていただけますか? 上記のように、 apiappワークスペースを含むベアヤーンを使用し、 yarn workspace api build && yarn workspace app buildを使用してビルドします(それぞれに固有のbuildスクリプトを使用)ワークスペース)。 ビルドスクリプト
1) outDirを含むTSコードをそれぞれapi/distapp/distコンパイルします
2)対応するpackage.jsonファイルをdistディレクトリにコピーします
3) yarn.lockを_root_フォルダーからdistディレクトリにコピーします

次に、_root_フォルダーからyarn firebase deployを実行すると、問題なくapi/distapp/dist両方が取得されます。 私のfirebase.jsonは次のようになります

  "functions": {
    "source": "api/dist"
  },
  "hosting": {
    "public": "app/dist",

残念ながら、私はまだ完全なコードを共有することはできませんが、この設定が重要です、afaik。

また、私は間違っているかもしれませんが、 firebase deployスクリプトは実際にはnode_modulesディレクトリを使用していないと思います。 distディレクトリからコードpackage.jsonyarn.lockを取得し、残りを実行すると思います。

それは本当だ。 firebase.jsonの「functions.ignore」のデフォルト値は
["node_modules"]なので、アップロードされません。 私はあなたがそれを上書きできると信じています
ただし、いくつかのローカルモジュールを出荷したい場合。

月、2019年6月17日には、6:58 PMデニス・ロジノブ[email protected]
書きました:

また、私は間違っているかもしれませんが、firebasedeployスクリプトはそうではないと思います
実際にはnode_modulesディレクトリを使用してください。 私はそれがちょうど拾うと思います
distディレクトリのcod、package.json、yarn.lockは、
残り。


このスレッドにサブスクライブしているため、これを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/firebase/firebase-tools/issues/653?email_source=notifications&email_token=ACATB2U73VS2KIILUVRFFB3P3A6NPA5CNFSM4EOR24GKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2
またはスレッドをミュートします
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アップロードしています(_firebase.json_のfunctions.ignoreを使用)。 結果は同じです。

utilitiesが_node-modules_ node_modules/utilities -> ../../utilitiesにsyslinkとして作成されているためだと思います

アップロード時にfirebase-toolsにシンボリックリンクされたモジュールのコンテンツが含まれていない可能性がありますか(逆参照なし)?

申し訳ありませんが、 firebase.jsonどのフォルダーにあるかを明確にできますか(そしてfunctions構成セクションを表示できますか)。

_firebase.json_はルートフォルダにありました。 構成は標準でした。 このようなSmth:

  "functions": {
    "predeploy": [
      "yarn --cwd \"$RESOURCE_DIR\" run lint",
      "yarn --cwd \"$RESOURCE_DIR\" run build"
    ],
    "source": "functions",
    "ignore": []
  },
  <...>

シンボリックリンクであるnode_modules/utilitiesを除いて、すべてが期待どおりにデプロイされました(_node_modules_を含む)。


私は、次のようないくつかのスクリプトを作成することで、この問題を回避することができます。

  • ワークスペースごとにパッケージを作成します( yarn pack )。 たとえば、これにより_utilities.tgz_が作成されます。
  • すべての出力を特定のディレクトリに移動します。
  • ワークスペースの依存関係にtgzファイルを使用するように_package.json_を変更します。 例: dependencies { "utilities": "1.0.0" -> dependencies { "utilities": "file:./utilities.tgz"
  • そのディレクトリをfirebaseにデプロイする

アップロード前の出力ディレクトリコンテンツ:

- dist
|  - lib
|  | -index.js
|  - utilities.tgz
|  - package.json <---------- This is modified to use *.tgz for workspaces

@audkar今日、私はあなたと同じ問題に遭遇しました。

LernaとYarnの両方のワークスペースは初めてです。 私が理解しているように、Lernaを使用することもできます。 それは何らかの形で役立ちますか?

あなたの回避策は私には少し複雑に思えます🤔

また、 `--cwd" $ RESOURCE_DIR "は何のためにあるのでしょうか?

--cwdは「現在の作業ディレクトリ」を表し、 $RESOURCE_DIRはソースディレクトリの値(この場合はfunctions )を保持します。 このフラグを追加すると、 yarnがルートではなくfunctionsディレクトリで実行されるようになります

@audkarああなるほど。 したがって、 yarn workspace functions lintyarn workspace functions buildでも同じことができます。

@dinvladなぜdistフォルダーをターゲットにして、そこにあるものをコピーしているのかは私にはdist/index.jsを指す場合、同じように機能するはずです。 次に、sourceをapi / distではなくapiに設定する必要があります。

@dinvladコメントからyarn workspaceコマンドを学びましたが、何らかの理由で機能しないようです。 こちらをご覧ください。 何か案が?

ここで少し話題から外れてすみません。 ノイズを最小限に抑えるために、SOでコメントするかもしれません。

@ 0x80 package.jsonapi/distにコピーし、 firebase.jsonapi/distポイントするので、「ビルドされた」ファイルのみがクラウド関数内にパッケージ化されます。 firebase.jsonapiにポイントするとどうなるかわかりません-おそらく、 api/distmain基づく)の中にあるものだけをパッケージ化するのに十分賢いでしょうpackage.json main属性)。 しかし、 api/dist指すだけの方がクリーンだと思いました。

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

また、packages / cloud-functionsには、追加のgitignoreファイルがあります。

yarn.lock
*.tgz

これが私のために働いたものです

- root/
|  - .firebaserc
|  - firebase.json
- packages/
  | - package1/
  | - functions/
    | - dist/
    | - src/
    | packages.json

そしてroot/firebase.json
`` `
{{
"関数": {
"predeploy": "npm --prefix" $ RESOURCE_DIR "run build"、
"ソース": "パッケージ/関数"
}
}
「」

@kaminskypavelは、packages / package1(または他の兄弟パッケージ)に依存するパッケージ/関数ですか?

@ 0x80ポジティブ。

モノレポについて私が誤解していた根本的なことがあったと思います。 共有パッケージを実際にNPMに公開しなくても、パッケージを共有し、そのパッケージを使用してアプリをデプロイできると想定しました。

FirebaseやNow.shなどのデプロイでは通常コードがアップロードされ、クラウドでインストールとビルドが行われるため、これは不可能なようです。 私は正しいですか?

@kaminskypavel私はあなたのアプローチを試しましたが、それは機能しますが、最初にパッケージをNPMに公開した後でのみです。 私の場合、パッケージはプライベートであるため、最初は「見つかりません」というエラーが発生しました。そのため、ここで説明するように、.npmrcファイルをクラウド関数パッケージのルートに追加する必要もありまし

@audkar共通パッケージをNPMに公開していますか、それとも公開されていない共有コードを使用してデプロイしようとしていますか?

@ 0x80私はこの理解についてあなたと一緒です-FirebaseFunctionのデプロイは、デプロイを高速化するという名目で、package.jsonで指定されたすべてのパッケージがnpmで利用可能になると(誤って)想定していると思います。

ヤーンワークスペースのセットアップの人気が高まるにつれ、Firebase Functionsでシンボリックリンクされたパッケージを使用できないことに驚く人が増えると思います。特に、デプロイするまでは正常に機能するためです。

npmがワークスペースのサポートを追加することで、ローカルパッケージがどのように機能するかについてのエコシステム標準があります。

この問題は1年以上前のものですが、Firebase側からの計画(または計画の欠如)に関する更新はありますか?

これはかなり素晴らしい機会だと思います。Firebaseの一連のサービスは、優れたモノレポの設定を求めています。

これに+1すると、クラウド機能は通常、他のアプリといくつかの共通コード(インターフェースなど)を共有する必要があります。これに対処する良い方法は、モノレポ(lernaなど)またはシンボリックリンクを直接使用することです。 私は後者を採用し、いくつかのスクリプトを作成することで解決しました。 概念は非常に簡単です。必要なものをfunctionsディレクトリ内にコピーし、後で削除します。

これが私がこのディレクトリ構造でそれをした方法です:
`` `

  • 根/
    | -.firebaserc
    | --firebase.json
    | -..。
  • 関数/
    | --src /
    | --package.json
    | --pre-deploy.js
    | --post-deploy.js
    | -...。
  • 共有/
    | --src /
    | --package.json
    | -...。
content of `pre-deploy.js`

const fs = require( "fs-extra");

const packageJsonPath = "./package.json";
const packageJson = require(packageJsonPath);

(非同期()=> {
fs.remove( ./shared );を待つ
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 = require(packageJsonPath);
const fs = require( "fs-extra");

(非同期()=> {
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)

"関数": {
「ソース」:「関数」、
「事前デプロイ」:[
"npm --prefix" $ RESOURCE_DIR "run pre-deploy"
]、
"postdeploy":[
"npm --prefix" $ RESOURCE_DIR "run post-deploy"
]
}、
`` `

ビルドを行う場合、 distまたはlibディレクトリ内に、関数と共有の2つの兄弟があります(これは共有の依存関係のために発生しました)。 デプロイを機能させるには、関数package.json mainlib/functions/src/index.jsを指すように更新してください。

今のところ解決されていますが、これは回避策であり、解決策ではありません。 Firebaseツールは本当にシンボリックリンクをサポートする必要があると思います

@michelepatrassiは、このケースを管理するためにfirelinkライブラリを作成したことを思い出させてくれたことに触発されました。 内部的にrsyncを使用して、再帰ファイルをコピーします。

https://github.com/rxdi/firelink

npm i -g @rxdi/firelink

基本的な使い方
monorepoアプローチがあり、パッケージがpackage.jsonが配置されている現在のディレクトリから2レベル下に配置されていると仮定します。

package.json

  "fireDependencies": {
    "@graphql/database": "../../packages/database",
    "@graphql/shared": "../../packages/shared",
    "@graphql/introspection": "../../packages/introspection"
  },

firelink実行すると、フォルダに関連するパッケージがコピーされ、既存のパッケージがローカルモジュールインストール"@graphql/database": "file:./.packages/database",マップされ、コマンドfirebaseが実行され、残りの引数がfirelinkから渡されます。
基本的にfirelinkの代替品であるfirebaseそれが生成しますので、CLI firebase彼の仕事のコピーが終了したら、最後にpackagesし、修正package.json

よろしく!

これに噛まれたばかりです。monoreposが標準になり、デフォルトでサポートされるはずです。

みんな、この問題の簡単な解決策は、webpackを使用してクラウド機能をバンドルし、バンドルされたディレクトリからデプロイすることです。 ここに添付されているのは、私が使用している基本的な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"
  }
}

webpack/cloud-functionsフォルダーにもpackage.jsonファイルがあることを忘れないでください。

{
  "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
}

これはテストされ、機能しています。 私はグーグルクラウドビルドを使用しています。 必要に応じて詳細をお尋ねください。

ありがとう、

@sowdri共有してくれてありがとう! firebase.json functions.predeployステップからwebpackビルドをトリガーしますか、それともfirebase deployを呼び出す前にクラウドビルドスクリプトからトリガーしますか?

@ 0x80 cloud buildステップでビルドしています。 つまり、 firebase cliによると、これはJSで構築された関数のセットにすぎません。

@sowdri例をありがとう。 AWS Lambdas / Serverlessの過去のプロジェクトで同じアプローチを使用することになりました。ツールを強制的にヤーンモノレポで動作させるよりも、(Webpack)バンドルをアップロードする方が簡単でした。

私もこれに固執しています....関数をデプロイしようとするまで(Firebaseエミュレーターでさえ)すべてが正常に機能しました(reactでビルドされたWebアプリはOKをデプロイします)。 :(Firebaseチームがmonoreposのサポートをすぐに追加できることを願っています。

モノレポの他のパッケージにはbabelを使用しているので、そのままにしておきたいと思います。 他に何もなければ、私はwebpackを試すかもしれません...それはいくつかのために働いているようです。

編集:GitHubパッケージレジストリを使用してこれを解決しました。 そこで、すべてのパッケージをそこで公開してから、 travis functionsサーバーと.npmrc介して実行)。 ...エレガントなソリューションのようです。 私はここでこのアプローチのアイデアを得ました: https

ええ、これにも噛まれました。 firebase serve --only functionsではすべてが完全に機能しましたが、デプロイするとモジュールを見つけることができませんでした。

結局、パッケージを作成するための小さなスクリプトを作成しました。 これは、モジュールやディレクトリ名と一致するパッケージ名を使用するなど、私の環境の詳細を反映していますが、他の人にも役立つことを願っています。

`` `「fs」からfsをインポートします。
「child_process」からchild_processをインポートします。

const internalPackagesFull = new Map();

//パッケージのすべての部門を検索します
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)=> key.includes( "turing")); //これはあなたのために変更する必要があります

const packageTgzName = ${packageName.replace("@", "").replace("/", "-")}-v${ packageSpec.version }.tgz ;

internalPackagesFull.set(packageName、{
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(packageName);

//更新されたパッケージを作成します-一般的なjsを使用し、参照はローカルtgzファイルです
[... internalPackagesFull.values()]。forEach((internalDep)=> {
const {packageSpec、packageSpecFileName、packageInternalDeps} = internalDep;

//パッケージタイプを変更します
packageSpec.type = "commonjs"; //これはあなたのために変更する必要があるかもしれません

//パッケージ化されたzipファイルとなるdepの場所を指定します
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( "yarn build"、{
cwd: ../${internalDep.packageDir}
});
console.log( Packaging ${internalDep.packageDir} );
child_process.execSync( "yarn pack"、{
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が提供するソリューションを使用しました(ありがとうpackage.jsonを含むdist/ディレクトリ全体を自由に削除して再生成できるようにしました。

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と同期させる必要がなくなります)が、私は試していません。

スクリプトを使用して単一のリポジトリを使用し、関連するすべてのディレクトリまたはFirebaseプロジェクトの.firebasercfirebase.jsonを、コンパイルされたコードが存在する出力ディレクトリにdir構造を保持するnpmcpyパッケージを使用してコピーします。

関数のデプロイ用に、元のpackage.jsonからpackage.jsonを作成します。
image

これが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」がある場合、サブモジュールからのインポートは一致せず、ライブラリはバンドルに含まれるため、違いが生じました。

バンドルの問題の結果として、デプロイ時にいくつかの不可解な@grpcエラーも発生しました。 参考までに保管するのを忘れてしまいました。

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は必要ないことがわかりました。 もちろん、このファイルがあることの厄介なことは、そこにリストされている依存関係のいずれかを更新するたびに手動で更新する必要があることです。 ですから、それを忘れがちです。

代わりに、package.dist.jsonにリストしないすべてのパッケージをdevDependenciesリストに移動し、そのファイルをwebpackコピープラグインで使用します。 これで、処理するpackage.jsonが1つだけになりました🎉

また、ローカルのnodejsバージョンが関数でデプロイされたノードのバージョンと必ずしも同じである必要はありません。 firebase.jsonファイルでfunctions.runtimeを指定できるようになりました。 そのため、package.jsonからenginesフィールドを取り出し、代わりにFirebase設定でfunctions.runtimeを「10」または「12」に設定します。

これは私にとってそれがどのように見えるかです:

{
  "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"を使用して関数をwebpackにバンドルすると、スタックドライバーのエラーレポートに反映されません。 @sowdri

私は自分のプロジェクトで同じことに遭遇しましたが、サイドプロジェクトのすべてのパッケージを公開したくないので、これはかなり大きな問題でした。 複数のpackage.jsonファイルについていくのは面倒で、パッケージの外でビルドする必要がありました。 オプションとしてdepsを含めると、Lernaは引き続きそれらを取得し、Firebaseはアップロード時に文句を言いません。

以下の設定は、単一のpackage.jsonでシンボリックリンクされたdepサポートを取得します!

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/*"
    ]
  },

yarn upgrade-interactiveを実行すると、すべてを一度に処理できるため、各/ packages / *フォルダーにpackage.jsonを置いてもかまいません。 一部のパッケージでは、そのスコープ専用のスクリプトを追加できると便利です。

- - 編集 - -

プロジェクト参照でTypescriptを使用していることを忘れました。 それはそれと関係があるかもしれません。 Vercelの場合、next-transpile-modulesを使用して、共有コードをバンドルに含めています。

私はこれを機能させるために@ 0x80@sowdriまでの同様の設定を使用していますが、ローカルの依存関係をdevDependenciesに移動するのではなく(実際には機能しませんでした。ステップが欠落していると思います)、 copy-webpack-pluginを使用しgenerate-package-json-webpack-pluginを使用してdistフォルダーにpackage.jsonをビルドしています。 これにより、結果のコードが実際に必要としているものから依存関係リストが作成されるため、バンドルされている場合やdevの依存関係がある場合は、結果のpackage.jsonに含まれません。

また、 webpack-node-externalsを使用して外部を設定し、プロジェクト名のプレフィックスと一致するように正規表現を使用しているシンボリックリンクされたmonorepoパッケージを除くすべてを外部にしました。 追加の外部として投稿された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つの利点は、最終的にモジュールエイリアスを使用できることです:)

このページは役に立ちましたか?
0 / 5 - 0 評価