Firebase-tools: Mendukung mono-repo dalam penerapan

Dibuat pada 31 Jan 2018  ·  47Komentar  ·  Sumber: firebase/firebase-tools

Lihat: https://github.com/firebase/firebase-functions/issues/172

Informasi versi

3.17.3

Langkah-langkah untuk mereproduksi

Perilaku yang diharapkan

Perilaku sebenarnya

feature request

Komentar yang paling membantu

Memberi +1 pada ini, fungsi cloud biasanya perlu berbagi beberapa kode umum (misalnya antarmuka) dengan aplikasi lain dan cara yang bagus untuk menangani ini adalah monorepo (misalnya lerna) atau menggunakan symlink secara langsung. Saya mengambil yang terakhir dan menyelesaikannya dengan membuat beberapa skrip. Konsepnya cukup mudah: Saya menyalin apa yang diperlukan di dalam direktori fungsi dan saya menghapusnya setelahnya

Inilah cara saya melakukannya dengan struktur direktori ini:
```

  • akar/
    | - .firebaserc
    | - firebase.json
    | - ...
  • fungsi/
    | -src/
    | - package.json
    | - pra-penyebaran.js
    | - pasca-penyebaran.js
    | - ....
  • bersama/
    | -src/
    | - package.json
    | - ....
content of `pre-deploy.js`

const fs = membutuhkan("fs-ekstra");

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

(asinkron () => {
menunggu fs.remove( ./shared );
menunggu 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 = membutuhkan(packageJsonPath);
const fs = membutuhkan("fs-ekstra");

(asinkron () => {
menunggu 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)

"fungsi": {
"sumber": "fungsi",
"pra-penerapan": [
"npm --prefix "$RESOURCE_DIR" jalankan pra-penyebaran"
],
"pasca penerapan": [
"npm --prefix "$RESOURCE_DIR" jalankan pasca-penyebaran"
]
},
```

Jika Anda melakukan pembangunan, di dalam direktori dist atau lib Anda sekarang harus memiliki dua saudara kandung: fungsi dan bersama (ini terjadi karena ketergantungan bersama). Pastikan untuk memperbarui fungsi package.json main untuk menunjuk ke lib/functions/src/index.js agar penerapan berfungsi.

Untuk saat ini sudah terpecahkan tetapi itu solusi, bukan solusi. Saya pikir alat firebase harus benar-benar mendukung symlink

Semua 47 komentar

Ini tampaknya berfungsi dalam pengaturan saya, yaitu deploy mengambil paket dari root node_modules , meskipun package.json untuk itu terletak di bawah ruang kerja api/ ( Saya telah menggunakan nama folder yang berbeda, bukan functions/ ). Apakah ada hal lain yang perlu diperbaiki di sini?

EDIT: Selain itu, saya menyalin package.json ke api/dist untuk digunakan oleh deploy .

// firebase.json
  ...
  "functions": {
    "source": "api/dist"
  },
  ...

Jadi, 2 level bersarang masih berhasil menyelesaikan root node_modules .

@dinvlad bisakah Anda membagikan repo?

@orouz sayangnya belum, itu sumber tertutup untuk saat ini.

Apakah ada yang berhasil mengatasi masalah ini? Berbagi proyek contoh sederhana akan sangat berguna.

@audkar Saat ini saya hanya menggunakan lerna.js.org dan run perintah untuk mengeksekusi skrip npm di setiap subfolder dengan struktur folder ini:

- service1/
|  - .firebaserc
|  - firebase.json
- service2/
|  - .firebaserc
|  - firebase.json
- app1/
|  - .firebaserc
|  - firebase.json
- app2/
|  - .firebaserc
|  - firebase.json
- firestore/
|  - firestore.rules
|  - firestore.indexes.json
- etc...

Memastikan file firebase.json untuk setiap layanan tidak saling menginjak, diserahkan kepada pengguna. Konvensi sederhana menggunakan grup fungsi dan penargetan nama multi-situs berarti ini diselesaikan untuk Cloud Functions dan Hosting. Masih belum mendapatkan solusi untuk aturan Firestore/GCS, meskipun memisahkannya mungkin tidak ideal...

dibahas di sini sebelumnya - https://github.com/firebase/firebase-tools/issues/1116

