Ortak sınıflar için paylaşılan bir düğüm modülü kullanma


15

Hedef

Bu yapıya sahip bir projem var:

  • iyonik Uygulama
  • Firebase fonksiyonları
  • paylaşılan

Amaç sharedmodüldeki ortak arayüzleri ve sınıfları tanımlamaktır .

Kısıtlamalar

Yerel olarak kullanmak için kodumu npm'e yüklemek istemiyorum ve kodu hiç yüklemeyi planlamıyorum. % 100 çevrimdışı çalışmalıdır.

Geliştirme sürecinin çevrimdışı çalışması gerekirken, ionic-appve firebase-functionsmodülleri ateş tabanına (barındırma ve işlevler) dağıtılacaktır. Bu nedenle, sharedmodülün kodu orada mevcut olmalıdır.

Şimdiye kadar denediklerim

  • Daktiloda Proje Referanslarını kullanmayı denedim , ancak çalışmaya yakın bulmadım
  • Bu sorunun ikinci cevabında olduğu gibi bir npm modülü olarak kurarak denedim
    • İlk başta iyi çalışıyor gibi görünüyor, ancak derleme sırasında çalışırken böyle bir hata alıyorum firebase deploy:
Function failed on loading user code. Error message: Code in file lib/index.js can't be loaded.
Did you list all required modules in the package.json dependencies?
Detailed stack trace: Error: Cannot find module 'shared'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._load (module.js:475:25)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/srv/lib/index.js:5:18)

Soru

Typcripts config veya NPM'yi kullanarak paylaşılan bir modül oluşturmak için bir çözümünüz var mı?

Lütfen bunu bir kopya olarak işaretlemeyin → StackOverflow üzerinde bulduğum herhangi bir çözümü denedim.

İlave bilgi

Paylaşım için yapılandırma:

// package.json
{
  "name": "shared",
  "version": "1.0.0",
  "description": "",
  "main": "dist/src/index.js",
  "types": "dist/src/index.d.ts",
  "files": [
    "dist/src/**/*"
  ],
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "publishConfig": {
    "access": "private"
  }
}

// tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "rootDir": ".",
    "sourceRoot": "src",
    "outDir": "dist",
    "sourceMap": true,
    "declaration": true,
    "target": "es2017"
  }
}

İşlevler için yapılandırma:

// package.json
{
  "name": "functions",
  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "8"
  },
  "main": "lib/index.js",
  "dependencies": {
    "firebase-admin": "^8.0.0",
    "firebase-functions": "^3.1.0",
    "shared": "file:../../shared"
  },
  "devDependencies": {
    "@types/braintree": "^2.20.0",
    "tslint": "^5.12.0",
    "typescript": "^3.2.2"
  },
  "private": true
}


// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./",
    "module": "commonjs",
    "noImplicitReturns": true,
    "noUnusedLocals": false,
    "rootDir": "src",
    "outDir": "lib",
    "sourceMap": true,
    "strict": true,
    "target": "es2017"
  }
}

Mevcut dikkat

Tüm modülleri (index.js olmadan) diğer modüllere kopyalayan paylaşılan modüle bir npm komut dosyası ekledim. Bu sorun, SCM içine yinelenen kod kontrol ve her değişikliği bu komutu çalıştırmak gerekir. Ayrıca, IDE sadece farklı dosyalar gibi davranır.

Yanıtlar:


4

Önsöz: Typescript derlemesinin nasıl çalıştığı ve package.jsonböyle bir modülde nasıl tanımlanması gerektiği konusunda fazla bilgim yok . Bu çözüm, çalışmasına rağmen, eldeki görevi başarmanın kaba bir yolu olarak düşünülebilir.

Aşağıdaki dizin yapısını varsayarsak:

project/
  ionic-app/
    package.json
  functions/
    src/
      index.ts
    lib/
      index.js
    package.json
  shared/
    src/
      shared.ts
    lib/
      shared.js
    package.json

Bir Firebase hizmetini dağıtırken, ön dağıtım ve dağıtım sonrası kancalara komutlar ekleyebilirsiniz . Bu firebase.jsonözellikler predeployve postdeployistenen hizmet üzerinden yapılır . Bu özellikler, kodunuzu dağıtmadan önce ve sonra çalıştırılacak bir dizi sıralı komut içerir. Ayrıca, bu komutlar ortam değişkenleri RESOURCE_DIR(veya dizin yolu ./functionsveya ./ionic-apphangisi varsa) ve PROJECT_DIR(dizin yolu içeren firebase.json) ile çağrılır .

