Flaskista Flask+Reactiin

  • Keskustelun aloittaja Keskustelun aloittaja Makis
  • Aloitettu Aloitettu
Voisiko joku vinkata, miten tuollaista etusivua kannattaisi lähteä kehittelemään? Alkaa olla käyttäjä-UI:lla kaikki olennaiset tehty (tilastosivu, muutoshistoria ja FAQ taitaa olla ainoat puuttuvat), joten kai tuohon etusivuun on seuraavaksi pureuduttuva.

Kannattaako tuo kuva ympätä normikuvana vai vai tausta-? Minulla oli joku sivu, joka laski kuvan parametrit niin että se näytti tuolta, mutta tietenkään en jostain syystä laittanut sivua talteen.

Muuten ajattelisin että tuo olisi ihan gridi, jossa tuo kuva vie leveydestä riippuen sopivan osan ruudusta, mutta tuo kyllä hajoaa kun mennään kännykkäleveyksiin. Silloin ei mahdu kuin vasemmanpuoleinen sisältö näkyviin tai tulee aivan liian kapea sarake. Mikä noissa on käytäntö, jätetäänkö koko kuva pois?
 
Saako muuten VSC:ssä jotenkin toimimaan outlineä Reactin koodin kanssa? Muilla kielillä toimii, mutta tsx-fileiden kohdalla ainakin näyttää vain tyhjää. Enkä löytänyt googlailulla mitään apuja.
 
Authorization-homma osoittautuikin yllättävän mutkikkaaksi. Vanhassa Flask-sovelluksessa framework hoiti käytänössä hommat, kunhan lisäsin haluttuihin routeihin @login_required-dekoraattorin.

JWT-tokenit näyttäisivät olevan paras ratkaisu ja muuten tämän koodailinkin mutta ongelmaksi tuli logout. Kun käytttää näitä cookieina, niin selain osaa hoitaa client-pään automaattisesti. Mutta invalidointi ei olekaan triviaalia. Kaikesta päätellen tähän on kaksi tapaa: joko luotetaan TTL:ään, eli cookie on sitten voimassa vaikka vuorokauden eikä mitään logoutia ole, tai sitten bäkkärissä on blacklist, johon token lisätään logoutissa.

Tavallaan ymmärrän blacklistin, mutta onkohan tuossa muuta kuin ideologiset syyt miksei hommaa voi tehdä sessio-pohjaisesti? Toisin sanoen tallennetaan ne voimassaolevat tokenit mieluummin kantaan. Blacklistihän kasvaa kasvamistaan, ellei listaa välillä tyhjennä. Whitelist taas pysyy koko ajan pienenä.

flask-jwt-extended -paketissa esimerkiksi on tuon blacklistin-tuki.
 
Palstalla on kyllä lukuisia kokeneempia web-devaajia, ite oon enemmän tämmönen backend- / jokapaikanhöylä, mutta kevyemmän harrastusprojektin tapauksessa minä varmaan vaan poistaisin tokenin clientista ja antaisin (järkevän mittaisen) TTL:n tehdä tehtävänsä palvelimella. Tota blacklistia ei tekis mieli lähteä implementoimaan.

Täältä vois saada kanssa jotain ajatuksia: What Are Refresh Tokens and How to Use Them Securely
 
Lukemani perusteella jos se tokeni on cookiessa niin clientti ei voi sitä poistaa. Toki jos välitän sen muuten niin sitten voin, mutta se tarkoittaa sitten sitä, että joudun clientissä käsittelemään tokenin itse. Cookiet hoitaa selain.
 
Joo, tarvis varmaan ekana kirkastaa se, haluaako autentikoinnin hoitaa tilattomasti, käyttää palvelinpuolen sessioita vai miten. Ratkaisut tokenin välitykseen yms. sen mukaan.

Minä oon tosiaan harrastanu kotona vaan hyvin kevyttä React / Node tai Python koodailua. Selaimessa token on laitettu vaan localstorageen ja logoutissa otettu sieltä veks. Palvelin voi asettaa tokenille ekspiroitumisajan.