@jthegedus terima kasih atas balasan Anda. Tapi saya pikir masalah tiket ini berbeda. Saya mencoba menggunakan ruang kerja benang. Dan tampaknya alat firebase tidak mengambil dependensi symlink saat mengunggah fungsi

Ah cukup adil, aku sendiri sudah menghindari lubang kelinci itu

Bisakah Anda menjelaskan apa masalahnya? Seperti disebutkan di atas, saya hanya menggunakan Benang kosong dengan ruang kerja api dan app di dalamnya, dan saya membuatnya menggunakan yarn workspace api build && yarn workspace app build (dengan skrip build khusus untuk masing-masing ruang kerja). Script membangun
1) kompilasi kode TS dengan outDir menjadi api/dist dan app/dist
2) salin file package.json ke dalam direktori dist
3) salin yarn.lock dari folder _root_, ke direktori dist

Kemudian saya hanya menjalankan yarn firebase deploy dari folder _root_, dan itu mengambil api/dist dan app/dist tanpa cegukan. firebase.json terlihat seperti

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

Sayangnya, saya masih tidak dapat membagikan kode lengkapnya, tetapi pengaturan ini yang terpenting, afaik.

Juga, saya mungkin salah tetapi saya pikir skrip firebase deploy sebenarnya tidak menggunakan direktori node_modules . Saya pikir itu hanya mengambil kode, package.json , dan yarn.lock dari direktori dist , dan melakukan sisanya.

Itu benar. Nilai default "functions.ignore" di firebase.json adalah
["node_modules"] jadi tidak diunggah. Saya percaya Anda bisa menimpanya
meskipun jika Anda ingin mengirimkan beberapa modul lokal.

Pada Senin, 17 Juni 2019, 18:58 Denis Loginov [email protected]
menulis:

Juga, saya mungkin salah tetapi saya pikir skrip penyebaran firebase tidak
benar-benar menggunakan direktori node_modules Anda. Saya pikir itu hanya mengambil
cod, package.json, dan yarn.lock dari direktori dist, dan melakukan
istirahat.


Anda menerima ini karena Anda berlangganan utas ini.
Balas email ini secara langsung, lihat di GitHub
https://github.com/firebase/firebase-tools/issues/653?email_source=notifications&email_token=ACATB2U73VS2KIILUVRFFB3P3A6NPA5CNFSM4EOR24GKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVW78ZGODX465W150XHJKTORDN
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/ACATB2U3Q2TLVBICRJ3B5OLP3A6NPANCNFSM4EOR24GA
.

@dinvlad Ya, itu membutuhkan package.json dan file kunci mana pun yang Anda gunakan saat menginstal deps di penyebaran cloud post.

Saya percaya skenario yang awalnya diuraikan dalam masalah lain menggunakan paket bersama di dalam ruang kerja dan beberapa masalah dengan pengangkatan ruang lingkup. Karena saya tidak menggunakan benang dengan cara ini, saya hanya bisa berspekulasi dari apa yang saya baca di sana.

@samtstern @jthegedus terima kasih, senang tahu!

Sepertinya kita semua membicarakan masalah yang berbeda. Saya akan mencoba menjelaskan masalah yarn workspaces .

Proyek bermasalah

tata letak proyek

- utilities/
|  - package.json
- functions/
|  - package.json
- package.json

_./package.json_

{
  "private": true,
  "workspaces": ["functions", "utilities"]
}

_fungsi/paket.json_

{
  <...>
  "dependencies": {
    "utilities": "1.0.0",
    <...>
  }
}

Masalah

Kesalahan selama penerapan fungsi:

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

Fungsi berfungsi dengan baik secara lokal di emulator.

Solusi dicoba

Mengunggah node_modules (menggunakan functions.ignore di _firebase.json_). Hasilnya sama.

Dugaan saya itu karena utilities dibuat sebagai syslink di _node-modules_ node_modules/utilities -> ../../utilities

Mungkinkah firebase-tools tidak menyertakan konten modul yang disinkronkan saat mengunggah (tanpa dereferensi)?

Maaf, dapatkah Anda menjelaskan di folder mana firebase.json tinggal (dan tunjukkan bagian konfigurasinya untuk functions )?

