
åçã§ã¯ãèªå® ã®ãã¹ã¯ã«ããŠã90ïŒ ã®æéåããŠããŸãã
ç§ãã¡ã«ã¯å°ããªããŒã ããã ãããžãã¹èªååã®ããã®Webã¢ããªã±ãŒã·ã§ã³ãéçºããŠããŸãã ã«ã¹ã¿ã ãããžã§ã¯ãã®å®è¡ã«å ããŠã2ã€ã®ãªã³ã©ã€ã³ãµãŒãã¹ãäœæããã³éçºããŠããŸãã
ããŒã å šå¡ãAB-DOCã«åãçµãã§ããããã§ã¯ãããŸããããç§ãšIgorBBã® 2人ã ãã§ã ã

ããã§ã¯ãAB-DOCãšã¯äœã§ããïŒ
ãµãŒããŒã¬ã¹ã¢ãŒããã¯ãã£
ãµãŒããŒã¬ã¹ã¢ããªã±ãŒã·ã§ã³ã¯ãçŸåšãWebéçºã®äžçã§åŒ·åãªãã¬ã³ããšãªã£ãŠããŸãã ç°¡åã«èšãã°ããããã¯å®å šã«ã¯ã©ãŠããããã€ããŒã®ãµãŒãã¹ã«åºã¥ããŠåäœããã¢ããªã±ãŒã·ã§ã³ã§ãã ãããã®å©ç¹ã¯ãããããæ©èœãããã¯ã©ãŠããµãŒãã¹ã®ç¹æ§ïŒãã©ãŒã«ããã¬ã©ã³ã¹ãšã¹ã±ãŒã©ããªãã£ïŒã«ç±æ¥ããŸãã ããã«ãã¯ã©ãŠããµãŒãã¹ãšåæ§ã«ããããã®ã³ã¹ãã¯è² è·ã«çŽæ¥äŸåããŸãã è² è·ããªãå Žåãã³ã¹ãã¯ãŒãã§ãã ããã¯éåžžã«å¿«é©ã§çŽ æŽãããã§ãã
ããããã³ã€ã³ã«ã¯è£è¿ãããããŸãã ãµãŒããŒã¬ã¹ã¢ããªã±ãŒã·ã§ã³ã®æåã®æ¬ ç¹ã¯ãè€éãªéçºããã»ã¹ã§ãã ã€ãŸããã€ã³ãã©ã¹ãã©ã¯ãã£ã®åææ§æããã³éçºããã»ã¹ã®æ§ç¯ã®æ®µéã§ã¯ããµãŒããŒãåããéåžžã®Webã¢ããªã±ãŒã·ã§ã³ãããå€ãã®åŽåãå¿ èŠã§ãã 2çªç®ã®æ¬ ç¹ã¯ããã®ãããªã¢ããªã±ãŒã·ã§ã³ã¯éåžžãã³ããŒã«äŸåããŠãããããå¥ã®ã¯ã©ãŠããããã€ããŒã«ç§»è¡ããã®ã¯å°é£ãªäœæ¥ã«ãªãå¯èœæ§ãããããšã§ãã
Amazon Web Servicesã§ã¢ããªã±ãŒã·ã§ã³ãäœæããŠããããããã®èšäºã®ãã¹ãŠã¯ãã®ã¯ã©ãŠããããã€ããŒãåç §ããŸãã
éåžžããµãŒããŒã¬ã¹ã¢ããªã±ãŒã·ã§ã³ã«ã¯ããã¯ãšã³ãããããŸãã ããã¯ãšã³ãã¯ããµãŒãã¹DynamoDBïŒNOSQL DBMSïŒãŸãã¯RDSïŒãªã¬ãŒã·ã§ãã«DBMSïŒã®åœ¢åŒã®ããŒã¿ããŒã¹ã§ãã ããã¯ãšã³ãã®ã³ãŒãã¯Lambdaé¢æ°ãšããŠå®è£ ãããAPI Gatewayãä»ããŠã¢ã¯ã»ã¹ãããŸãã
AB-DOCã«ã¯ããã¯ãããŸããã éåžžãããã¯ãšã³ããšãµãŒããŒã³ãŒãã¯ãããŸããïŒå°ãªããšããŸã ïŒã
AB-DOCã¢ãŒããã¯ãã£ã¯æ¬¡ã®ããã«ãªããŸã

ã¢ããªã±ãŒã·ã§ã³ã³ãŒãïŒHTMLãCSSãJavaScriptãªã©ïŒã¯å¥ã®S3ãã±ããã«ãããCDN CloudFrontãä»ããŠæäŸãããŸãã ååãšããŠããã±ããã§ã¯éçã³ã³ãã³ãããã¹ãããæ©èœãæå¹ã«ã§ãããããS3ããçŽæ¥æäŸã§ããŸãã
CloudFrontãå¿ èŠãªçç±ã¯ãã³ã³ãã³ãã®èªã¿èŸŒã¿ãé«éåããã ãã§ãªãããã¹ãŠã®ãªã³ã¯ãindex.htmlã«ãªãã€ã¬ã¯ãããæ¹æ³ãå¿ èŠã ã£ãããã§ããããŸããã AB-DOCã¯åäžããŒãžã¢ããªã±ãŒã·ã§ã³ïŒSPAïŒã§ãããããURLãèŠæ±ããå ŽåããŠãŒã¶ãŒãèªã¿èŸŒãããã«index.htmlãå¿ èŠã§ãã ããã«ããªã¯ãšã¹ããããURLã«åºââã¥ããŠãJavaScriptã¯ajaxã䜿çšããŠãŠãŒã¶ãŒã«å¿ èŠãªã³ã³ãã³ããèªã¿èŸŒã¿ãŸãã ããã³ããšã³ããã¬ãŒã ã¯ãŒã¯ã¯äœ¿çšããªããããç¬èªã®å°ããªã«ãŒã¿ãŒãäœæããŸããã
ãããã£ãŠããã¹ãŠã®URLãindex.htmlã«ãªãã€ã¬ã¯ãããã«ã¯ãCloudFrontã§404ãšã©ãŒåŠçã«ãŒã«ãèšå®ããŸãïŒããŒãžãèŠã€ãããŸããïŒã