Jos tarvis tehdä jotain professionaalimpaa, niin itellä vaihtuis bäkkäri Javaan ja Spring Securityyn. Sinne saa pultattua mukaan aika pitkälti sellaisen autentikaatioflown, mitä sattuu tarvitsemaan.
 
Jipppikaijee. Nyt tuo autentikointi hajosi syystä X. Tokeni kyllä välitetään clientille, mutta jostain syystä ilmeisesti client ei palauta oikeaa tokenia. Kai. Mistäpä pirusta tuonkaan tietää, kun serverin päässä en saa breikkaamaan mihinkään checkiin, palauttaa vaan 401.

Täytynee sitten alkaa käsin käsittelemään tuo tokeni ja unohtaa keksit.
 
Mitkähän apinat näitä komponentteja mahtaa tehdä?

React Routerissa oli sitten jostain syystä vaihdettu useHistory useNavigateksi v6:ssa. Nähdäkseni toiminta ei ei muuttunut mitenkään. Eli kaikki tuota käyttäneet softat meni rikki, ja netti on nyt täynnä ohjeita, jotka eivät enää päde. Saahan siinä ihmetellä kun edes maaliskuussa tehty ohje redirectistä ei enää toiminut.
 
Mitkähän apinat näitä komponentteja mahtaa tehdä?

React Routerissa oli sitten jostain syystä vaihdettu useHistory useNavigateksi v6:ssa. Nähdäkseni toiminta ei ei muuttunut mitenkään. Eli kaikki tuota käyttäneet softat meni rikki, ja netti on nyt täynnä ohjeita, jotka eivät enää päde. Saahan siinä ihmetellä kun edes maaliskuussa tehty ohje redirectistä ei enää toiminut.

Ainoa apina on se devaaja, joka päivittää paketin, jonka major-versio muuttuu, eikä tutustu muutoksiin. Tässä ohjeet:

 
Kyllä ne on yksiä v*tun apinoita, jotka rikkovat huvikseen rajapintoja. Vuosia tästä eteenpäin kun guuglaa tuohon liittyviä juttuja, tulee hitosti vääriä osumia. Noissa ohjeissa näköjään kun harvemmin vielä kerrotaan mihin versioon neuvot liittyvät.

Tässä on vielä se naurettavuus, että tuossa lähinnä pitää vaihtaa nimiä. Siis logiikka ei ole muuttunut tjsp, mikä oikeasti pakottaisi tähän. Olisi siis joko voitu jättää vanha toteutus useHistory():stä paikalleen deprecoituna tai sitten kirjoitettu vaan useHistory() uusiksi. Sama juttu tuon Switchin kanssa, aivan hyvin olisi voitu jättää Switch aliakseksi Routelle.

Olen kymmeniä jos en satoja rajapintoja nähnyt uran aikana ja tällaiset muutokset, joissa rikotaan taaksepäin yhteensopivuus vaikka ei ole oikesti pakko on merkki siitä, että koodarit ei paljon muista välitä. Joku Microsoft pystyi pitämään vanhat API:t taaksenpäinyhteensopivina jostain 3.1:sta Win8:iin ja sitten päättivät vetää homman uusiksi kymppiin. Joten kyllä tällaisen pienen komponentin kohdallakin pitäisi onnistua. Itselläkään ei ole tainnut tulla ikinä vastaan tilannetta, että joku rajapinta olisi ollut pakko rikkoa. Kyllä niihin on aina konstit löytyneet.
 
Ja muuten, miten nuo muutosdokumentit auttavat jos lähtee suoraan tekemään v6:lle?
 
Kyllä ne on yksiä v*tun apinoita, jotka rikkovat huvikseen rajapintoja.

Käsittämätön ylimielinen asenne. Lue ne dokumentaatiot:

We recommend waiting for the backwards compatibility package to be released before upgrading apps that have more than a few routes.

Yhä edelleen se apina on devaaja, joka päivittää lukematta dokumentaatiota ja release noteseja.
 