_firebase.json_ berada di folder root. Konfigurasi adalah standar. Seperti ini:

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

semuanya dikerahkan seperti yang diharapkan (termasuk _node_modules_) kecuali node_modules/utilities yang merupakan symlink.


Saya berhasil mengatasi masalah ini dengan menulis beberapa skrip yang:

  • buat paket untuk setiap ruang kerja ( yarn pack ). misalnya ini menciptakan _utilities.tgz_.
  • memindahkan semua output ke beberapa dir tertentu.
  • memodifikasi _package.json_ untuk menggunakan file tgz untuk dependensi ruang kerja. misalnya dependencies { "utilities": "1.0.0" -> dependencies { "utilities": "file:./utilities.tgz"
  • menyebarkan dir itu ke firebase

keluaran konten dir sebelum mengunggah:

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

@audkar Hari ini saya mengalami masalah yang sama seperti Anda.

Saya baru mengenal ruang kerja Lerna dan Yarn. Seperti yang saya pahami, Anda juga bisa menggunakan Lerna. Apakah itu membantu?

Solusi Anda tampaknya agak rumit bagi saya

Juga bertanya-tanya, untuk apa `--cwd "$RESOURCE_DIR"?

--cwd adalah singkatan dari "current working directory" dan $RESOURCE_DIR menyimpan nilai untuk direktori sumber ( functions dalam kasus ini). Menambahkan flag ini akan membuat yarn dieksekusi di dir functions alih-alih root

@audkar Ah begitu. Jadi Anda bisa melakukan hal yang sama dengan yarn workspace functions lint dan yarn workspace functions build

@dinvlad Tidak jelas bagi saya mengapa Anda menargetkan folder dist dan menyalin hal-hal di sana. Jika Anda membangun ke dist, tetapi meninggalkan package.json di tempatnya dan mengarahkan main ke dist/index.js maka semuanya akan berfungsi sama, bukan? Anda kemudian harus mengatur sumber ke api alih-alih api/dist.

@dinvlad Saya mempelajari perintah yarn workspace dari komentar Anda, tetapi sepertinya tidak dapat membuatnya berfungsi karena suatu alasan. Lihat di sini . Ada ide?

Maaf untuk pergi sedikit di luar topik di sini. Mungkin berkomentar di SO, untuk meminimalkan kebisingan.

@0x80 Saya menyalin package.json ke api/dist dan mengarahkan firebase.json ke api/dist jadi hanya file "buatan" yang dikemas di dalam fungsi cloud. Saya tidak yakin apa yang akan terjadi jika saya mengarahkan firebase.json ke api - mungkin masih cukup pintar untuk hanya mengemas apa yang ada di dalam api/dist (berdasarkan main atribut di package.json ). Tapi saya pikir itu lebih bersih untuk hanya menunjuk ke api/dist .

Re yarn workspace , saya menjawab pada SO ;)

@dinvlad itu akan menggabungkan akar dari apa yang Anda arahkan, tetapi Anda dapat memasukkan semua yang tidak ingin Anda sertakan dalam daftar abaikan firebase.json.

Saya sekarang telah menggunakan solusi yang mirip dengan @audkar.

{
  "functions": {
    "source": "packages/cloud-functions",
    "predeploy": ["./scripts/pre-deploy-cloud-functions"],
    "ignore": [
      "src",
      "node_modules"
    ]
  }
}

Maka skrip pre-deploy-cloud-functions adalah:

#!/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

Dan package/cloud-functions memiliki file gitignore tambahan:

yarn.lock
*.tgz

inilah yang berhasil untuk saya

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

dan di root/firebase.json :
```
{
"fungsi": {
"predeploy": "npm --prefix "$RESOURCE_DIR" jalankan build",
"sumber": "paket/fungsi"
}
}
````

@kaminskypavel apakah paket/fungsi Anda tergantung pada paket/paket1 (atau paket saudara lainnya)?

@0x80 positif.

Saya pikir ada sesuatu yang mendasar yang saya salah pahami tentang monorepos. Saya berasumsi Anda dapat membagikan paket dan menerapkan aplikasi menggunakan paket itu tanpa benar-benar memublikasikan paket bersama ke NPM.

Tampaknya ini tidak mungkin, karena penerapan seperti Firebase atau Now.sh biasanya akan mengunggah kode dan kemudian di cloud melakukan instalasi dan pembangunan. Apakah saya benar?

@kaminskypavel Saya mencoba pendekatan Anda dan berhasil, tetapi hanya setelah menerbitkan paket saya ke NPM terlebih dahulu. Karena dalam kasus saya paketnya pribadi, saya awalnya mendapatkan kesalahan "tidak ditemukan", jadi saya juga harus menambahkan file .npmrc saya ke root paket fungsi cloud seperti yang dijelaskan di sini

@audkar Apakah Anda menerbitkan paket umum Anda ke NPM, atau apakah Anda seperti saya mencoba menyebarkan dengan kode bersama yang tidak dipublikasikan?

@ 0x80 Saya bersama Anda dalam pemahaman ini - Saya pikir penerapan Fungsi Firebase hanya (salah) dengan asumsi bahwa semua paket yang disebutkan dalam package.json akan tersedia di npm, atas nama mempercepat penerapan.

Karena pengaturan ruang kerja benang menjadi lebih populer, saya membayangkan lebih banyak orang akan terkejut bahwa mereka tidak dapat menggunakan paket yang disinkronkan di Firebase Functions – terutama karena mereka berfungsi dengan baik sampai Anda menerapkannya.

Dengan npm menambahkan dukungan untuk ruang kerja , kami memiliki standar ekosistem tentang cara kerja paket lokal.

Karena masalah ini sudah lebih dari satu tahun, adakah pembaruan dari pihak Firebase tentang rencana (atau kurangnya rencana) di sini?

Saya pikir ini adalah peluang yang cukup keren – rangkaian layanan Firebase meminta pengaturan monorepo yang baik.

Memberi +1 pada ini, fungsi cloud biasanya perlu berbagi beberapa kode umum (misalnya antarmuka) dengan aplikasi lain dan cara yang bagus untuk menangani ini adalah monorepo (misalnya lerna) atau menggunakan symlink secara langsung. Saya mengambil yang terakhir dan menyelesaikannya dengan membuat beberapa skrip. Konsepnya cukup mudah: Saya menyalin apa yang diperlukan di dalam direktori fungsi dan saya menghapusnya setelahnya

Inilah cara saya melakukannya dengan struktur direktori ini:
```

  • akar/
    | - .firebaserc
    | - firebase.json
    | - ...
  • fungsi/
    | -src/
    | - package.json
    | - pra-penyebaran.js
    | - pasca-penyebaran.js
    | - ....
  • bersama/
    | -src/
    | - package.json
    | - ....
content of `pre-deploy.js`

const fs = membutuhkan("fs-ekstra");

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

(asinkron () => {
menunggu fs.remove( ./shared );
menunggu 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 = membutuhkan(packageJsonPath);
const fs = membutuhkan("fs-ekstra");

(asinkron () => {
menunggu 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)

"fungsi": {
"sumber": "fungsi",
"pra-penerapan": [
"npm --prefix "$RESOURCE_DIR" jalankan pra-penyebaran"
],
"pasca penerapan": [
"npm --prefix "$RESOURCE_DIR" jalankan pasca-penyebaran"
]
},
```

Jika Anda melakukan pembangunan, di dalam direktori dist atau lib Anda sekarang harus memiliki dua saudara kandung: fungsi dan bersama (ini terjadi karena ketergantungan bersama). Pastikan untuk memperbarui fungsi package.json main untuk menunjuk ke lib/functions/src/index.js agar penerapan berfungsi.

Untuk saat ini sudah terpecahkan tetapi itu solusi, bukan solusi. Saya pikir alat firebase harus benar-benar mendukung symlink

@michelepatrassi terinspirasi oleh apa yang Anda ingatkan saya, saya membuat perpustakaan firelink untuk mengelola kasus ini. Menggunakan internal rsync untuk menyalin file rekursif.

https://github.com/rxdi/firelink

npm i -g @rxdi/firelink

Penggunaan dasar
Dengan asumsi Anda memiliki pendekatan monorepo dan paket Anda berada 2 tingkat di bawah direktori saat ini di mana package.json berada.

package.json

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

Menjalankan firelink itu akan menyalin paket yang terkait dengan folder kemudian akan memetakan paket yang ada dengan modul lokal menginstal "@graphql/database": "file:./.packages/database", kemudian akan menjalankan perintah firebase dan akan meneruskan sisa argumen dari firelink perintah
Pada dasarnya firelink adalah pengganti firebase CLI karena ia memunculkan firebase di akhir ketika menyelesaikan pekerjaannya menyalin packages dan memodifikasi package.json !

Salam!

Kami baru saja digigit oleh ini, saya pikir monorepos akan menjadi standar dan ini harus didukung secara default.

Teman-teman, solusi sederhana untuk masalah ini adalah menggunakan webpack untuk menggabungkan fungsi cloud Anda dan menyebarkan dari direktori yang dibundel. Terlampir di sini adalah file webpack dasar yang saya gunakan. Selama pembuatan, ini akan mengemas semua kode fungsi, termasuk dependensi yang diselesaikan dalam mono-repo ke folder tingkat atas (dalam hal ini webpack/cloud-functions , bisa berupa apa pun yang Anda konfigurasikan)

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'
  }
};