İçerideki predeploydiziyi kullanarak, paylaşılan kitaplığın kodunu Cloud Functions örneğine dağıtılan klasöre kopyalayabiliriz. Bunu yaparak, bir alt klasörde bulunan bir kütüphane sanki sadece paylaşılan kod içerebilir veya kullandığınız 's adını eşleyebilir typescript yolunun eşleme içinde (eğer kullanabilmesi için adlandırılmış modülüne ).functionsfirebase.jsontsconfig.jsonimport { hiThere } from 'shared';

predeployKanca tanımı (küresel kullanımları yükleme shx, Windows uyumluluğu için):

// firebase.json
{
  "functions": {
    "predeploy": [
      "shx rm -rf \"$RESOURCE_DIR/src/shared\"", // delete existing files
      "shx cp -R \"$PROJECT_DIR/shared/.\" \"$RESOURCE_DIR/src/shared\"", // copy latest version
      "npm --prefix \"$RESOURCE_DIR\" run lint", // lint & compile
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ]
  },
  "hosting": {
    "public": "ionic-app",
    ...
  }
}

Kopyalanan kütüphanenin typescript kaynağını, typescript derleyici config işlevlerine bağlama:

// functions/tsconfig.json
{
  "compilerOptions": {
    ...,
    "baseUrl": "./src",
    "paths": {
      "shared": ["shared/src"]
    }
  },
  "include": [
    "src"
  ],
  ...
}

"Paylaşılan" modül adını kopyalanan kitaplığın paket klasörüyle ilişkilendirme.

// functions/package.json
{
  "name": "functions",
  "scripts": {
    ...
  },
  "engines": {
    "node": "8"
  },
  "main": "lib/index.js",
  "dependencies": {
    "firebase-admin": "^8.6.0",
    "firebase-functions": "^3.3.0",
    "shared": "file:./src/shared",
    ...
  },
  "devDependencies": {
    "tslint": "^5.12.0",
    "typescript": "^3.2.2",
    "firebase-functions-test": "^0.1.6"
  },
  "private": true
}

Barındırma klasörü için de aynı yaklaşım kullanılabilir.


Umarım bu, bu kancalardan yararlanan daha temiz bir çözüm bulması için Typcript derlemesine daha aşina olan birine ilham verir.


3

Sen denemek isteyebilirsiniz Lerna , JavaScript (ve typescript) çoklu paketleri ile projeleri yönetmek için bir araç.

Kurmak

Projenizin aşağıdaki dizin yapısına sahip olduğunu varsayarsak:

packages
  ionic-app
    package.json
  firebase-functions
    package.json
  shared
    package.json

Yayınlamak istemediğiniz tüm modüllerde ve modülünüzdeki girişte doğru erişim düzeyini ( privateve config/accessanahtarları) belirttiğinizden emin olun :typingsshared

Paylaşılan:

{
  "name": "shared",
  "version": "1.0.0",
  "private": true,
  "config": {
    "access": "private"
  },
  "main": "lib/index.js",
  "typings": "lib/index.d.ts",
  "scripts": {
    "compile": "tsc --project tsconfig.json"
  }
}

İyonik-app:

{
  "name": "ionic-app",
  "version": "1.0.0",
  "private": true,
  "config": {
    "access": "private"
  },
  "main": "lib/index.js",
  "scripts": {
    "compile": "tsc --project tsconfig.json"
  },
  "dependencies": {
    "shared": "1.0.0"
  }
}

Yukarıdaki değişiklikler uygulandığında, birim test çerçeveniz, tslint vb. Gibi tüm proje modüllerinizin erişmesini istediğiniz package.jsonherhangi birini belirtebileceğiniz bir kök düzeyi oluşturabilirsiniz devDependencies.

packages
  ionic-app
    package.json
  firebase-functions
    package.json
  shared
    package.json
package.json         // root-level, same as the `packages` dir

Bu kök düzeyi ayrıca package.json, projenizin modüllerinde (lerna aracılığıyla) karşılık gelen komut dosyalarını çağıracak npm komut dosyalarını tanımlamak için de kullanabilirsiniz :

{
  "name": "my-project",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "compile": "lerna run compile --stream",
    "postinstall": "lerna bootstrap",
  },
  "devDependencies": {
    "lerna": "^3.18.4",
    "tslint": "^5.20.1",
    "typescript": "^3.7.2"
  },
}