Ylimielisyyttä on nimenomaan rikkoa taaksepäin yhteensopivuus noin vain ja teettää käyttäjillä turhaa työtä.

Olen muuten tuon dokumentin lukenut joskus kuukausia sitten.

Mutta joo, ehkä minä olen sitten sitä porukkaa, jolla on ihan riittävästi tekemistä ilman että pitää keksiä tällaisia lisähommia muille koodaajille. Ehkä nuoremmilla koodareilla on aikaa tunkata jokaisen versiopäivityksen jälkeen jokaisen komponentin rikotut rajapinnat kohdalleen.
 
ehkä minä olen sitten sitä porukkaa, jolla on ihan riittävästi tekemistä ilman että pitää keksiä tällaisia lisähommia muille koodaajille

Ei tule mitään lisähommaa yhtään kenellekään kun et silmät sidottuna päivitä niitä riippuvuuksia :facepalm: Tee päivitys 5->6 vasta kun olet valmis lukemaan dokumentaation ja migraatio-ohjeet, kun tarvitset 6:n ominaisuuksia ja kun sulla on aikaa tehdä se migraatio. Jos nämä kaikki eivät täyty, niin pysyttele 5:ssä.
 
Viimeksi muokattu:
Eli siis sinulla _on_ projekteissa aikaa puuhailla kaikenlaista ylimääräistä, kuten päivitellä funktioiden nimiä? Jossain vaiheessa kun tahtoo olla vähän pakko tehdä päivityksiä. Tuollaiset muutokset lisäävät faktuaalisesti työmäärää.

Mikään ei estänyt jättämästä sitä vanhaa interfacea vaikka "deprecated"-leimalla tuonne.

Ja edelleen, kun etsin ratkaisua vaikka siihen, että miten tässä nyt redirektointi tehdään, niin hakukone ei todellakaan tarjoa hakutulosten kärjessä ohjeita migraation tekemiseen vaan lähinnä ohjeita miten homma tehdään v5:ssä. Mutta tietenkään nuo ohjeet yleensä kerro versiosta mitään, ja varsinkaan niitä ei koskaan jälkikäteen päivitetä, että tämä muuten ei enää päde.

Mutta tämä tästä. Jos joku on tosiaan sitä mieltä, että rajapintojen summittainen rikkominen on ok, niin siinä on niin iso railo minun käsitykseeni hyvistä ohjelmointikäytännöistä, että mitään yhteistä pohjaa on mahdoton löytää.
 
Mitä muuta tuo sitten on? Poistetaan laajasti käytetty ominaisuus. Mikä tuohon oli tässä vaiheessa syynä?

Ja sinun kykenemättömyytesi lukea, mitä kirjoitan on kyllä aika huikeaa kun puhun muustakin kuin päivittämisestä, mutta takerrut jatkuvasti siihen.
 
Jaahas, saahan sitä kuvitella, että hommat menisi jotenkin helposti. Muutin clientiä niin, että se lukee loginin vastausviestistä tokenit ja API-kutsuissa sitten lisää headeriin. Sain tuon toimimaan kun lisäsin flask_jwt_extended:n konffeihin, että etsii tokenia paitsi cookieista myös headerista.

No tietysti Postmanin testit sitten hajosivat, vaikka tuon komponentin speksien perusteella minkään ei olisi pitänyt muuttua. Ja nyt olen tätä tunkatessa ilmeisesti saanut rikottua jotain muutakin, koska vaikka olen palauttanut bäkkärin alkuperäiseen asentoon, niin silti Postman kiukuttelee. Vaikuttaisi vähän siltä, että nuo cookiet on nyt jotenkin sekaisin, mutta sitäpä sopiikin ihmetellä että miten. Mutta tuo tokeni, jonka luen näyttää erilaiselta. Ihan kuin jostain syystä Postman olisi alkanut automaattisesti purkamaan koodaus tai jostain syystä bäkkäri päätti olla enää tekemättä sitä. Postmanista kuitenkin deletoinut kaikki vanhat cookiet ja muuttujat.

Olisihan sitä itse sovellustakin voinut kehittää...
 