Dan akhirnya di file firebase.json , lihat folder ini untuk penerapan.

{
  "functions": {
    "source": "webpack/cloud-functions"
  }
}

Ingatlah untuk memiliki file package.json di folder webpack/cloud-functions juga.

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

Ini diuji dan bekerja. Saya menggunakan google cloud build. Minta info lebih lanjut jika diperlukan.

Terima kasih,

@sowdri Terima kasih telah berbagi! Apakah Anda memicu build webpack dari langkah firebase.json functions.predeploy , atau apakah Anda memicunya dari skrip cloud build sebelum memanggil firebase deploy?

@0x80 Saya sedang membangunnya di langkah cloud build . Jadi menurut firebase cli itu hanya satu set fungsi yang dibangun dengan JS

@sowdri Terima kasih untuk contohnya. Kami akhirnya menggunakan pendekatan yang sama dalam proyek sebelumnya untuk AWS Lambdas / Tanpa Server: lebih mudah mengunggah bundel (Webpack) daripada memaksa alat untuk bekerja dengan yarn monorepo.

Saya juga terjebak dengan ini .... semuanya bekerja dengan baik (bahkan emulator firebase) sampai saya mencoba untuk menyebarkan fungsi (aplikasi web membangun reaksi menyebarkan OK). :( Semoga tim firebase dapat segera menambahkan dukungan untuk monorepos.

Saya menggunakan babel untuk paket lain di monorepo saya, jadi saya lebih memilih untuk tetap menggunakan itu. Jika tidak ada yang lain, saya dapat mencoba webpack ... yang sepertinya berfungsi untuk beberapa orang.

EDIT: Saya memecahkan ini dengan menggunakan registri paket GitHub. Jadi saya menerbitkan semua paket saya di sana dan kemudian untuk server travis dan functions saya harus mengatur registri dan memberikan token untuk otentikasi (dilakukan melalui .npmrc ). ...sepertinya solusi yang elegan. Saya mendapat ide untuk pendekatan ini di sini: https://medium.com/gdgeurope/how-to-use-firebase-cloud-functions-and-yarn-workspaces-24ca35e941eb

Ya, digigit oleh ini juga. Semuanya bekerja dengan sempurna di firebase serve --only functions tetapi ketika digunakan, tidak dapat menemukan modul.

Saya akhirnya membuat skrip kecil untuk membuat paket untuk saya. Meskipun ini mencerminkan hal-hal khusus dari lingkungan saya, seperti menggunakan modul dan nama paket saya yang cocok dengan nama direktori saya, saya harap ini berguna untuk orang lain.

```impor fs dari "fs";
impor child_process dari "child_process";

const internalPackagesFull = Peta baru();

// Temukan semua deps untuk paket
const getDepsForPackage = (nama paket) => {
const packageDir = packageName.split("/")[1]; // INI MUNGKIN PERLU BERUBAH UNTUK ANDA
const packageSpecFileName = ../${packageDir}/package.json ;
const packageSpecFile = fs.readFileSync(packageSpecFileName);
const packageSpec = JSON.parse(packageSpecFile);
const packageInternalDeps = Object.keys(
packageSpec.dependencies
).filter((kunci) => key.includes("turing")); // INI PERLU BERUBAH UNTUK ANDA

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

internalPackagesFull.set(namapaket, {
paketSpecFileName,
paketSpesifikasi,
paketDir,
paketInternalDeps,
paketTgzNama,
});

const packageToProcess = packageInternalDeps.filter(
(internalDepName) => !internalPackagesFull.has(internalDepName)
);

packageToProcess.forEach((internalPackageName) =>
getDepsForPackage(internalPackageName)
);
};

const packageName = JSON.parse(fs.readFileSync("./package.json")).name;
child_process.execSync( cp ./package.json ./package.json.org );
getDepsForPackage(namapaket);

// tulis paket yang diperbarui - gunakan js umum dan referensi adalah file tgz lokal
[...internalPackagesFull.values()].forEach((internalDep) => {
const { packageSpec, packageSpecFileName, packageInternalDeps } = internalDep;

// ubah jenis paket
packageSpec.type = "commonjs"; // INI MUNGKIN PERLU BERUBAH UNTUK ANDA

// tentukan lokasi dep untuk menjadi file zip yang dikemas
packageInternalDeps.forEach((internalDepOfPackage) => {
const { packageTgzName } = internalPackagesFull.get(internalDepOfPackage);
packageSpec.dependencies[internalDepOfPackage] = ./${packageTgzName} ;
});

fs.writeFileSync(
paketSpecFileName,
JSON.stringify(packageSpec, null, "")
);
});

// jalankan pembuatan dan pengepakan benang
[...internalPackagesFull.values()].forEach((internalDep) => {
mencoba {
console.log( Buliding ${internalDep.packageDir} );
child_process.execSync("pembuatan benang", {
cwd: ../${internalDep.packageDir} ,
});
console.log( Packaging ${internalDep.packageDir} );
child_process.execSync("paket benang", {
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: ".",
    }
  );
}

} tangkap (e) {
console.log(e);
}
});

// kembali ke struktur paket standar
[...internalPackagesFull.values()]
.filter((internalDep) => packageName !== internalDep.packageSpec.name)
.forEach((internalDep) => {
konstan {
paketSpesifikasi,
paketSpecFileName,
paketInternalDeps,
} = 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, "  ")
);

});
```

Saya menggunakan solusi yang disediakan oleh @sowdri (terima kasih untuk itu!), Dengan sedikit tweak sehingga saya dapat dengan bebas menghapus dan membuat ulang seluruh direktori dist/ , termasuk package.json sekunder :

const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');

module.exports = {
  ...,
  plugins: [
    new CopyPlugin({
      patterns: [{ from: 'package.dist.json', to: 'package.json' }],
    }),
  ],
};

Dan kemudian saya menyimpan package.dist.json di root paket:

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

Dimungkinkan untuk menghapus dependensi dari file ini dan mengandalkan Webpack untuk menggabungkannya juga (menghapus kebutuhan untuk menjaga dependensi ini tetap sinkron dengan package.json ), tetapi saya belum mencoba.

Saya menggunakan repositori tunggal dengan skrip untuk menyalin .firebaserc & firebase.json untuk semua direktori yang relevan atau proyek firebase menggunakan paket npm

Saya membuat package.json dari package.json asli untuk penerapan fungsi.
image

ini skrip 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);
})();