ãã®ã«ãŒã«ã®ãããã§ãCloudFrontã¯ããªãœãŒã¹ã«ååšããªãURLã®ãªã¯ãšã¹ãã«å¿ããŠã200ã®å¿çã³ãŒãã§index.htmlãæäŸããŸããããã¯ãS3ã§ã³ãŒãããã¹ãããSPAãå®è£ ããããã®éæ³ã§ãã
ãŠãŒã¶ãŒã³ã³ãã³ããS3ã®å¥ã®ãã±ããã§ãã¹ããããCloudFrontãéããŠãæäŸãããŸãã ã«ã¹ã¿ã ã³ã³ãã³ãã«ã¯ãããªãŒæ§é ïŒJsonïŒãããã¥ã¡ã³ãã³ã³ãã³ãïŒHTMLïŒãããã¥ã¡ã³ãã«åã蟌ãŸããç»åãããã³æ·»ä»ãã¡ã€ã«ïŒããŸããŸãªåœ¢åŒïŒãå«ãŸããŸãã
ããã«ãç§ã®æèŠã§èå³æ·±ãå人ãã¢ããªã±ãŒã·ã§ã³ã®å®è£ ã®ãã¥ã¢ã³ã¹ã«ã€ããŠã話ããŸãã
èªèšŒãšæ¿èª
ã³ãŒãããŠãŒã¶ãŒã®ãã©ãŠã¶ã«ããŠã³ããŒãããåŸãAB-DOCã¯æåã«ãŠãŒã¶ãŒãèªèšŒããã³æ¿èªããŸãã ãã®ããã«ãCognitoã䜿çšããŸãã
èªèšŒã¯ãŠãŒã¶ãŒãèªèšŒããããã»ã¹ã§ãããæ¿èªã¯ãã®ãŠãŒã¶ãŒã«ããã°ã©ã ã§äœæ¥ããç¹å®ã®æš©å©ãäžããããã»ã¹ã§ããããšãæãåºãããŠãã ããã
Cognitoã¯3ã€ã®ãµãŒãã¹ã§æ§æãããŠããŸãã
- ãŠãŒã¶ãŒããŒã«
- ãã§ãã¬ãŒã·ã§ã³ID
- åæãã
CognitoãµãŒãã¹ã®çµéšããªãã£ãå ŽåãåãµãŒãã¹ãå¿ èŠãªçç±ãç解ããããšã¯å°é£ã§ãã ãããç解ããæ¹æ³ãæžããŠããŸãã
ãŠãŒã¶ãŒããŒã«
ããã¯ããŠãŒã¶ãŒã®ç»é²ãèªèšŒïŒèªèšŒïŒãããã³ã¢ã«ãŠã³ãã®ã¹ãã¬ãŒãžãæäŸãããããŒãžããµãŒãã¹ã§ãã åãŠãŒã¶ãŒã®ããŒã¿ãã£ãŒã«ãïŒæ ŒçŽãããã®ïŒããã¹ã¯ãŒãã®è€éãã®ããªã·ãŒãMFAã䜿çšãããã©ãããç»é²äžã«èµ·åã§ããããŸããŸãªããªã¬ãŒããã°ã€ã³ãªã©ãæ§æã§ããŸãã ããã§ããŠãŒã¶ãŒãç»é²ãããšãã«ãµãŒãã¹ãé»åã¡ãŒã«æ€èšŒã®ããã«éä¿¡ããã¡ãã»ãŒãžãæ§æã§ããŸãã
å€éšIDãããã€ããŒïŒFacebookãGoogleãAmazonããŸãã¯SAMLïŒããŠãŒã¶ãŒããŒã«ã«æ·»ä»ã§ããŸãã å€éšãããã€ããŒãä»ããŠãã°ã€ã³ãããšããŠãŒã¶ãŒããŒã«ã«ã¢ã«ãŠã³ããäœæãããŸãã ããã¯åºæ¬çã«ãCognitoãµãŒãã¹èªäœããã¹ããããã°ã€ã³ããŒãžã䜿çšããå Žåã«æ©èœããŸãã ã€ãŸãããŠãŒã¶ãŒããªãã€ã¬ã¯ãããŠãyour-app.authã[Region] .amazoncognito.comãšãã圢åŒã®ç¹å¥ãªURLãå ¥åããå¿ èŠããããŸãã ãã®ããŒãžã®å€èŠ³ã¯ãã¢ããªã±ãŒã·ã§ã³ã®å€èŠ³ã®ããã«ã«ã¹ã¿ãã€ãºã§ããŸãã æ¿èªåŸããŠãŒã¶ãŒã¯ã¢ããªã±ãŒã·ã§ã³ã«æ»ããŸãã ç§ã¯ãã®å®è£ ãªãã·ã§ã³ã奜ãã§ã¯ãããŸããã§ããã
JavaScriptçšAmazon Cognito Identity SDKã䜿çšããŠããŠãŒã¶ãŒããŒã«ãå€éšãããã€ããŒãšçµ±åããããšãããªãé·ãéè©Šã¿ãŸããã çè«çã«ã¯ããããå¯èœã§ããããã®ããŒãã«é¢ããããã¥ã¡ã³ããèŠã€ããããšãã§ãããç§ã¯ãããããŸããã ããã¯2ã3ã¶æåã§ããã
ãã§ãã¬ãŒã·ã§ã³ID
ãŠãŒã¶ãŒããŒã«ãšã¯ç°ãªãããã®ãµãŒãã¹ã¯ãŠãŒã¶ãŒãæ¿èªãã責任ããããŸããã€ãŸããAWSãµãŒãã¹ïŒS3ãªã©ïŒã«ã¢ã¯ã»ã¹ããç¹å®ã®ç¹æš©ããŠãŒã¶ãŒã«ä»äžããŸãã
ãã®ãµãŒãã¹ãæ©èœããã«ã¯ãIDããŒã«ãäœæãããããæ©èœããèªèšŒãããã€ããŒãæ§æããå¿ èŠããããŸãã ãŠãŒã¶ãŒããŒã«ã¯ãèªèšŒãããã€ããŒãšããŠã ãã§ãªããAmazonãFacebookãGoogleãTwitterãOpenIDãSAMLãªã©ã®å€ãã®å€éšãããã€ããŒããŸãã¯èªåã§äœæããèªèšŒãããã€ããŒãšããŠãæ©èœããŸãã
AB-DOCã§ã¯ããŠãŒã¶ãŒããŒã«ãš1ã€ã®å€éšãããã€ããŒã§ããGoogleãèªèšŒãããã€ããŒãšããŠäœ¿çšããŸãã ãããã£ãŠããŠãŒã¶ãŒã«ã¯2ã€ã®ãªãã·ã§ã³ããããŸãã
- æ°ããã¢ã«ãŠã³ããäœæããŸãïŒãã°ã€ã³ãã¹ã¯ãŒããäœæããã¡ãŒã«ã確èªããŸãïŒã ãã®å ŽåããŠãŒã¶ãŒããŒã«ã«ã¢ã«ãŠã³ããäœæããã次ã«IDããŒã«ã«ã¢ã«ãŠã³ããäœæãããŸããããã«ããã圌ã¯å¿ èŠãªæš©éãååŸããŸãã
- Googleã¢ã«ãŠã³ãã§ãµã€ã³ã€ã³ããŸãã ãã®åŸããŠãŒã¶ãŒããŒã«ã®ã¢ã«ãŠã³ãã¯äœæãããããŠãŒã¶ãŒã¯IDããŒã«ã«ã¢ã«ãŠã³ããäœæããã ãã§ãã¢ããªã±ãŒã·ã§ã³ãæäœããããã«å¿ èŠãªæš©éãäžããããŸãã
IDããŒã«ã§ã®æš©éä»äžã®ããã»ã¹ã¯éåžžã«ç°¡åã§ãã IDããŒã«ã®å ŽåãAWS Identity and Access ManagementïŒIAMïŒãã2ã€ã®ããŒã«ãéžæãããŸãïŒèªèšŒæžã¿ãŠãŒã¶ãŒçšãšéèªèšŒãŠãŒã¶ãŒçšã
IAMã®åããŒã«ã«å¯ŸããŠããŠãŒã¶ãŒã«å¿ èŠãªæš©éãä»»æã«ä»äžããããªã·ãŒãæ·»ä»ã§ããŸãã ããªã·ãŒã§å€æ°ã䜿çšããããšã§ãåå¥åãå¯èœã§ãã ããšãã°ãS3ãã±ããã®ãã©ã«ããŒå ã§ã®ã¿ãŠãŒã¶ãŒã«æžã蟌ã¿ã¢ã¯ã»ã¹ãèš±å¯ããã«ã¯ããªãœãŒã¹ã®èª¬æã§ãã®ãããªå€æ°ã䜿çšããŸã
... "Resource": [ "arn:aws:s3:::ab-doc-storage/${cognito-identity.amazonaws.com:sub}", "arn:aws:s3:::ab-doc-storage/${cognito-identity.amazonaws.com:sub}/*", ] ...
ãããã£ãŠãåãŠãŒã¶ãŒã®$ {cognito-identity.amazonaws.com:sub}ã®ä»£ããã«ãã¢ã€ãã³ãã£ãã£ããŒã«å ã®ãŠãŒã¶ãŒã®èå¥åãããªã·ãŒã«ä»£å ¥ãããŸãã åãŠãŒã¶ãŒã¯ããã±ããå ã®èªåã®ãã©ã«ããŒå ã§äœæ¥ããŸãããã®ååã¯ãIDããŒã«ã®IDã«å¯Ÿå¿ããŠããŸãã
S3ã«ã¯å®éã«ã¯ãã©ã«ããŒããªããããããã®ãã©ã«ããŒãšããèšèã¯åŒçšç¬Šã§å²ãããšãã§ããŸãã ããã¯ãã©ãããã¡ã€ã«ã·ã¹ãã ã§ãã åãã¡ã€ã«ã«ã¯åçŽã«ããŒïŒããŒïŒããããæ¡ä»¶ä»ãã§ããã©ã«ããŒãã«åå²ãããŸãã
åæãã
ãã®ãµãŒãã¹ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ãŠãŒã¶ãŒããŒã¿ã®ã¹ãã¬ãŒãžãæäŸããŸãã Syncã§ãã¹ããããããŒã¿ã¯ãIDããŒã«ã®ãŠãŒã¶ãŒIDã«ãã€ã³ããããããŒãšå€ã®ã»ããïŒããŒã¿ã»ããïŒãšããŠä¿åãããŸãã ãããã£ãŠãSyncã䜿çšãããšããŠãŒã¶ãŒããŒã«ãŸãã¯å€éšãããã€ããŒã§ãããã©ããã«ããããããèªèšŒãããªããã¹ãŠã®ãŠãŒã¶ãŒã®ä»»æã®æ å ±ãä¿åã§ããŸãã ããã«ãSyncã¯ããŠãŒã¶ãŒãã¢ããªã±ãŒã·ã§ã³ã§äœæ¥ããŠãããã¹ãŠã®ããã€ã¹éã§ããŒã¿ã»ããã®åæãæäŸããŸãã
äžè¬ã«ãèªå¯ã¯ããŒã¯ã³ã«åºã¥ããŠæ§ç¯ãããŸãã ãããæ åœããJavaScriptã³ãŒãã¯ãçŸåšãã¢ããªã±ãŒã·ã§ã³ã³ãŒãå šäœã®1/3以äžãå ããŠããŸãã ã€ãŸããããã¯ããªãèšå€§ãªãããã¯ã§ãããããã«ã€ããŠã¯ä»åŸå¥ã®èšäºãæžããããããŸããã
å€æŽãšã€ãã³ããã¥ãŒã远跡ãã
AB-DOCèªäœã¯ãããªãŒããŒããŸãã¯ããã¥ã¡ã³ãã®ã³ã³ãã³ããç·šéãããšãã«ãŠãŒã¶ãŒãå ããå€æŽã远跡ããŠä¿åããŸãã
ãã®ã¡ã«ããºã ã®åäœã¯ãJavaScriptã¿ã€ããŒsetIntervalïŒïŒã«åºã¥ããŠããŸãã ããªãŒçšãšããã¥ã¡ã³ãçšã«å¥ã ã®ã¿ã€ããŒãäœæããã3ç§ããšã«å€æŽãçºçããŠãããã©ããã確èªãããçºçããå Žåã¯S3ã«ä¿åãããŸãã ã¢ããªã±ãŒã·ã§ã³ã®ã¿ã€ããŒã¯ãTIMERSãªããžã§ã¯ããä»ããŠäžå€®ã§äœæãããŸãã
äžå åãããå€æŽè¿œè·¡ã®ããã«ãã€ãã³ããã¥ãŒã管çããACTIVITYãªããžã§ã¯ããäœæããŸããã ãã¥ãŒã¯ããŠãŒã¶ãŒãäœæã§ããã³ã³ãã³ãã®ãªãã·ã§ã³ã«åŸã£ãŠåœ¢æãããŸãã ããªãŒã«ã¯ç¬èªã®ãã¥ãŒããããããã¥ã¡ã³ãã«ã¯ç¬èªã®ãã¥ãŒããããåãã¥ãŒã«ã¯ç¬èªã®ãã¥ãŒããããŸãã
ãã¥ãŒã«èšé²ãããã€ãã³ãã«ã¯ãä¿çãŸãã¯ä¿åã®2çš®é¡ããããŸãã ãã¥ãŒã®ããžãã¯ã¯æ¬¡ã®ãšããã§ãã
ãŠãŒã¶ãŒãäœããã®ç·šéãè¡ããšãåŸ æ©ã€ãã³ããç®çã®ãã¥ãŒã«è¿œå ãããŸãã ããªãŒã§ã¯ãã€ãã³ãã¯å€æŽãåŠçããã³ãŒãããçŽæ¥è¿œå ãããããã¥ã¡ã³ãã®å€æŽã¯Mutation Observerã®ãããã§è¿œè·¡ãããŸãã
ããã«ã察å¿ããã¿ã€ããŒãããªã¬ãŒããããšã ä¿åã€ãã³ãããã¥ãŒã«è¿œå ãããS3ã«å€æŽãããŒãããããã»ã¹ãéå§ãããŸãã ããŠã³ããŒããæåãããšããã®ãã¥ãŒã¯æåŸã®ä¿åã€ãã³ããŸã§ã¯ãªã¢ãããŸãã ã¯ãªã¢ã®æç¹ã§ããã¥ãŒã«ã¯æ¬¡ã®3ç§ãµã€ã¯ã«ãåŸ æ©ããæ°ããåŸ æ©ã€ãã³ããæ¢ã«ããå ŽåããããŸãã
ããã¯ãããã¥ã¡ã³ãã®å€æŽãæ åœããããã¥ã¡ã³ãå€æŽãã¥ãŒã®äŸã§ã©ã®ããã«èŠãããã§ãã