Autentikaatiohomma ratkesi sillä, että potkin keksipurkin nurin. Nyt autentikaatiotokeni menee headerissä sekä sovelluksen että Postmanin kanssa. Ja nimenomaan piti flask_jwt_extended konffata niin, että se ei etsi keksipurkista noita tokeneita.
 
Autentikaatiohomma ratkesi sillä, että potkin keksipurkin nurin. Nyt autentikaatiotokeni menee headerissä sekä sovelluksen että Postmanin kanssa. Ja nimenomaan piti flask_jwt_extended konffata niin, että se ei etsi keksipurkista noita tokeneita.

Olikos tää projekti githubissa tms?
 
On, mutta nuo muutokset menee vasta kun saan tuon homman valmiiksi. Koko autentikaatiohomma tuli ajankohtaiseksi kun aloin ensimmäisiä ylläpito-ominaisuuksia tekemään.

Mutta siis:
Bäkkärissä on koko nykyinen sivusto frontteineen, joten siellä on valtaosa sellaista, joka pitää jossain vaiheessa siivota pois. REST on tiedostoissa api.py, impl.py ja model.py sekä kunhan saan muutokset tuonne, api_jwt.py app-kansiossa. Fronttiinin on jo kaikenlaista refaktoroitavaa löytynyt, kunhan olisi aikaa.
 
Tulipas kummallinen ongelma. Kun tarjosin tiettyä tietorake

nnetta useFormArray:lle niin tuli virheilmoitus circular referecenstä. Googlailun perusteella import typen olisi pitänyt auttaa, mutta ei auta vaikka tungin tuon mielestäni jokaiseen paikkaan, jossa importoidaan pelkkä interface.

No, takaisin plan b:hen, eli joudun muuttamaan tuon tietotyypin simppelimmäksi ennen kuin käytän. Mutta vaikka miten TS:n speksejä tavaan niin en hoksaa, miten saisin tehtyä näiden kahden funktion sijasta yhden generaalin:

JavaScript:
const personToKeyValue = (arr: IPerson[]): KeyValuePair[] => {
    let retval: KeyValuePair[] = [];
    arr.map(item => retval.push({ id: item.id, value: item.name }));
    return retval;
}

const genreToKeyValue = (arr: IGenre[]): KeyValuePair[] => {
    let retval: KeyValuePair[] = [];
    arr.map(item => retval.push({ id: item.id, value: item.name }));
    return retval;
}
Ehkä jotenkin niin, että sekä IPerson että IGenre extends from joku perustyyppi?

Sellaisen jännän huomion tein kanssa, että tämän tyyppinen juttu ei onnistu:
Koodi:
const convToForm = (short: IShort): IShortForm => ({
    authors: {() => short.authors.map(author => {id: author.id, name: author.name})}
    })
Ei toimi, vaan pitää olla nimenomaan nimetty funktio (siis personToKeyValue).
 
Eikös se ihan näin toimisi:
JavaScript:
const toKeyValue = (items: (IPerson | IGenre)[]): KeyValuePair[] => items.map(i => ({ id: i.id, value: i.name }))
 
Joo, tässä tapauksessa tosiaan voisi tehdä noin, mutta ajattelin siis geneeristä funktiota. Jos en määrittele tyyppiä, niin kääntäjä marmattaa että items on any-tyyppiä, se ei siis osaa päätellä tyyppiä. Tuo on minusta vähän heikkoa suorittamista, koska pitäisihän sen minusta olla mahdollista.

Genericit vaativat joka tapauksessa näköjään opettelua. Ei ole omassa historiassa hirveästi tarvinnut, lähinnä C++:n templateja jonkun verran. Haskellissa homma toimii sitten ihan eri tavalla (enkä voi väittää että sitäkään osaisin), siinä oli esimerkiksi hyvin toimivat polymorfiset funktiot.
 
Joo, tässä tapauksessa tosiaan voisi tehdä noin, mutta ajattelin siis geneeristä funktiota. Jos en määrittele tyyppiä, niin kääntäjä marmattaa että items on any-tyyppiä, se ei siis osaa päätellä tyyppiä. Tuo on minusta vähän heikkoa suorittamista, koska pitäisihän sen minusta olla mahdollista.