untuk penerapan, buka ./out/[project-name]/firebase deploy --only=functions atau tulis skrip untuk itu juga.

Saya mengalami beberapa peringatan Webpack seperti ini:

PERINGATAN di /Users/me/Development/myproject/node_modules/firebase-functions/lib/config.js 61:23-42
Ketergantungan kritis: permintaan ketergantungan adalah ekspresi

Apakah Anda menemukan cara untuk menyelesaikannya, atau apakah Anda mengabaikan/menekannya?

Saya berhasil membuat semuanya berfungsi tanpa peringatan Saya berakhir dengan konfigurasi di bawah ini. Terutama menggunakan pola regex untuk eksternal membuat perbedaan karena jika Anda hanya memiliki "firebase-functions" di eksternal Anda, impor apa pun yang Anda buat dari submodule tidak akan cocok dan perpustakaan masih disertakan dalam bundel Anda.

Sebagai akibat dari masalah bundling, saya juga mengalami beberapa kesalahan @grpc samar saat menerapkan. Saya lupa menyimpannya untuk referensi.

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" }],
    }),
  ],
};

Ternyata tidak perlu package.dist.json terpisah. Hal yang menyebalkan dari memiliki file ini tentu saja Anda harus memperbaruinya secara manual setiap kali Anda memperbarui salah satu dependensi yang terdaftar di sana. Jadi sangat mudah untuk melupakannya.