Bu durumda, lerna config dosyasını kök dizininize ekleyin:

packages
  ionic-app
    package.json
  firebase-functions
    package.json
  shared
    package.json
package.json
lerna.json

aşağıdaki içeriklerle:

{
  "lerna": "3.18.4",
  "loglevel": "info",
  "packages": [
    "packages/*"
  ],
  "version": "1.0.0"
}

Şimdi npm installkök dizinde çalıştırdığınızda , kök postinstallseviyenizde tanımlanan komut dosyası package.jsonçalıştırılacaktır lerna bootstrap.

Ne lerna bootstrapyapar bu senin sembolik bir link olacaktır sharedmodülü ionic-app/node_modules/sharedve firebase-functions/node_modules/sharedböylece bu iki modülden noktadan, sharedtıpkı diğer npm modülü gibi görünüyor.

Derleme

Tabii ki, modülleri işaretlemek yeterli değildir, çünkü bunları yine de TypeScript'ten JavaScript'e derlemeniz gerekir.

Kök seviyesi package.json compilebetiği burada devreye girer.

Eğer çalıştırdığınızda npm run compileproje kök, npm çağıracağı lerna run compile --streamve lerna run compile --streamdenilen komut dosyasını çağırır compilesenin modüllerin her package.jsondosyanın.

Modüllerinizin her birinin artık kendi compilekomut dosyası olduğundan, tsonfig.jsonmodül başına bir dosyaya sahip olmanız gerekir . Çoğaltmayı sevmiyorsanız, kök düzeyinde tsconfig veya kök düzeyinden miras kalan kök düzeyinde tsconfig ve modül düzeyinde tsconfig dosyalarının bir birleşimi ile kurtulabilirsiniz.

Bu kurulumun gerçek dünyadaki bir projede nasıl çalıştığını görmek istiyorsanız, Serenity / JS'ye oldukça kapsamlı bir şekilde kullandığım yere bakın .

yayılma

Sahip güzel yanı sharedaltında sembolik olarak modül node_modulesaltında firebase-functionsve ionic-app, ve devDepedenciesaltında node_modulesproje kökü altında (bunu tüketici modülü hiçbir yerinde dağıtmak için gerekiyorsa olmasıdır ionic-appörneğin) aşağıdaki özelliklerinden hepsini birlikte fermuarını sadece olabilir node_modulesdeğil dert dağıtımdan önce geliştirici bağımlılıklarını kaldırmak zorunda.

Bu yardımcı olur umarım!

Ocak


Intresting! Kesinlikle kontrol ve bu uygun uygun olup olmadığına bakın.
MauriceNino

2

Kodunuzu yönetmek için git kullanıyorsanız başka bir olası çözüm kullanmaktır git submodule. git submoduleBunu kullanarak projenize başka bir git deposu ekleyebilirsiniz.

Kullanım durumunuza uygulanır:

  1. Paylaşılan git git deponuzun geçerli sürümünü aktarın
  2. Kullanım git submodule add <shared-git-repository-link>ana proje (ler) içine paylaşılan deposunu bağlamaya.

Dokümanlara bir bağlantı: https://git-scm.com/docs/git-submodule


Aslında kötü bir fikir değil, ancak yerel kalkınma ve test temelde bu yaklaşımla gitti.
MauriceNino

0

Sorununuzu doğru anlarsam, çözüm tek bir cevaptan daha karmaşıktır ve kısmen tercihinize bağlıdır.

Yaklaşım 1: Yerel kopyalar

Gulp kullanabilirsiniz önce açıkladığınız çalışma çözümünü otomatikleştirmek için , ancak IMO, başka bir geliştiricinin geldiği bir noktada karmaşıklığı korumak ve karmaşıklığı önemli ölçüde arttırır.

Yaklaşım 2: Monorepo

Üç klasörü de içeren tek bir havuz oluşturabilir ve bunları tek bir proje gibi davranacak şekilde bağlayabilirsiniz. Yukarıda yanıtlandığı gibi, Lerna'yı kullanabilirsiniz . Biraz yapılandırma gerektirir, ancak bir kez yapıldığında, bu klasörler tek bir proje gibi davranacaktır.

Yaklaşım 3: Bileşenler