Genericit vaativat joka tapauksessa näköjään opettelua. Ei ole omassa historiassa hirveästi tarvinnut, lähinnä C++:n templateja jonkun verran. Haskellissa homma toimii sitten ihan eri tavalla (enkä voi väittää että sitäkään osaisin), siinä oli esimerkiksi hyvin toimivat polymorfiset funktiot.

Tämän geneerisempää en saa aikaan. Mutta pitäisi toimia kaikilla tyypeillä, joissa on nuo kaksi määrättyä attribuuttia.
JavaScript:
// Generic Constraints for TypeScript: https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-constraints
interface KeyValueType {
    id: string;
    value: string;
}
// Enforce that objects will have a id and name attributes
interface HasIdAndName {
    id: string;
    name: string;
}
// Map from any type T that has attributes id and name into a object implementing KeyValueType
const extractKeyValueMappings = <T extends HasIdAndName>(xs:T[]): KeyValueType[] => xs.map(x => ({ id: x.id, value: x.name }));

// OK
console.log(extractKeyValueMappings([{ id: "me", name: "2", extra: "this does not matter" }]));

// ERROR
console.log(extractKeyValueMappings([{ id: "me", name: 2 }]));
//                                               ~~~~~
// Type 'number' is not assignable to type 'string'.ts(2322)

// ERROR
console.log(extractKeyValueMappings([{ id: "me", value: "2" }]));
//                                               ~~~~~~~~~~
// Type '{ id: string; value: string; }' is not assignable to type 'HasIdAndName'.
// Object literal may only specify known properties, and 'value' does not exist
// in type 'HasIdAndName'.ts(2322)

// ERROR
console.log(extractKeyValueMappings([{ id: "me" }]));
//                                   ~~~~~~~~~~~~
// Property 'name' is missing in type '{ id: string; }' but required in type 'HasIdAndName'.ts(2741)
 
Ah, eli tuota T extends-juttua tarkoitin, mutta olin tekemässä hommaa jotenkin liian monimutkaisesti.
 
No niin, nyt yritin kontittaa tuota fronttia, mutta ei vaan nyt oikein lähde. Tällaiseen muotoon olen Dockerfilen vääntänyt:
Koodi:
FROM node:latest

WORKDIR /app

ENV PATH /app/node_modules/.bin:$PATH

COPY package.json .

RUN mkdir -p ./node_modules
RUN chown -R node:node ./node_modules
RUN npm config set unsafe-perm true
RUN npm install --force
RUN npm install -g react-scripts

COPY . .

CMD ["npm", "start"]
Mutta aina vaan tulee
Koodi:
/usr/local/lib/node_modules/react-scripts/node_modules/resolve/lib/sync.js:34
        throw e;
        ^