Alih-alih, pindahkan semua paket yang _tidak__ Anda daftarkan di package.dist.json Anda ke daftar devDependencies, dan cukup gunakan file itu di plugin webpack copy. Sekarang Anda hanya memiliki satu package.json untuk ditangani

Juga, saya tidak ingin versi nodejs lokal saya harus sama dengan fungsi yang digunakan versi node. Saya menemukan bahwa Anda sekarang dapat menentukan functions.runtime dalam file firebase.json. Jadi, keluarkan bidang engines dari package.json dan sebagai gantinya setel functions.runtime ke "10" atau "12" di konfigurasi firebase Anda.

Ini adalah apa yang terlihat seperti bagi saya:

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

Bagaimana Anda berurusan dengan peta sumber? Jika saya menggabungkan fungsi saya dengan webpack menggunakan devtool: "inline-source-map" itu tidak diambil dalam pelaporan kesalahan stackdriver. @sowdri

Saya mengalami hal yang sama pada proyek saya dan ini sangat mengecewakan karena saya tidak ingin melalui penerbitan setiap paket untuk proyek sampingan. Itu menjengkelkan menjaga dengan beberapa file package.json atau harus membangun di luar paket. Ternyata jika Anda menyertakan deps sebagai opsional, Lerna akan tetap mengambilnya dan Firebase tidak akan mengeluh saat diunggah.