Bu klasörlerin her birine bağımsız bir bileşen gibi davranın. Bir göz atın Bit . Klasörleri daha büyük bir projenin daha küçük bölümleri olarak ayarlamanıza olanak tanır ve bu bileşenleri yalnızca size dahil edecek özel bir hesap oluşturabilirsiniz. İlk kurulduktan sonra, ayrı klasörlere güncellemeler bile uygulamanıza izin verir ve bunları kullanan üst klasör otomatik olarak güncellemeleri alır.

Yaklaşım 4: Paketler

Özellikle npm kullanmak istemediğinizi söylediniz, ancak paylaşmak istiyorum, çünkü şu anda aşağıda açıklandığı gibi bir kurulumla çalışıyorum ve benim için mükemmel bir iş yapıyor:

  1. Her klasör için bir paket oluşturmak için npmveya kullanın yarn(her ikisi için de kapsamlı paketler oluşturabilirsiniz, böylece kod sadece sizin için endişeliyse kullanılabilir olacaktır).
  2. Üst klasörde (bu klasörlerin tümünü kullanan), oluşturulan paketler bağımlılık olarak bağlanır.
  3. Tüm paketleri paketlemek için webpack'i kullanıyorum ve daktilo yolları ile birlikte webpack yol takma adlarını kullanıyorum.

Bir cazibe gibi çalışır ve paketler yerel gelişim için işaretlendiğinde tamamen çevrimdışı ve benim deneyimime göre çalışır - her klasör ayrı ayrı ölçeklenebilir ve bakımı çok kolaydır.

Not

Oldukça büyük oldukları ve her paket için ayrı tsconfig'ler oluşturduğumdan, 'child' paketleri zaten benim durumumda önceden derlenmiş, ancak güzel olan şey, kolayca değiştirebilmeniz. Geçmişte modülde derlenmiş yazı ve derlenmiş dosyalar ve ayrıca ham js dosyaları kullandım, bu yüzden her şey çok, çok yönlü.

Bu yardımcı olur umarım

***** GÜNCELLEME **** 4. noktaya devam etmek için: Özür dilerim, kötüyüm. Belki yanlış anladım çünkü bildiğim kadarıyla, yüklenmemişse bir modülün bağlantısını kaldıramazsınız. Yine de, işte burada:

  1. Ayrı bir npm modülünüz var, firebase-functionsbunun için kullanalım . Tercihinize göre derlersiniz veya çiğ ts kullanırsınız.
  2. Üst projenize firebase-functionsbağımlılık olarak ekleyin .
  3. In tsconfig.json, eklenti"paths": {"firebase-functions: ['node_modules/firebase-functions']"}
  4. Web paketinde - resolve: {extensions: ['ts', 'js'], alias: 'firebase-functions': }

Bu şekilde, dışa aktarılan tüm işlevlerinizi firebase-functionsmodülden basitçe kullanarak referans alırsınız import { Something } from 'firebase-functions'. Webpack ve TypeScript onu düğüm modülleri klasörüne bağlayacaktır. Bu yapılandırmada, ana proje firebase-functionsmodülün TypeScript ya da vanilya javascript ile yazılmış olup olmadığını umursamaz .

Kurulduktan sonra, üretim için mükemmel bir şekilde çalışacaktır. Ardından, çevrimdışı bağlantı oluşturmak ve çalışmak için:

  1. firebase-functionsProjeye gidin ve yazın npm link. Makinenize yerel bir sembolik bağlantı oluşturur ve bağlantıyı package.json içinde ayarladığınız adı eşler.
  2. npm link firebase-functionsSymlink'i oluşturacak ve firebase işlevlerinin bağımlılığını oluşturduğunuz klasöre eşleyecek olan ana projeye ve yaz'a gidin.

Bence bir şeyi yanlış anladın. Asla npm kullanmak istemediğimi söylemedim. Aslında bu modüllerin üçü de düğüm modülleridir. Az önce dedim ki, modüllerimi npm'ye yüklemek istemiyorum. Bu 4. bölüm hakkında biraz daha ayrıntı verebilir misiniz - ilginç geliyor mu? belki bir kod örneği sağlayabilir?
MauriceNino

Yorum olarak uzun ve okunaksız olacağından başka bir cevap ekleyeceğim
Ivan Dzhurov

İlk cevabımı güncelledim, umarım daha net
Ivan Dzhurov

0

Yerel olarak kullanmak için kodumu npm'e yüklemek istemiyorum ve kodu hiç yüklemeyi planlamıyorum. % 100 çevrimdışı çalışmalıdır.