Error: EACCES: permission denied, stat '/root/.node_modules'
    at Object.statSync (node:fs:1590:3)
    at isDirectory (/usr/local/lib/node_modules/react-scripts/node_modules/resolve/lib/sync.js:31:23)
    at loadNodeModulesSync (/usr/local/lib/node_modules/react-scripts/node_modules/resolve/lib/sync.js:200:17)
    at Function.resolveSync [as sync] (/usr/local/lib/node_modules/react-scripts/node_modules/resolve/lib/sync.js:107:17)
    at getModules (/usr/local/lib/node_modules/react-scripts/config/modules.js:119:32)
    at Object.<anonymous> (/usr/local/lib/node_modules/react-scripts/config/modules.js:142:18)
    at Module._compile (node:internal/modules/cjs/loader:1159:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Module._load (node:internal/modules/cjs/loader:878:12) {
  errno: -13,
  syscall: 'stat',
  code: 'EACCES',
  path: '/root/.node_modules'
}

Tuossa Dockerfilessä on siis useampi rivi lisätty hakujen perusteella (mkdir, chown, set unsafe-perm ja install react-scripts), mutta mikään ei tunnu auttavan. .dockerignoressa on node_modules ja **/node_modules myös.

Mutta sitten heräsi sellainen kysymys, että miten kontitettua softaa kehitetään? Näyttää ainakin tästä Dockerista (v 20.10.21) puuttuvan --keep-git-dir, joten muutosten vieminen toiseen suuntaan on vähän kinkkistä.
 
En liene paras ihminen sanomaan tuon npm:n konffimisesta, mutta virhehän lienee aika selvä, eli tiedosto- / hakemisto-oikeuksista kyse.

Mutta sitten heräsi sellainen kysymys, että miten kontitettua softaa kehitetään? Näyttää ainakin tästä Dockerista (v 20.10.21) puuttuvan --keep-git-dir, joten muutosten vieminen toiseen suuntaan on vähän kinkkistä.
En ihan ymmärrä tuota loppua ja mitä on muutosten vieminen toiseen suuntaan, mutta kontitettua softaa kehitetään muilta osin ihan niin kuin muutakin softaa, jota ei julkaista konttina, mutta julkaisuprosessiin vaan kuuluu itse sovelluksen buildauksen lisäksi uuden kontti-imagen buildaus ja pusku repositorioon, josta se saadaan haetuksi ajoympäristöön.

Pikainen huomio vielä tuosta Dockerfilestä, että tyypillisesti kontti-imageihin kannattaa olla viittaamatta "latest" tagilla, koska nyt sulla muuttuu vähän niin kuin hallitsemattomasti tuo oman imagen buildaus, kun pohjaimagen "latest" päivittyy. Sen sijaan kannattaa käyttää spesifejä tägejä, tyyliin vaikka nyt tuossa node-imagen tapauksessa "node:16-buster-slim" tai mikä versio nyt tarviikaan olla.
 
Siis mietin sitä, että jos haluan kehittää sitä kontissa olevaa softaa (ettei tarvitse asentaa kirjastoja koko koneeseen), niin miten se onnistuu? Vai tehdäänkö niin?
 
Pitäähän sulla yleensä olla softan tarvitsemat riippuvuudet lokaalistikin, että näet, että sovellus ylipäätään buildaantuu, ennen kuin sitä voi lähteä laittamaan konttiin. Ja nuo softan tarvitsemat riippuvuudet ei oo Dockerfilen asioita, vaan ne hallitaan sen itse sovelluksen tasolla ja yleensä jollain omalla build-työkalullaan (Noden tai Reactin kanssa se lienee tuo npm ja esim. Javan kanssa Maven tai Gradle).

Sit jos jonkun sovelluksen buildaaminen (tai ajaminen) tarvii semmoisia työkaluja, joita ei käytetyssä pohjaimagessa ole, niin ne tarvii asentaa erikseen Dockerfilessä ennen käyttöä. Kannattaa varmaan kattoa vähän jotain tutoriaalia konteista ja Dockerfilen rakentamisesta.
 
Viimeksi muokattu:
Global react-scripts tarpeellinen, oikeudet? Dockerfile ja compose ladataan gittiin normaalisti, josta muut saa alustasta riippumatta saman kehitysympäristön/palvelimen.
 
Pitäähän sulla yleensä olla softan tarvitsemat riippuvuudet lokaalistikin, että näet, että sovellus ylipäätään buildaantuu, ennen kuin sitä voi lähteä laittamaan konttiin. Ja nuo softan tarvitsemat riippuvuudet ei oo Dockerfilen asioita, vaan ne hallitaan sen itse sovelluksen tasolla ja yleensä jollain omalla build-työkalullaan (Noden tai Reactin kanssa se lienee tuo npm ja esim. Javan kanssa Maven tai Gradle).

Sit jos jonkun sovelluksen buildaaminen (tai ajaminen) tarvii semmoisia työkaluja, joita ei käytetyssä pohjaimagessa ole, niin ne tarvii asentaa erikseen Dockerfilessä ennen käyttöä. Kannattaa varmaan kattoa vähän jotain tutoriaalia konteista ja Dockerfilen rakentamisesta.
Ei välttämättä, jos on vaikka useampi kone, jossa kehittää. Tuossa just viime viikolla tein simppelimmän kontin, jossa ristiinkäännetään ARM-koodia. Ei niitä työkaluja tarvitse olla valmiina koneessa (vrt. vaikka osana CI-putkea).

Tuossa asenetaan siis react-scripts, mutta eikö tuon pitäisi nuo package.json:n paketit hakea automaattisesti? Sitä minä tässä ihmettelen, että luin jo useamman jutun siitä, miten React kontitetaan, mutta ei onnaa. Olen myös muutaman kurssin katsonut aiheesta Pluralsightisss, mutta eivät menneet tälle tasolle.
 
Global react-scripts tarpeellinen, oikeudet? Dockerfile ja compose ladataan gittiin normaalisti, josta muut saa alustasta riippumatta saman kehitysympäristön/palvelimen.
Miten nuo oikeudet oikein tarkistetaan? En nimittäin hiffaa, kun buildaan tuon, niin menen konttiin sisälle niin sieltä ei tunnu löytyvän noita lisäosia, esimerkiksi node_modules -kansiota ei löydy, vaikka buildivaiheessa kaikki tuntuu onnistuvan.
 
Siis näissä kaikissa tehdään muka toimiva React-kontti:

Ja noita löytyy lisääkin. Sitä minä ihmettelen, että miksei minulla toimi?
 
Ei niitä työkaluja tarvitse olla valmiina koneessa (vrt. vaikka osana CI-putkea).
CI-putket on asia ihan erikseen. Minä ymmärsin, että haluat vaan saada lokaalisti kehitettävän ja yksinkertaisen React-sovelluksen buildatuksi ja laitettua konttiin.

Tuo oikeusjuttu liittyy varmaan tohon, mitä @Letuk kirjoitteli ja tuo kun ratkeaa, niin saanet varmaan tuon ekan konttiversion ainakin buildatuksi.
 
En näköjään ymmärtänyt tuota vastausta. Jos otan tuon pois, niin tulee "sh: 1 react-scripts: not found" ja sama tulee ilman -g -parametriä.
 
En näköjään ymmärtänyt tuota vastausta. Jos otan tuon pois, niin tulee "sh: 1 react-scripts: not found" ja sama tulee ilman -g -parametriä.
React scripts globaalisti asennettu kehitys koneessa, eikä package.json tiedostossa?
npm uninstall -g <package_name>
 
Tässä koneessa ei ole edes npm:ää tällä hetkellä - ja haluaisin välttää sen. Minulla on siis projektien välissä vähän aikaa ja ajattelin harjoitella tätä kontittamista vähän viime viikkoista monimutkaisemmalla keissillä niin tämä tuli mieleen.
 
Asensin sitten kuitenkin ympäristön tähän koneeseen ja seuraavat loitsut piti loitsia että lokaaliversio pyörähti:
Koodi:
npm install react-scripts
npm install typescript --save-dev
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt install nodejs
npm install --save react react-dom @types/react @types/react-dom
npm install
Tuossa taisi tulla pari ylimääräistä askelta, olisikohan pelklä nodejs:n päivitys (tässä on Debian 10) ja npm install riittänyt?
 
On kyllä ollut taas ennätysrasittavaa selata propellipäiden ohjeita. Yritän saada aliakset toimimaan ja ilmeisestikin siihen tarvitaan Craco-niminen moduli, koska CRA. Mutta en saa sitä kanssa tunkattua toimimaan noiden aliasten kanssa vaikka olen puolentusinaa ohjesivua lukenut. Nyt viimeksi tavaan tuollaista reac-app-alias-nimistä plugaria tuolle cracolle.

Ongelma on siis siinä, että CRA kirjoittaa tsconfig.json:n aina uusiksi. Cracolla pitäisi voida määritellä asioita, joita haluaa muuttaa tsconfigista. Tässä tapauksessa webpackiin pitäisi lisätä pari aliasta. Mutta esimerkiksi tuo plugari kertoo että näin lisäät plugarin tsconfig.json:iin (mistä ei ole vitunkaan hyötyä minulle, koska CRA) ja näin lisäät plugarin cracoon. Öh tota. Siis plugari komponentille, jonka tarkoitus on mahdollistaa tuon tsconfigin muokkaamisen ilman ejectiä neuvoo, että tsconfigia pitää muokata... jos ei tarvitsisi, niin voisin lisätä ne aliakset suoraan tuohon tiedostoon.

Ref.

Sitä kanssa ihmettelen, että kuvittelin, että craco laittaa ne muutokset suoraan tuohon tsconfigiin, mutta siellä niitä ei näy -> VS Code ei tajua myöskään niiden päälle. Mikä ei ole tietysit ihme, kun käännöksessäkin on "Cannot find module"-virhe. Huoh.

Ja tietysti tähän pisteeseen piti ensin päivittää koko CRA, koska craco ei tukenut enää käyttämääni versiota. Ihmeen kaupalla näytti onnistuvan, vaikka dokumentaation mukaan kaikenlaista breaking changea tuossa välissä on tullut.
 
Ja siis syy tuohon hommaan on se, että sain vihdoin kehiteltyä / lainattua / inspiroiduttua jonkunlaisesta tiedostorakenteesta. Tiedostot on tähän asti olleet epäloogisia sekä sijainniltaan että sisällöltään. Samassa tiedostossa on useampi komponentti, tyypit jne. Joten olen päätymässä tämän tapaiseen rakenteeseen:
Koodi:
src/
  - components
  - features
    - Person
      - index.js
      - api
        - PersonRoutes.tsx
      - components
      - forms
        - PersonForm.tsx
      - routes
        - PersonPage.tsx
      - types
        - index.tsx
      - services
  - services
  - utils
Featuresilla näyttää olevan monta mahdollista, nimeä. Pages, views, jne. Minulla on sellainenkin käsite kuin "Short", joka tarkoittaa lyhytmuotoista tarinaa, artikkelia, runoa, esipuhetta jne. Sille ei ole omaa sivua tällä hetkellä, vaan erilaisia komponentteja, jotka upotetaan muihin sivuihin. Joten features on paras yhteinen nimittäjä.

Eli:
  • components:n alla on sellaiset komponentit, jotka eivät liity mihinkään ominaisuuteen. Featuren alla taas tietysti sellaiset komponentit, jotka liittyvät siihen. Esimerkiksi novellilistaus.
  • index.js:ssä exportataan kaikki alikansioista. Näin jos haluaa jotain vaikka Personin alta, niin riittää "import { foo } from "features/Person".
  • Api:ssa on funktiot, jotka hakevat ja lähettävät dataa bäkkäriin.
  • Routesissa on komponentit, jotka käytännössä lisätään suoraan routerin Routeihin.
  • Typesin alla kaikki typet ja interfacet. Jotka pitänee nekin vielä refaktoroida, koska olin jostain lukenut IPerson-tyyppisestä nimeämisestä, mutta ilmeisesti tämä ei ole enää muodikasta. Eli pelkkä Person riittää.
Vähän vielä arvon, että mikä olisi loogisin paikka formeihin liittyville komponenteille. Noita kun voi käyttää monesta paikasta. Esimerkkinä komponentti, jolla valitaan kieli teokselle tai novellille. Tuo vielä aika selvästi menee päätason components:n alle, mutta entä komponentti, jolla valitaan kirjasarja? Kirjasarja on myös oma featurensa, joten loogisesti se menisi sen alle. Tällöin nuo formin komponentit menisivät kahteen paikkaan.

Tästä myös näkee, miksi kaipaisin noita moduleita. Nyt jos vaikka PersonForm.tsx:stä haluan incluudata jotain componentsin alta, niin se menee näin:
import { foo } from "../../../components/bar";
Kun haluaisin että se menee
import { foo } from "@components/bar";
 

Statistiikka

Viestiketjuista
261 816
Viestejä
4 548 227
Jäsenet
74 849
Uusin jäsen
Pizzapäivä123

Hinta.fi

Back
Ylös Bottom