Konfigurasi di bawah ini akan memberi Anda dukungan dep yang disinkronkan dengan satu 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
    }
  }
}

Saya menggunakan ruang kerja benang, tetapi saya juga tidak perlu menyebutkan nama paket lokal saya di file package.json lainnya. Saya berhasil menerapkan ke Firebase dan Vercel tanpa itu.

Saya tidak yakin apa yang membuatnya bekerja. Cukup miliki konfigurasi standar ini di package.json tingkat atas saya:

"workspaces": {
    "packages": [
      "packages/*"
    ]
  },

Saya tidak keberatan memiliki package.json di setiap folder /packages/*, karena menjalankan yarn upgrade-interactive hanya akan menangani semuanya sekaligus. Dalam beberapa paket saya merasa berguna untuk dapat menambahkan skrip khusus untuk ruang lingkup itu.

---- edit----

Saya lupa menyebutkan saya menggunakan TypeScript dengan referensi proyek. Itu mungkin ada hubungannya dengan itu. Untuk Vercel saya menggunakan modul-transpile berikutnya untuk memasukkan kode yang saya bagikan ke dalam bundel.

Saya menggunakan pengaturan serupa ke @0x80 dan @sowdri untuk membuat ini berfungsi, tetapi alih-alih memindahkan dependensi lokal saya ke devDependencies (yang sebenarnya tidak berfungsi untuk saya, saya pikir saya melewatkan satu langkah) dan menggunakan copy-webpack-plugin , saya menggunakan generate-package-json-webpack-plugin untuk membangun package.json saya di folder dist. Ini membangun daftar ketergantungan saya dari apa yang sebenarnya dibutuhkan oleh kode yang dihasilkan, jadi jika itu dibundel atau ketergantungan dev, itu tidak termasuk dalam package.json yang dihasilkan.

Saya juga telah mengatur eksternal saya menggunakan webpack-node-externals untuk membuat semuanya menjadi eksternal kecuali paket monorepo symlink saya yang saya gunakan regex untuk mencocokkan awalan nama proyek. Saya juga telah menambahkan ekspresi regex untuk paket firebase @0x80 yang diposting sebagai eksternal tambahan.

Ini adalah konfigurasi saya

/* 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)]
};

Manfaat lain tentang menggunakan webpack untuk membundel kode adalah saya akhirnya bisa menggunakan alias modul :)

Apakah halaman ini membantu?
0 / 5 - 0 peringkat