Tüm npm modülleri yerel olarak kurulur ve her zaman çevrimdışı çalışır, ancak insanların görebilmesi için paketlerinizi herkese açık olarak yayınlamak istemiyorsanız, özel npm kayıt defterini yükleyebilirsiniz.

ProGet, özel paketlerinizi barındırmak, erişmek ve yayınlamak için özel geliştirme / üretim ortamınızda kullanabileceğiniz pencereler için kullanılabilen NuGet / Npm Özel veri havuzu sunucusudur. Rağmen windows üzerinde ama linux üzerinde çeşitli alternatifler olduğundan eminim.

  1. Git Submodules kötü bir fikirdir, paketler gibi sürümlendirilmemiş kodu paylaşmak, eski modülleri değiştirmek ve taahhüt etmek gerçekten acı veren eski moda bir yoldur.
  2. Kaynak içe aktarma klasörü de kötü bir fikirdir, yine sürüm oluşturma sorunu vardır, çünkü birisi bağımlı depodaki bağımlı klasörü değiştirirse, tekrar izlemek kabustur.
  3. Paket ayırmayı taklit etmek için herhangi bir üçüncü taraf komutlu araç zaman kaybıdır, çünkü npm zaten paketleri yönetmek için çok çeşitli araçlar sağlar.

İşte derleme / dağıtım senaryomuz.

  1. .npmrcİçerdiği her özel paket vardır registry=https://private-npm-repository.
  2. Tüm özel paketlerimizi özel olarak barındırılan ProGet veri havuzumuzda yayınlıyoruz.
  3. Her özel paket ProGet'te bağımlı özel paketler içerir.
  4. Yapı sunucumuz ProGet'e bizim tarafımızdan belirlenen npm kimlik doğrulaması ile erişir. Ağımız dışındaki hiç kimse bu veri havuzuna erişemez.
  5. Yapı sunucumuz, bundled dependenciesiçindeki tüm paketleri içeren npm paketi oluşturur node_modulesve gerekli tüm paketler zaten paketlendiği için üretim sunucusunun NPM veya özel NPM paketlerine erişmesi gerekmez.

Özel npm deposu kullanmanın çeşitli avantajları vardır,

  1. Özel komut dosyasına gerek yok
  2. Düğüm buid / yayın boru hattına uyar
  3. Her özel npm paketi, özel git kaynak kontrolünüze doğrudan bağlantı içerecek, hata ayıklama ve gelecekteki hataları araştıracak
  4. Her paket salt okunur bir anlık görüntüdür, bu nedenle yayınlandıktan sonra değiştirilemez ve yeni özellikler oluştururken, bağımlı paketlerin eski sürümüne sahip mevcut kod tabanı etkilenmez.
  5. Bazı paketleri kolayca herkese açık hale getirebilir ve gelecekte başka bir depoya taşıyabilirsiniz
  6. Özel npm sağlayıcı yazılımınız değişirse, örneğin kodunuzu düğümün özel npm paketi kayıt defteri bulutuna taşımaya karar verirseniz, kodunuzda herhangi bir değişiklik yapmanız gerekmez.

Bu bir çözüm olabilir ama maalesef benim için değil. Zaman ayırdığınız için teşekkürler!
MauriceNino

Küçük bir düğüm sunucusu olarak kurulan bir yerel npm deposu da var, verdaccio.org
Akash Kava

-1

Aradığınız araç npm link. npm linkyerel bir npm paketine sembolik bağlantılar sağlar. Bu şekilde bir paketi bağlayabilir ve ana projenizde npm paket kütüphanesinde yayınlamadan kullanabilirsiniz.

Kullanım durumunuza uygulanır:

  1. Paketinizin npm linkiçinde kullanın shared. Bu, gelecekteki yüklemeler için simge bağlantısı hedefini ayarlar.
  2. Ana projenize / projelerinize gidin. Senin İçinde functionspaket ve kullanım npm link sharedpaylaşılan paketi bağlamak ve eklemek node_modulesdizine.

Dokümanlara bir bağlantı: https://docs.npmjs.com/cli/link.html


Bildiğim kadarıyla, npm bağlantısı sadece test içindir ve sonuçta ortaya çıkan kodu (örneğin işlevleriim) dağıtmak istiyorsanız çalışmaz.
MauriceNino

Anlıyorum, muhtemelen bu şartı sorunuza eklemelisiniz.
friedow

Soruda zaten bahsediliyor, ancak açıklığa kavuşacağım.
MauriceNino
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.