ããããŒã®å€æŽã€ã³ãžã±ãŒã¿ã¯ãã€ãã³ããã¥ãŒã®ã¹ããŒã¿ã¹ãåæ ããŠããŸãã
äœãèµ·ãããããã¹ãŠã®ãã¥ãŒã空ã®å Žåãã€ã³ãžã±ãŒã¿ã¯è¡šç€ºãããŸããã

ãã¥ãŒã«åŸ æ©äžã®ã€ãã³ããããå Žåããªã¬ã³ãžè²ã®éçã§è¡šãããŸãã

ä¿åäžã®ãã¥ãŒãããå Žåãã€ã³ãžã±ãŒã¿ã¯çœã«å€ãããŸãã

ãã¥ãŒã空ã§ã¯ãªãããŠãŒã¶ãŒããã©ãŠã¶ãéããããšããããåã«ããŒãžãé¢ããããšãããšãwindow.onbeforeunloadïŒïŒé¢æ°ãæ©èœããŸãã 圌女ã¯ãç·šéå 容ããŸã ä¿åãããŠããªãããšããŠãŒã¶ãŒã«èŠåããŸãã 圌ã¯ãä¿åãå®äºãããŸã§åŸ ã€ããæåŸã®å€æŽã倱ã£ãŠããŒãžãé¢ããããšãã§ããŸãã
ã€ã³ãžã±ãŒã¿ãŒã¯ã$æŽæ°å€æ°ã«æžã蟌ãŸããŸãã
$update = $('#update');
ãªããžã§ã¯ãã³ãŒãã¿ã€ããŒ
//TIMERS object //tracks all timers and prevents memory leaks //call TIMERS.set('name') to create new timer //call TIMERS.<timer_name>.destroy() to destroy timer //call TIMERS.<timer_name>.execute() to execute timer TIMERS = { on: true, //timers are ON when true set: function(callback, interval, name){ if(['on', 'set', 'execute', 'destroy', 'Timer'].indexOf(name) !== -1){ throw new Error('Invalid timer name: ' + name); } if(this.hasOwnProperty(name) && this[name].id !== 0){ //automatically clears previous timer this[name].destroy(); } if(this.on || PRODUCTION){ this[name] = new this.Timer(callback, interval); } else { this[name] = { id: 0, execute: callback, destroy: function(){ void(0); } } } }, Timer: function(callback, interval){ //timer constructor this.id = setInterval(callback, interval); this.execute = callback; this.destroy = function(){ clearInterval(this.id); }; } };
ã¢ã¯ãã£ããã£ãªããžã§ã¯ãã³ãŒã
//ACTIVITY object //stores activities states and updates indicator in navbar. //Activities: doc edit, file [guid] upload, file [guid] delete or whatever. //Two possible states: pending or saving. //Each activity on each specific object must be reported independently! //"saving" class is "!important", so it dominates if both classes are active ACTIVITY = { lines: {}, //each activity has own line of pending and saving events push: function (activity, state){ var self = this; if(this.lines.hasOwnProperty(activity)){ this.lines[activity].push(state); } else { this.lines[activity] = [state]; } this.refresh(); return self; }, get: function(activity){ var self = this; if(this.lines.hasOwnProperty(activity)){ var length = this.lines[activity].length; return this.lines[activity][length-1]; } else { return undefined; } }, flush: function(activity){ var self = this; if(this.lines.hasOwnProperty(activity)){ var index = this.lines[activity].indexOf('saving'); if(index !== -1){ this.lines[activity] = this.lines[activity].slice(index+1); } } this.refresh(); return self; }, drop: function(activity){ var self = this; if (this.lines.hasOwnProperty(activity)){ delete this.lines[activity]; this.refresh(); } return self; }, refresh: function(){ var keys = Object.keys(this.lines), pending = false, saving = false; for (var i = 0; i < keys.length; i++) { pending = pending || this.lines[ keys[i] ].indexOf('pending') !== -1; saving = saving || this.lines[ keys[i] ].indexOf('saving') !== -1; } pending ? $update.addClass('pending') : $update.removeClass('pending'); saving ? $update.addClass('saving') : $update.removeClass('saving'); } }
ç¹°ãè¿ããŸãããããã¥ã¡ã³ãã®äŸã§ã¯ãããã»ã¹ã¯æ¬¡ã®ããã«ãªããŸãã ããã¥ã¡ã³ããéããšãããã¥ã¡ã³ãã®å 容ãå€æŽããã€ãã³ããã³ãã©ãŒããã³ã°ããŸãïŒå éšã«ã¯Mutation Observerã§ãïŒã ãã³ãã©ãŒã¯åã«åŸ æ©ã€ãã³ããããã¥ã¡ã³ãå€æŽãã¥ãŒã«è¿œå ããŸãã
editor.on('text-change', function () { ACTIVITY.push('doc modify', 'pending'); });
ããã¥ã¡ã³ãã¿ã€ããŒã¯3ç§ããšã«1åãããã¥ã¡ã³ãå€æŽãã¥ãŒã§åŸ æ©ã€ãã³ãããã§ãã¯ããå¿ èŠã«å¿ããŠS3ã«ããã¥ã¡ã³ãã®ã³ã³ãã³ããããŒããããã¥ãŒãã¯ãªã¢ããŸãã
TIMERS.set(function () { if(ACTIVITY.get('doc modify') === 'pending'){ ACTIVITY.push('doc modify', 'saving'); var params = { Bucket: STORAGE_BUCKET, Key: self.ownerid + '/' + self.docGUID + '/index.html', Body: self.editor.root.innerHTML, ContentType: 'text/html', ContentDisposition: abUtils.GetContentDisposition('index.html'), ACL: 'public-read' }; Promise.all([ s3.upload(params).promise(), new Promise(function(res, rej) { setTimeout(res, 800); }) ]).then(function(){ ACTIVITY.flush('doc modify'); }).catch(function(){ g.abUtils.onWarning(g.abUtils.translatorData['couldNotSave'][g.LANG]); }); } }, 3000, 'doc');
S3ã§ã®èªã¿èŸŒã¿ãéåžžéåžžã«é«éã§ãããšããäºå®ã«é¢é£ããé¢çœãç¬éããããŸãã ãããã£ãŠãä¿åã€ã³ãžã±ãŒã¿ãŒãã¡ãã€ããªãããã«ã2ã€ã®Promiseãå®äºãããšããªã¬ãŒãããPromise.allïŒïŒã䜿çšããŸããå®éã«ã¯s3.uploadïŒïŒãš0.8ç§ç¶ãå°ããªsetTimeoutïŒïŒã§ãã ããã¯ãå®éã«å€æŽãããéãèªã¿èŸŒãŸããå Žåã§ããã€ã³ãžã±ãŒã¿ãŒãå°ãªããšã0.8ç§ã®ç¯çŽã瀺ãããã«å¿ èŠã§ãã
S3ã§ã®ããŒã¿ã®ããŒããšä¿å
S3ã®åãŠãŒã¶ãŒã«ã¯ãIDããŒã«ã®IDãšäžèŽããååã®åå¥ã®ãã©ã«ããŒãå²ãåœãŠãããŸãã ãã®ãã©ã«ãã®ã«ãŒãã§ãAB-DOCã¯ãŠãŒã¶ãŒããªãŒæ§é ãæ ŒçŽããtree.jsonãã¡ã€ã«ãä¿åããŸãã
tree.jsonãã¡ã€ã«åœ¢åŒã¯æ¬¡ã®ãšããã§ãã
[ { "id": "GUID ()", "name": " ()", "children": [ { "id": "...", "name": "...", "children": [...] }, { "id": "...", "name": "...", "children": [...] }, ... ] }, { "id": "GUID ()", "name": " ()", "children": [ { "id": "...", "name": "...", "children": [...] }, { "id": "...", "name": "...", "children": [...] }, ... ] }, ... ]
ãã®æ§é ã¯ãããªãŒãã¬ã³ããªã³ã°ãããšãã«zTreeã®ããŒã¿ãœãŒã¹ãšããŠå€æŽãªãã§äœ¿çšãããŸãã
åããã¥ã¡ã³ãã¯åå¥ã®ãµããã©ã«ãã«ä¿åããããã®ååã¯ããã¥ã¡ã³ãã®GUIDãšäžèŽããŸãã ãã®ãã©ã«ããŒå ã«ãå®éã«ã¯ããã¥ã¡ã³ãã§ããindex.htmlãã¡ã€ã«ãä¿åãããŸãã ãã®ãã¡ã€ã«ã«å ããŠãããã¥ã¡ã³ãã«æ¿å ¥ãããç»åã¯åå¥ã®ãªããžã§ã¯ããšããŠããã¥ã¡ã³ããã©ã«ããŒã«ä¿åãããæ·»ä»ãã¡ã€ã«ã®ãµããã©ã«ããŒã«ã¯ããã¥ã¡ã³ãã«æ·»ä»ããããã¹ãŠã®ãã¡ã€ã«ãä¿åãããŸãã
ãã¹ãŠã®ããŒã¿ã¯ãAWS JavaScript SDKã®uploadïŒïŒé¢æ°ã䜿çšããŠããŠãŒã¶ãŒã®ãã©ãŠã¶ãŒããS3ã«çŽæ¥ããŠã³ããŒããããŸãã 圌女ã¯ãS3ã«ãã¡ã€ã«ãã¢ããããŒãããããããéšåã«åå²ïŒãã«ãããŒãã¢ããããŒãïŒããããã€ãã®ã¹ããªãŒã ã§ãããè¡ãæ¹æ³ãç¥ã£ãŠããŸãã
ããšãã°ãããã¯ããã¥ã¡ã³ãã«æ·»ä»ããããã¡ã€ã«ã4ã€ã®ã¹ããªãŒã ã«ããŒãããããããã6 MBã®éšåã«åå²ãããæ¹æ³ã§ãã ãã®ã³ãŒãã¯abDocãªããžã§ã¯ãïŒããã¥ã¡ã³ãïŒå ã§åäœããŸãããã®å Žåã¯self =ãã®ãªããžã§ã¯ãã®thisã§ãã
ACTIVITY.push('doc file upload', 'saving'); var fileGUID = abUtils.GetGUID(), key = self.ownerid + '/' + self.docGUID + '/attachments/' + fileGUID, partSize = 6 * 1024 * 1024; var file_obj = { guid: fileGUID, name: file.name, iconURL: abUtils.mimeTypeToIconURL(file.type), key: key, size: file.size, percent: '0%', abortable: file.size > partSize //only multipart upload can be aborted }; var params = { Bucket: STORAGE_BUCKET, Key: key, Body: file, ContentType: file.type, ContentDisposition: abUtils.GetContentDisposition(file.name), ACL: 'public-read' }; var upload = s3.upload(params, {partSize: partSize, queueSize: 4}); upload.on('httpUploadProgress', function(e) { var $file = $('.file-container[data-guid='+fileGUID+']'); if(!$file.hasClass('freeze')){ file_obj.percent = Math.ceil(e.loaded * 100.0 / e.total) + '%'; var $file_size = $file.find('.file-size'); $file_size.css('width', file_obj.percent); if($file_size.attr('data-text')){ $file_size.text( file_obj.percent ); } } }); upload.send(function(err, data) { if(err) { if (err.name !== 'RequestAbortedError') { abUtils.onError(err); } } else { var params = { Bucket: data.Bucket, Prefix: data.Key }; s3.listObjectsV2(params, function(err, data) { if (err) { abUtils.onError(err); } else { file_obj.modified = data.Contents[0].LastModified; self.updateFilesList(); ACTIVITY.flush('doc file upload'); } }); } });
httpUploadProgressã€ãã³ãã䜿çšãããšãããŠã³ããŒãã®é²è¡ç¶æ³ã远跡ãããã¡ã€ã«ã®é²è¡ç¶æ³ããŒãæŽæ°ã§ããŸãã
s3ãªããžã§ã¯ãïŒAWS JavaScript SDKïŒã¯ãID IDããŒã«ããŠãŒã¶ãŒã®ããŒã¯ã³IDãèªèšŒãããã€ããŒã®ååãå«ãè³æ Œæ å ±ã䜿çšããŸãã S3ãµãŒãã¹ãžã®ãã¹ãŠã®åŒã³åºãã¯ããŠãŒã¶ãŒIDããŒã¯ã³ã®è»¢éã§è¡ãããŸãã ãŠãŒã¶ãŒã«ã¯ãããŒã«ã«é¢é£ä»ããããããªã·ãŒã§èŠå®ãããŠããæš©å©ãä»äžãããŸãããã®ããªã·ãŒã¯ãã¢ã€ãã³ãã£ãã£ããŒã«ã§èšå®ãããŸãã åãååãJavaScript SDKãä»ããŠä»ã®AWSãµãŒãã¹ã§æ©èœããŸãã IDããŒã¯ã³ã®æå¹æéã¯çãïŒ1æéïŒåŸãæŽæ°ããŒã¯ã³ã䜿çšããŠæ°ããIDããŒã¯ã³ãååŸããå¿ èŠããããŸãã ãªãã¬ãã·ã¥ããŒã¯ã³ã®æå¹æéã¯365æ¥ã§ãã
空ã容éã€ã³ãžã±ãŒã¿
äžèŠãããã¯éåžžã«åçŽãªããšã®ããã«æãããããããŸããããå®å šã«çå®ã§ã¯ãããŸããã

空ãã¹ããŒã¹ã®ã€ã³ãžã±ãŒã¿ããã¹ã±ããã®åœ¢ã§äœæããŸãããäžéšãçããäžæ¹ã«åãã£ãŠåºãã£ãŠããŸãã èŠèŠçã«å å¡«å¯èœãªãã¹ã±ãããããã®ãããªãã¹ã±ãããç©ççãªäžçã§ã©ã®ããã«æºããããããšå¯Ÿå¿ãããããšèããŸããã ã€ãŸããäžããçããªããããæåã¯ããã«ãã£ã±ãã«ãªããŸãã ãããŠãããããã£ã±ãã«ãªããšãã¬ãã«ã¯äžåãã«æ¡å€§ããããããã£ãããšäžæããŸãã
ãããå®çŸããããã«ãåè§åœ¢ã®ã¬ãŠã¹é¢ç©åŒã䜿çšããŸãã ã

ãã®åŒã䜿çšããŠããã¹ã±ããäžã®ãã€ã³ãã®åº§æšãããã¹ã±ããå šäœã®é¢ç©ãèšç®ã§ããŸããããã¯ã1 GBã®æ倧空ãé åå¶éã«å¯Ÿå¿ããŸãã ããã«ããŠãŒã¶ãŒãæºãããããªã¥ãŒã ã®å€ã«åºã¥ããŠãåçŽãªæ¯çã䜿çšããŠããŠãŒã¶ãŒãå æãããã¹ã±ããã®éšåã®é¢ç©ãèšç®ããŸãã
ãŠãŒã¶ãŒãé åãå æãããšãäžèšã®åŒã«åºã¥ããŠãå¡ãã€ã¶ãããã¹ããŒã¹ã®äžéšå¢çã®Y座æšãèšç®ããŸãã å æã¹ããŒã¹ã®äžéšãã€ã³ãã®X座æšã¯ããã¹ã±ããã®ã³ãŒããŒã®æ¥ç·ãä»ããŠè¡šç€ºãããŸãã äžè¬ã«ãYã®å°åºã®çµæãã²ã©ãèŠãç®ã§ãããæ®éã®2次æ¹çšåŒãåŸãããŸããã ããŒãäžã®å³äžé ã«ãããŸãã

é»æ¿ã§ã¯ããµã€ãºã¯ãã¹ã±ãããåãŸãæ£æ¹åœ¢ã®èŸºã®é·ãã瀺ããŸãã ããšãã°ãããŒãã§ã¯ããµã€ãº= 30ã§ããäžè¬çãªåŒãå°åºããå¿ èŠããã£ããããè¡šèšãµã€ãºã䜿çšããŸããã
ããŠããããã®è¡ãæžããšããããŸããªçåãå ¥ã蟌ãã ã ãããããç§ã¯éåžžã«è³¢ããæ°åãäºç蟺å°åœ¢ã§ãããšä»®å®ãããšãã¯ããã«æšæž¬ããããã§ããã...
ã€ã³ãã£ã±ãŒã¿ãŒãæç»ããããã«ãèŠäºãªSVG.jsã©ã€ãã©ãªãŒã䜿çšããŸãããããã«ãããJavaScriptã§SVGã°ã©ãã£ãã¯ã¹ãæç»ã§ããŸãã ããã«ãæç»ããã ãã§ãªããã°ã©ãã£ãã¯ããªããã£ããæäœããããã¢ãã¡ãŒã·ã§ã³ãäœæããããã°ã©ãã£ãã¯ãšã¬ã¡ã³ãã§ã€ãã³ããã³ãã©ãŒããã³ã°ãããããšãã§ããŸãã 確ãã«ãæåŸã®æ©äŒã¯äœ¿çšããŸããã§ããã
ããã¯ã€ã³ãžã±ãŒã¿ãŒãæãé¢æ°ã§ã
function() { var size = 32, bucket_capacity = this.maxUsedSpace, space_occupied = this.userUsedSpace + this.userUsedSpaceDelta + this.userUsedSpacePending; //bucket coords var bx1 = 2, bx2 = 5, bx3 = size - bx2, bx4 = size - bx1, by1 = 2, by2 = size - by1, by3 = by2, by4 = by1, tg_alpha = (bx2 - bx1) / (by2 - by1); //calculate areas var barea = Math.abs(bx1*by2 + bx2*by3 + bx3*by4 + bx4*by1 - bx2*by1 - bx3*by2 - bx4*by3 - bx1*by4) / 2, sarea = Math.min(1.0, space_occupied / bucket_capacity) * barea; //calculate y of the occupied space (see sizeIndicator.jpg for details) var a = -2*tg_alpha, b = 3*tg_alpha*by2 + bx3 + size - 3*bx2 + tg_alpha*by3, c = bx2*by2 - tg_alpha*Math.pow(by2, 2) + 2*bx2*by3 - bx3*by2 - size*by3 - tg_alpha*by2*by3 + 2*sarea, D = Math.pow(b, 2) - 4*a*c, y = (-b + Math.sqrt(D)) / (2*a); //occupied space coords var sx1 = Math.ceil(bx2 - by2*tg_alpha + y*tg_alpha), sx2 = bx2, sx3 = bx3, sx4 = size - sx1, sy1 = Math.ceil(y)-2, sy2 = by2, sy3 = by3, sy4 = sy1; //draw if(!this.sizeIndicator){ this.sizeIndicator = SVG('sizeIndicator'); this.sizeIndicator.space = this.sizeIndicator .polygon([sx1,sy1, sx2,sy2, sx3,sy3, sx4,sy4]) //occupied space .fill('#DD6600'); this.sizeIndicator.bucket = this.sizeIndicator .polyline([bx1,by1, bx2,by2, bx3,by3, bx4,by4]).fill('none') //bucket shape .stroke({ color: '#fff', width: 3, linecap: 'round', linejoin: 'round' }); } else { this.sizeIndicator.space .animate(2000) .plot([sx1,sy1, sx2,sy2, sx3,sy3, sx4,sy4]); } //update tooltip $('#sizeIndicator').attr('title', g.abUtils.GetSize(space_occupied) + ' / ' + g.abUtils.GetSize(bucket_capacity)); }
ã¢ãã€ã«çã«ã€ããŠ
å¥ã®ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ãäœæããäºå®ã¯ãããŸããã ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ãè¿œå ã§ã€ã³ã¹ããŒã«ããå¿ èŠãããããããŠãŒã¶ãŒã¯ããŸã奜ãã§ã¯ãããŸããã ãã®ãããå®éã«ã¯ãå¥ã®ã¢ããªã±ãŒã·ã§ã³ãäœæããå¿ èŠãããããããããžã§ã¯ãã®ãµããŒããšéçºãè€éã«ãªããŸãã 代ããã«ãããã°ã¬ãã·ãWebã¢ããªã±ãŒã·ã§ã³ïŒProgressive Web AppãŸãã¯PWAïŒã®ãã¹ããã©ã£ãŠãããŸãã ããããçŸæç¹ã§ã¯ãAB-DOCã¯ããã§ã¯ãããŸããã ãããŸã§ã®ãšãããã¢ãã€ã«ãã©ãŠã¶ãŒããã¢ããªã±ãŒã·ã§ã³ã®äœæ¥ãã§ããéãå®å šãã€äŸ¿å©ã«ããããšããŠããŸãã
ç»é¢å¹ ã600ãã¯ã»ã«æªæºã®ã¢ãã€ã«ããã€ã¹ã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã®åäœãå€å°ç°ãªããŸãã ãã®ãããªããã€ã¹ã§ã¯ãããªãŒãŸãã¯ããã¥ã¡ã³ãã®2ã€ã®ã¢ãŒãã®ããããã§ã®ã¿æ©èœããŸãã äžè¬ã«ãããªãŒããŒãã®ãã©ãã°ã¢ã³ããããããããã¥ã¡ã³ããžã®ãã¡ã€ã«ã®æ·»ä»ãªã©ãã¿ããããã€ã¹ã®æ©èœãå®å šã«ç¶æããããšãã§ããŸããã
ãã ããã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã€ã³ã¿ãŒãããã«æ¥ç¶ããã«ããã¥ã¡ã³ããæäœããããšã¯ã§ããŸããã ããã¯ãPWAã®äœææã«å®è£ ãããéèŠãªæ©èœã§ãã
ã¢ãã€ã«ããã€ã¹ã§ã®ã¢ããªã±ãŒã·ã§ã³ã®é©å¿ã«åãçµãã§ãããšãã«çŽé¢ããå°é£ã®1ã€ã¯ã䟿å©ãªãã¹ãããŒã«ã®æ¬ åŠã§ãã
éçºè ã®ããŒã«ã«ãã·ã³ã§å®è¡ãããŠããã¢ããªã±ãŒã·ã§ã³ãã¢ãã€ã«ããã€ã¹ããéãããšã¯é£ãããããŸããã Wi-Fiçµç±ã§ããŒã«ã«ã¢ãã¬ã¹ã«ã¢ã¯ã»ã¹ã§ããŸãã ãã®ããã®ãã¡ã€ã³ãäœæãããããå€éšIPã«è»¢éããŠãããŒããã«ãŒã¿ãŒã®ããŒã«ã«ãã·ã³ã«è»¢éã§ããŸãã ãããŠããã®ãã¡ã€ã³ã¯ããŒã«ã«ãã·ã³ã®ã¢ããªã±ãŒã·ã§ã³ã¢ãã¬ã¹ã«ãªããŸãã
ã«ãŒã¿ãŒã®èšå®ã«å ¥ãæ¹æ³ããªãå Žåã¯ãUSBã¢ããã¿ãŒçµç±ã§Wi-Fiã䜿çšãããªãã·ã§ã³ããŸã ãããŸãã IgorBBã«ãã£ãŠçºæãããŸãã ã ãã®ãªãã·ã§ã³ã®è©³çŽ°ã«ã€ããŠã¯ãAB-DOCããªãŒhttps://ab-doc.com/eu-west-1_a01c087d-a71d-401c-a599-0b8bbacd99e5/d4b68bc3-2f32-4a3a-a57c-15cb697e8ef3ãã芧ãã ãã ã
ãã¹ãã®äž»ãªåé¡ã¯ãã¢ãã€ã«ãã©ãŠã¶ãŒã«éçºè ã³ã³ãœãŒã«ããªãããšã§ãã alertïŒïŒãä»ããŠãããã°æ å ±ãåºåããŠããŸãããããã¯ãã¡ããè¯ãéžæè¢ã§ã¯ãããŸããã ãããããŸã é©åãªæ¹æ³ãå®è£ ããŠããŸããã
éçºãšå±é
ãããžã§ã¯ãã«åãçµãã§ããã®ã¯2人ã ãã§ãããããéçºããã»ã¹ã¯éåžžã«ç°¡åã§ãã BitBucketã§gitãšãã©ã€ããŒããªããžããªã䜿çšããŸãã ãã¹ã¿ãŒãã©ã³ãã¯è£œåã³ãŒãã§ãã ããããã®ã¿ãããã€ããŸãã ç§ãã¡ã¯ãã¹ãŠã®æ©èœ/ãšã©ãŒãå¥ã ã®ãã©ã³ãã§åŠçããŸãã åãã©ã³ãã«ã¯ãç¬èªã®ã¿ã¹ã¯ãã©ãã«ãŒAB-TASKSã«åå¥ã®ã¿ã¹ã¯ããããŸãã ãã©ã³ãã¯ãã§ããã ãé »ç¹ã«ãã¹ã¿ãŒãšããŒãžããŠãããã€ããããšããŸãã
å±éããã»ã¹ã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã³ãŒããS3ãã±ããã«ããŒãããå¿ èŠããããŸãã ããã«ã¯ããã€ãã®ãã¥ã¢ã³ã¹ããããŸãã
äžèšã§æžããããã«ãCloudFrontã䜿çšããŠã³ã³ãã³ããé ä¿¡ããŸãã ã³ã³ãã³ããã»ãšãã©åžžã«CloudFrontãã£ãã·ã¥ããé ä¿¡ãããã¡ã«ããºã ãæäŸããå¿ èŠããããŸããããã¡ã€ã«ã®æŽæ°ããŒãžã§ã³ïŒpictureãcssãjsãhtmlãŸãã¯ãã®ä»ã®ãã¡ã€ã«ïŒãããŠã³ããŒããããšãCloudFrontã¯ãã£ãã·ã¥å ã®ãã¡ã€ã«ãæŽæ°ããå¿ èŠããããŸãã ããããªããšããŠãŒã¶ãŒããã£ãã·ã¥ãããã¡ã€ã«ã®äžéšãåãåã£ããããœãŒã¹ããæŽæ°ããããã¡ã€ã«ãåãåã£ãããããšããäžå¿«ãªç¶æ³ãçºçããå¯èœæ§ããããŸãïŒS3ïŒã ããã¯äºæž¬äžå¯èœãªçµæã«ã€ãªããå¯èœæ§ããããŸãã
ã¢ããªã±ãŒã·ã§ã³ã³ãŒããè¿ãã«ã¯ãAB-DOCãœãŒã¹ã³ãŒããå«ãS3ãã±ããã®åœ¢åŒã®1ã€ã®ãœãŒã¹ãšã2ã€ã®ãã£ãã·ã¥ã«ãŒã«ïŒãã£ãã·ã¥ã®åäœïŒãåããåå¥ã®CloudFrontãã£ã¹ããªãã¥ãŒã·ã§ã³ã䜿çšããŸãã
ãã£ãã·ã¥ã«ãŒã«ã¯ãCloudFrontããã¡ã€ã«ããã£ãã·ã¥ããæ¹æ³ãå®çŸ©ããŸãã ã«ãŒã«ãæ§æããã«ã¯ãèŠæ±ãã¿ãŒã³ïŒ* .htmlãŸãã¯images / *ãJpgãªã©ïŒãšãèŠæ±ãæå®ããããã¿ãŒã³ãšäžèŽãããšãã«é©çšãããèšå®ãèšå®ãããŸãã èšå®ã«ã¯ããã£ãã·ã³ã°ãã¢ã¯ãã£ããªHTTPã¡ãœãããTTLãã©ã¡ãŒã¿ãŒãŸãã¯ãã£ãã·ã¥å ã®ãªããžã§ã¯ãã®åç¶æéïŒæå°ãæ倧ãããã©ã«ãïŒãå§çž®ãããã³å®éã«ãã£ãã·ã³ã°ãå®è¡ãããåºæºïŒãã©ã¡ãŒã¿ãŒãèæ ®ããããã©ãããCookie ...ïŒãããã³ãã®ä»ã®å€ããå«ãŸããŸããã©ã¡ãŒã¿ã
2ã€ã®ãã£ãã·ã¥ã«ãŒã«ãæ§æããŸããã
- æåã®ã«ãŒã«ã¯HTMLãã¡ã€ã«çšã§ãã ãã£ãã·ã¥èšå®ã§ã¯ãå°ããTTLãèšå®ãããŠããŸãïŒæå°TTL = 100ç§ïŒã ãããã®ãã¡ã€ã«ã«cache-control max-age = 0ãèšå®ãããšãæå°TTLãé©çšãããŸããã€ãŸããHTMLãã¡ã€ã«ã¯100ç§åŸã«æéåããšèŠãªãããCloudFrontã¯ãœãŒã¹ãåŒã³åºããŠããã¡ã€ã«ã®ææ°ããŒãžã§ã³ãããã«è¡šç€ºããããã©ããã確èªããŸãã
- ä»ã®ãã¹ãŠã®ãã¡ã€ã«ã®2çªç®ã®ã«ãŒã«ã ãããã®ãã¡ã€ã«ã§ã¯ãcache-control max-ageãã¡ã€ã«ã®ããããŒãèšå®ããªããããæå°TTLãšããã©ã«ãTTLã®2ã€ã®æ倧å€ã䜿çšãããŸãã ç§ãã¡ã®å Žåãããã¯86400ç§ãŸãã¯24æéã§ããã€ãŸããé·ãæéãã£ãã·ã¥ãããŸãã ãã ããããã«å ããŠãã«ãŒã«èšå®ã§ã¯ããªããžã§ã¯ãããã£ãã·ã¥ãããšãã«CloudFrontããªã¯ãšã¹ããã©ã¡ãŒã¿ãŒããèŠããããšã瀺ããŠããŸãã
ããã¯ã AWSã®ããã¥ã¡ã³ã㧠ãããŸããŸãªTTLãšãã£ãã·ã¥å¶åŸ¡èšå®ãã©ã®ããã«çµã¿åãããããã説æããŠããå Žæã§ãã
ã¯ãšãªãã©ã¡ãŒã¿ã䜿çšãããšããã£ãã·ã¥ãç°¡åã«ç®¡çã§ããŸãã ãã¹ãŠã®ãã¡ã€ã«ã«ã€ããŠããã©ã¡ãŒã¿ãšããŠãã¡ã€ã«ã®æ¡ä»¶ä»ãããŒãžã§ã³ãè¿œå ããŸãïŒ filename.extensionïŒV = 123 ã ãã¡ã€ã«ãå€æŽãããŠããå Žåããã©ã¡ãŒã¿ãŒå€ãå€æŽããã ãã§ãCloudFrontã¯ãã£ãã·ã¥ããã§ã¯ãªããœãŒã¹ã«ãã¡ã€ã«ãè¿ããŸãã
ãã ãããã¡ã€ã«ã®å€æŽã远跡ããããããžã®ãªã³ã¯ãæåã§æŽæ°ããã®ã¯éåžžã«é¢åã§ãããæŠããŠäžå¯èœã§ãã ç§ãã¡ã¯ãããããããšãåžžã«å¿ããŠããŸããã ãã®ããããããèªåçã«è¡ãbashã¹ã¯ãªãããäœæããŸããã åæã«ãS3ã§ã®ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®æ¬æ Œçãªå±éã®ããã«å€ãã®æ©èœãå®è¡ããŸãã
圌ãå®è¡ããæé ã¯æ¬¡ã®ãšããã§ãã
- ãã¹ãŠã®HTMLãã¡ã€ã«ãã¹ãã£ã³ããŸãã grepã䜿çšãããšãå³é¢ãã¹ã¿ã€ã«ãã¹ã¯ãªãããžã®ãã¹ãŠã®ãªã³ã¯ãæ€çŽ¢ãããŸãã statã³ãã³ãã䜿çšããŠãåãã¡ã€ã«ã®æåŸã®å€æŽã®ã¿ã€ã ã¹ã¿ã³ãã確èªããŸã ã¹ã¯ãªããã®æåŸã®ãã¹ä»¥éã«ãã¡ã€ã«ãå€æŽãããŠããå Žåã sedã䜿çšããŠããã¡ã€ã«ãžã®ãªã³ã¯ã®ãã©ã¡ãŒã¿ãŒv = [timestamp]ã®ã¿ã€ã ã¹ã¿ã³ããæŽæ°ããŸãã
- ã¹ã¯ãªããæ§æã§ã¯ãã©ã®JavaScriptãã¡ã€ã«ã1ã€ã®ãã³ãã«ã«ã¢ã»ã³ãã«ãããã圌ã«äŒããããšãã§ããŸãã , babel . .
- S3 HTML , :
aws s3 sync $PACKAGE s3://"$bucket"/ --delete --acl public-read --exclude "*.html" aws s3 sync $PACKAGE s3://"$bucket"/ --delete --acl public-read --cache-control max-age=0 --exclude "*" --include "*.html"
#! /bin/bash # This script is used for deployment # It uploads files to the bucket, corrects timestamps of files included in HTML, bundles js scripts. # To use this script you need a config file: # .service/deploy.config : # bucket=mybucket # exclude=.git/*,.service/*,secret_file # Files and directories to exclude from uploading # bundle=script1.js,script2.js,script3.js # Scripts listed here would be removed from HTML files and bundeled into a single file, which will be minified. A separate bundle is created for every HTML file # You also need to install babel-cli and babel-preset-minify from npm: # npm install --save-dev babel-cli # npm install --save-dev babel-preset-minify # If you want this script to correct timestamps in HTML, you should include them with a ?v=<number> : <link rel="apple-touch-icon" sizes="180x180" href="/apple.png?ver=v123"> # You can use following options: # -v,--verbose - for detailed output # -n,--no-upload - do not upload result into bucket VERBOSE=false NO_UPLOAD=false PACKAGE="package" TMP="$PACKAGE/.temp" CONFIG=".service/deploy.config" PATH="$PATH:./node_modules/.bin" function log() { local message=$1 if [ "$VERBOSE" = true ] ; then echo $message fi } function error() { echo "$1" } bundle_n=0 function create_bundle() { local html_source_file=$1 echo "Creating bundle for \"$html_source_file\"..." #this is a grep command local grep0="$BUNDLE_GREP $html_source_file" #name before babel local bundle_before_babel="$TMP/ab.doc.bundle$bundle_n.js" #name to be used in html local bundle_after_babel_src="scripts/ab.doc.bundle$bundle_n.min.js" #name after babel local bundle_after_babel="$PACKAGE/$bundle_after_babel_src" $grep0 | while read -rx; do log "Adding \"$x\" to bundle" echo -en "//$x\n" >> $bundle_before_babel cat $x >> $bundle_before_babel echo -en "\n" >> $bundle_before_babel done # if files for bundling were found in html if [ -f $bundle_before_babel ] then #putting bundle through babel log "\"$bundle_before_babel\" >===(babel)===> \"$bundle_after_babel\"" npx --no-install babel "$bundle_before_babel" --out-file "$bundle_after_babel" --presets=minify #removing bundeled scripts from file log "Removing old scripts from \"$html_source_file\"..." sed="sed -i.bak -e \"" grep1="$BUNDLE_GREP -n $html_source_file" lines=($($grep1 | cut -f1 -d:)) for ln in ${lines[*]} do sed="$sed$ln d;" done sed="$sed\" $html_source_file" eval $sed #adding bundle instead of old scripts log "Adding bundle to \"$html_source_file\"..." current_time=$(stat -c %Y .$filename) sed -i.bak -e "${lines[0]}i<script src=\"/$bundle_after_babel_src?ver=v$current_time\"></script>" $html_source_file rm $html_source_file.bak bundle_n=$(expr $bundle_n + 1) fi } function update_versions() { local html_source_file=$1 local found=0 local modified=0 #set file versions according to modify timestamp echo "Updating file versions in \"$html_source_file\"..." grep -oE "\"[^\"]+\?ver=v[^\"]+\"" $html_source_file | while read -r href ; do ((found++)) local href="${href//\"/}" local current_timestamp=$(echo $href | grep -oE "[0-9]+$") local filename="${href/?ver=v[0-9]*/}" local new_timestamp=$(stat -c %Y $PACKAGE$filename) log $new_timestamp if [ "$current_timestamp" != "$new_timestamp" ] then ((modified++)) sed -i "s|$filename?ver=v[0-9]*|$filename?ver=v$new_timestamp|g" $html_source_file fi log "Found $found, modified $modified" done } function init_directory() { local path=$1 log "Creating empty directory \"$path\"" if [ -d "$path" ]; then log "\"$path\" already exists. Removing \"$path\"" rm -rf "$path" fi mkdir "$path" } echo "==== Initialization ====" # check flags while [[ $# -gt 0 ]] do key="$1" case $key in -v|--verbose) VERBOSE=true shift ;; -n|--no-upload) NO_UPLOAD=true shift ;; *) shift ;; esac done if [ ! -f $CONFIG ]; then error "Could not load config \"$CONFIG\"." exit -1 fi . $CONFIG exclude=${exclude//,/ } if ! npm list babel-preset-minify > /dev/null ; then error "babel-preset-minify is not installed" exit -2 fi if ! npm list babel-cli > /dev/null ; then error "babel-cli is not installed" exit -3 fi if [ -v bundle ]; then log "Using bundle" bundle=${bundle//,/ } BUNDLE_GREP="grep " for b in $bundle do BUNDLE_GREP="$BUNDLE_GREP -o -e $b " done else log "Not using bundle" fi # create package and tmp directories echo "==== Creating temporary directories ====" init_directory "$PACKAGE" init_directory "$TMP" # copying everything into package excluding files listed in $exclude copy="tar -c --exclude \"$PACKAGE\" " files_to_exclude="$exclude $bundle" #( "${exclude[@]}" "${bundle[@]}" ) for e in $files_to_exclude do log "Excluding $e" copy="$copy --exclude \"$e\"" done copy="$copy . | tar -x -C $PACKAGE" eval $copy echo "==== Working with HTML files ====" for f in $(find $PACKAGE -name '*.html') do if [ -v bundle ]; then create_bundle $f fi update_versions $f done rm -rf $TMP if [ "$NO_UPLOAD" = false ] ; then echo "==== S3 upload ====" #upload to S3 aws s3 sync $PACKAGE s3://"$bucket"/ --delete --acl public-read --exclude "*.html" aws s3 sync $PACKAGE s3://"$bucket"/ --delete --acl public-read --cache-control max-age=0 --exclude "*" --include "*.html" fi echo "==== Cleaning up ====" rm -rf $PACKAGE exit 0