diff --git a/packages/applications/turbo-blog/.gitignore b/packages/applications/blog/.gitignore similarity index 100% rename from packages/applications/turbo-blog/.gitignore rename to packages/applications/blog/.gitignore diff --git a/packages/applications/turbo-blog/package.json b/packages/applications/blog/package.json similarity index 98% rename from packages/applications/turbo-blog/package.json rename to packages/applications/blog/package.json index dc2d09d6..60a421bf 100644 --- a/packages/applications/turbo-blog/package.json +++ b/packages/applications/blog/package.json @@ -1,5 +1,5 @@ { - "name": "turbo-blog", + "name": "blog", "version": "1.0.0", "description": "", "keywords": [], diff --git a/packages/applications/turbo-blog/rspack.config.client.ts b/packages/applications/blog/rspack.config.client.ts similarity index 100% rename from packages/applications/turbo-blog/rspack.config.client.ts rename to packages/applications/blog/rspack.config.client.ts diff --git a/packages/applications/turbo-blog/rspack.config.server.ts b/packages/applications/blog/rspack.config.server.ts similarity index 100% rename from packages/applications/turbo-blog/rspack.config.server.ts rename to packages/applications/blog/rspack.config.server.ts diff --git a/packages/applications/turbo-blog/rspack.config.stylesheet.ts b/packages/applications/blog/rspack.config.stylesheet.ts similarity index 100% rename from packages/applications/turbo-blog/rspack.config.stylesheet.ts rename to packages/applications/blog/rspack.config.stylesheet.ts diff --git a/packages/applications/turbo-blog/src/articles/draft/about-new-core-web-vitals.md b/packages/applications/blog/src/articles/draft/about-new-core-web-vitals.md similarity index 100% rename from packages/applications/turbo-blog/src/articles/draft/about-new-core-web-vitals.md rename to packages/applications/blog/src/articles/draft/about-new-core-web-vitals.md diff --git a/packages/applications/turbo-blog/src/articles/draft/about-wasmtime.md b/packages/applications/blog/src/articles/draft/about-wasmtime.md similarity index 100% rename from packages/applications/turbo-blog/src/articles/draft/about-wasmtime.md rename to packages/applications/blog/src/articles/draft/about-wasmtime.md diff --git a/packages/applications/turbo-blog/src/articles/draft/learn-browser-through-creating.md b/packages/applications/blog/src/articles/draft/learn-browser-through-creating.md similarity index 100% rename from packages/applications/turbo-blog/src/articles/draft/learn-browser-through-creating.md rename to packages/applications/blog/src/articles/draft/learn-browser-through-creating.md diff --git a/packages/applications/turbo-blog/src/articles/en/eslint-plugin-for-orthographical-variants.md b/packages/applications/blog/src/articles/en/eslint-plugin-for-orthographical-variants.md similarity index 100% rename from packages/applications/turbo-blog/src/articles/en/eslint-plugin-for-orthographical-variants.md rename to packages/applications/blog/src/articles/en/eslint-plugin-for-orthographical-variants.md diff --git a/packages/applications/turbo-blog/src/articles/en/introduction-treeche.md b/packages/applications/blog/src/articles/en/introduction-treeche.md similarity index 100% rename from packages/applications/turbo-blog/src/articles/en/introduction-treeche.md rename to packages/applications/blog/src/articles/en/introduction-treeche.md diff --git a/packages/applications/turbo-blog/src/articles/en/m17n-with-cloudflare-workers.md b/packages/applications/blog/src/articles/en/m17n-with-cloudflare-workers.md similarity index 100% rename from packages/applications/turbo-blog/src/articles/en/m17n-with-cloudflare-workers.md rename to packages/applications/blog/src/articles/en/m17n-with-cloudflare-workers.md diff --git a/packages/applications/turbo-blog/src/articles/en/pnpm-outdated-command-supports-json-format.md b/packages/applications/blog/src/articles/en/pnpm-outdated-command-supports-json-format.md similarity index 100% rename from packages/applications/turbo-blog/src/articles/en/pnpm-outdated-command-supports-json-format.md rename to packages/applications/blog/src/articles/en/pnpm-outdated-command-supports-json-format.md diff --git a/packages/applications/turbo-blog/src/articles/third-pirty.json b/packages/applications/blog/src/articles/third-pirty.json similarity index 100% rename from packages/applications/turbo-blog/src/articles/third-pirty.json rename to packages/applications/blog/src/articles/third-pirty.json diff --git a/packages/applications/turbo-blog/src/assets/browser-on-browser/sys.png b/packages/applications/blog/src/assets/browser-on-browser/sys.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/browser-on-browser/sys.png rename to packages/applications/blog/src/assets/browser-on-browser/sys.png diff --git a/packages/applications/turbo-blog/src/assets/introduction-to-AST/ast-overview.png b/packages/applications/blog/src/assets/introduction-to-AST/ast-overview.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/introduction-to-AST/ast-overview.png rename to packages/applications/blog/src/assets/introduction-to-AST/ast-overview.png diff --git a/packages/applications/turbo-blog/src/assets/introduction-to-AST/ast-tool.png b/packages/applications/blog/src/assets/introduction-to-AST/ast-tool.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/introduction-to-AST/ast-tool.png rename to packages/applications/blog/src/assets/introduction-to-AST/ast-tool.png diff --git a/packages/applications/turbo-blog/src/assets/introduction-to-AST/ast-tree.png b/packages/applications/blog/src/assets/introduction-to-AST/ast-tree.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/introduction-to-AST/ast-tree.png rename to packages/applications/blog/src/assets/introduction-to-AST/ast-tree.png diff --git a/packages/applications/turbo-blog/src/assets/introduction-to-AST/transform.png b/packages/applications/blog/src/assets/introduction-to-AST/transform.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/introduction-to-AST/transform.png rename to packages/applications/blog/src/assets/introduction-to-AST/transform.png diff --git a/packages/applications/turbo-blog/src/assets/log-2020/kusa.png b/packages/applications/blog/src/assets/log-2020/kusa.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/log-2020/kusa.png rename to packages/applications/blog/src/assets/log-2020/kusa.png diff --git a/packages/applications/turbo-blog/src/assets/log-2020/newkusa.png b/packages/applications/blog/src/assets/log-2020/newkusa.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/log-2020/newkusa.png rename to packages/applications/blog/src/assets/log-2020/newkusa.png diff --git a/packages/applications/turbo-blog/src/assets/log-ca-web-speed-hackathon/hackathon-res.png b/packages/applications/blog/src/assets/log-ca-web-speed-hackathon/hackathon-res.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/log-ca-web-speed-hackathon/hackathon-res.png rename to packages/applications/blog/src/assets/log-ca-web-speed-hackathon/hackathon-res.png diff --git a/packages/applications/turbo-blog/src/assets/log-ca-web-speed-hackathon/webpack-bundle-analyzer.png b/packages/applications/blog/src/assets/log-ca-web-speed-hackathon/webpack-bundle-analyzer.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/log-ca-web-speed-hackathon/webpack-bundle-analyzer.png rename to packages/applications/blog/src/assets/log-ca-web-speed-hackathon/webpack-bundle-analyzer.png diff --git a/packages/applications/turbo-blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated-with-list.png b/packages/applications/blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated-with-list.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated-with-list.png rename to packages/applications/blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated-with-list.png diff --git a/packages/applications/turbo-blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated.png b/packages/applications/blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated.png rename to packages/applications/blog/src/assets/pnpm-outdated-command-supports-json-format/pnpm-outdated.png diff --git a/packages/applications/turbo-blog/src/assets/pnpm-outdated-command-supports-json-format/tweet.png b/packages/applications/blog/src/assets/pnpm-outdated-command-supports-json-format/tweet.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/pnpm-outdated-command-supports-json-format/tweet.png rename to packages/applications/blog/src/assets/pnpm-outdated-command-supports-json-format/tweet.png diff --git a/packages/applications/turbo-blog/src/assets/remake-blog-with-nextjs-nowsh/27-1.jpeg b/packages/applications/blog/src/assets/remake-blog-with-nextjs-nowsh/27-1.jpeg similarity index 100% rename from packages/applications/turbo-blog/src/assets/remake-blog-with-nextjs-nowsh/27-1.jpeg rename to packages/applications/blog/src/assets/remake-blog-with-nextjs-nowsh/27-1.jpeg diff --git a/packages/applications/turbo-blog/src/assets/remake-blog-with-nextjs-nowsh/27-2.png b/packages/applications/blog/src/assets/remake-blog-with-nextjs-nowsh/27-2.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/remake-blog-with-nextjs-nowsh/27-2.png rename to packages/applications/blog/src/assets/remake-blog-with-nextjs-nowsh/27-2.png diff --git a/packages/applications/turbo-blog/src/assets/remake-blog-with-nextjs-nowsh/27-3.png b/packages/applications/blog/src/assets/remake-blog-with-nextjs-nowsh/27-3.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/remake-blog-with-nextjs-nowsh/27-3.png rename to packages/applications/blog/src/assets/remake-blog-with-nextjs-nowsh/27-3.png diff --git a/packages/applications/turbo-blog/src/assets/static/AMP.png b/packages/applications/blog/src/assets/static/AMP.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/AMP.png rename to packages/applications/blog/src/assets/static/AMP.png diff --git a/packages/applications/turbo-blog/src/assets/static/a11y-dark.min.css b/packages/applications/blog/src/assets/static/a11y-dark.min.css similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/a11y-dark.min.css rename to packages/applications/blog/src/assets/static/a11y-dark.min.css diff --git a/packages/applications/turbo-blog/src/assets/static/a11y-dark.min.css.d.ts b/packages/applications/blog/src/assets/static/a11y-dark.min.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/a11y-dark.min.css.d.ts rename to packages/applications/blog/src/assets/static/a11y-dark.min.css.d.ts diff --git a/packages/applications/turbo-blog/src/assets/static/banana.png b/packages/applications/blog/src/assets/static/banana.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/banana.png rename to packages/applications/blog/src/assets/static/banana.png diff --git a/packages/applications/turbo-blog/src/assets/static/cloudflare.png b/packages/applications/blog/src/assets/static/cloudflare.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/cloudflare.png rename to packages/applications/blog/src/assets/static/cloudflare.png diff --git a/packages/applications/turbo-blog/src/assets/static/e-mail.png b/packages/applications/blog/src/assets/static/e-mail.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/e-mail.png rename to packages/applications/blog/src/assets/static/e-mail.png diff --git a/packages/applications/turbo-blog/src/assets/static/earth.png b/packages/applications/blog/src/assets/static/earth.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/earth.png rename to packages/applications/blog/src/assets/static/earth.png diff --git a/packages/applications/turbo-blog/src/assets/static/earth_africa.png b/packages/applications/blog/src/assets/static/earth_africa.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/earth_africa.png rename to packages/applications/blog/src/assets/static/earth_africa.png diff --git a/packages/applications/turbo-blog/src/assets/static/fastly.png b/packages/applications/blog/src/assets/static/fastly.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/fastly.png rename to packages/applications/blog/src/assets/static/fastly.png diff --git a/packages/applications/turbo-blog/src/assets/static/favicon.ico b/packages/applications/blog/src/assets/static/favicon.ico similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/favicon.ico rename to packages/applications/blog/src/assets/static/favicon.ico diff --git a/packages/applications/turbo-blog/src/assets/static/fire.png b/packages/applications/blog/src/assets/static/fire.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/fire.png rename to packages/applications/blog/src/assets/static/fire.png diff --git a/packages/applications/turbo-blog/src/assets/static/gb.png b/packages/applications/blog/src/assets/static/gb.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/gb.png rename to packages/applications/blog/src/assets/static/gb.png diff --git a/packages/applications/turbo-blog/src/assets/static/github.svg b/packages/applications/blog/src/assets/static/github.svg similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/github.svg rename to packages/applications/blog/src/assets/static/github.svg diff --git a/packages/applications/turbo-blog/src/assets/static/icon.png b/packages/applications/blog/src/assets/static/icon.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/icon.png rename to packages/applications/blog/src/assets/static/icon.png diff --git a/packages/applications/turbo-blog/src/assets/static/icon_blur.png b/packages/applications/blog/src/assets/static/icon_blur.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/icon_blur.png rename to packages/applications/blog/src/assets/static/icon_blur.png diff --git a/packages/applications/turbo-blog/src/assets/static/icon_thatsme.png b/packages/applications/blog/src/assets/static/icon_thatsme.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/icon_thatsme.png rename to packages/applications/blog/src/assets/static/icon_thatsme.png diff --git a/packages/applications/turbo-blog/src/assets/static/icon_transparent_header.png b/packages/applications/blog/src/assets/static/icon_transparent_header.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/icon_transparent_header.png rename to packages/applications/blog/src/assets/static/icon_transparent_header.png diff --git a/packages/applications/turbo-blog/src/assets/static/javascript.png b/packages/applications/blog/src/assets/static/javascript.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/javascript.png rename to packages/applications/blog/src/assets/static/javascript.png diff --git a/packages/applications/turbo-blog/src/assets/static/jp.png b/packages/applications/blog/src/assets/static/jp.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/jp.png rename to packages/applications/blog/src/assets/static/jp.png diff --git a/packages/applications/turbo-blog/src/assets/static/linkedin.svg b/packages/applications/blog/src/assets/static/linkedin.svg similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/linkedin.svg rename to packages/applications/blog/src/assets/static/linkedin.svg diff --git a/packages/applications/turbo-blog/src/assets/static/placeholder.png b/packages/applications/blog/src/assets/static/placeholder.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/placeholder.png rename to packages/applications/blog/src/assets/static/placeholder.png diff --git a/packages/applications/turbo-blog/src/assets/static/react.png b/packages/applications/blog/src/assets/static/react.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/react.png rename to packages/applications/blog/src/assets/static/react.png diff --git a/packages/applications/turbo-blog/src/assets/static/rust.png b/packages/applications/blog/src/assets/static/rust.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/rust.png rename to packages/applications/blog/src/assets/static/rust.png diff --git a/packages/applications/turbo-blog/src/assets/static/shinyaigeek_icon.png b/packages/applications/blog/src/assets/static/shinyaigeek_icon.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/shinyaigeek_icon.png rename to packages/applications/blog/src/assets/static/shinyaigeek_icon.png diff --git a/packages/applications/turbo-blog/src/assets/static/shinyaigeek_portrait_transparent.png b/packages/applications/blog/src/assets/static/shinyaigeek_portrait_transparent.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/shinyaigeek_portrait_transparent.png rename to packages/applications/blog/src/assets/static/shinyaigeek_portrait_transparent.png diff --git a/packages/applications/turbo-blog/src/assets/static/spider_web.png b/packages/applications/blog/src/assets/static/spider_web.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/spider_web.png rename to packages/applications/blog/src/assets/static/spider_web.png diff --git a/packages/applications/turbo-blog/src/assets/static/twitter.svg b/packages/applications/blog/src/assets/static/twitter.svg similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/twitter.svg rename to packages/applications/blog/src/assets/static/twitter.svg diff --git a/packages/applications/turbo-blog/src/assets/static/typescript.png b/packages/applications/blog/src/assets/static/typescript.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/typescript.png rename to packages/applications/blog/src/assets/static/typescript.png diff --git a/packages/applications/turbo-blog/src/assets/static/us.png b/packages/applications/blog/src/assets/static/us.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/static/us.png rename to packages/applications/blog/src/assets/static/us.png diff --git a/packages/applications/turbo-blog/src/assets/what-is-TypeScript-s-reversal/25-3.png b/packages/applications/blog/src/assets/what-is-TypeScript-s-reversal/25-3.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/what-is-TypeScript-s-reversal/25-3.png rename to packages/applications/blog/src/assets/what-is-TypeScript-s-reversal/25-3.png diff --git a/packages/applications/turbo-blog/src/assets/what-is-TypeScript-s-reversal/25-4.png b/packages/applications/blog/src/assets/what-is-TypeScript-s-reversal/25-4.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/what-is-TypeScript-s-reversal/25-4.png rename to packages/applications/blog/src/assets/what-is-TypeScript-s-reversal/25-4.png diff --git a/packages/applications/turbo-blog/src/assets/without-create-react-app/21-2.png b/packages/applications/blog/src/assets/without-create-react-app/21-2.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/without-create-react-app/21-2.png rename to packages/applications/blog/src/assets/without-create-react-app/21-2.png diff --git a/packages/applications/turbo-blog/src/assets/without-create-react-app/21-3.png b/packages/applications/blog/src/assets/without-create-react-app/21-3.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/without-create-react-app/21-3.png rename to packages/applications/blog/src/assets/without-create-react-app/21-3.png diff --git a/packages/applications/turbo-blog/src/assets/without-create-react-app/21-4.gif b/packages/applications/blog/src/assets/without-create-react-app/21-4.gif similarity index 100% rename from packages/applications/turbo-blog/src/assets/without-create-react-app/21-4.gif rename to packages/applications/blog/src/assets/without-create-react-app/21-4.gif diff --git a/packages/applications/turbo-blog/src/assets/without-create-react-app/21-5.png b/packages/applications/blog/src/assets/without-create-react-app/21-5.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/without-create-react-app/21-5.png rename to packages/applications/blog/src/assets/without-create-react-app/21-5.png diff --git a/packages/applications/turbo-blog/src/assets/without-create-react-app/21-6.png b/packages/applications/blog/src/assets/without-create-react-app/21-6.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/without-create-react-app/21-6.png rename to packages/applications/blog/src/assets/without-create-react-app/21-6.png diff --git a/packages/applications/turbo-blog/src/assets/without-create-react-app/21-7.png b/packages/applications/blog/src/assets/without-create-react-app/21-7.png similarity index 100% rename from packages/applications/turbo-blog/src/assets/without-create-react-app/21-7.png rename to packages/applications/blog/src/assets/without-create-react-app/21-7.png diff --git a/packages/applications/turbo-blog/src/build/application/chooseLanguage/chooseLanguage.ts b/packages/applications/blog/src/build/application/chooseLanguage/chooseLanguage.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/application/chooseLanguage/chooseLanguage.ts rename to packages/applications/blog/src/build/application/chooseLanguage/chooseLanguage.ts diff --git a/packages/applications/turbo-blog/src/build/application/getBlogPost/getBlogPost.usecase.ts b/packages/applications/blog/src/build/application/getBlogPost/getBlogPost.usecase.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/application/getBlogPost/getBlogPost.usecase.ts rename to packages/applications/blog/src/build/application/getBlogPost/getBlogPost.usecase.ts diff --git a/packages/applications/turbo-blog/src/build/application/getBlogPosts/getBlogposts.usecase.ts b/packages/applications/blog/src/build/application/getBlogPosts/getBlogposts.usecase.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/application/getBlogPosts/getBlogposts.usecase.ts rename to packages/applications/blog/src/build/application/getBlogPosts/getBlogposts.usecase.ts diff --git a/packages/applications/turbo-blog/src/build/babel.config.js b/packages/applications/blog/src/build/babel.config.js similarity index 100% rename from packages/applications/turbo-blog/src/build/babel.config.js rename to packages/applications/blog/src/build/babel.config.js diff --git a/packages/applications/turbo-blog/src/build/build.ts b/packages/applications/blog/src/build/build.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/build.ts rename to packages/applications/blog/src/build/build.ts diff --git a/packages/applications/turbo-blog/src/build/context/context.ts b/packages/applications/blog/src/build/context/context.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/context/context.ts rename to packages/applications/blog/src/build/context/context.ts diff --git a/packages/applications/turbo-blog/src/build/handlers/index/generate.tsx b/packages/applications/blog/src/build/handlers/index/generate.tsx similarity index 100% rename from packages/applications/turbo-blog/src/build/handlers/index/generate.tsx rename to packages/applications/blog/src/build/handlers/index/generate.tsx diff --git a/packages/applications/turbo-blog/src/build/handlers/index/output.tsx b/packages/applications/blog/src/build/handlers/index/output.tsx similarity index 100% rename from packages/applications/turbo-blog/src/build/handlers/index/output.tsx rename to packages/applications/blog/src/build/handlers/index/output.tsx diff --git a/packages/applications/turbo-blog/src/build/handlers/post/generate.tsx b/packages/applications/blog/src/build/handlers/post/generate.tsx similarity index 100% rename from packages/applications/turbo-blog/src/build/handlers/post/generate.tsx rename to packages/applications/blog/src/build/handlers/post/generate.tsx diff --git a/packages/applications/turbo-blog/src/build/handlers/post/getBlogChildren/getBlogChildren.ts b/packages/applications/blog/src/build/handlers/post/getBlogChildren/getBlogChildren.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/handlers/post/getBlogChildren/getBlogChildren.ts rename to packages/applications/blog/src/build/handlers/post/getBlogChildren/getBlogChildren.ts diff --git a/packages/applications/turbo-blog/src/build/handlers/post/output.tsx b/packages/applications/blog/src/build/handlers/post/output.tsx similarity index 100% rename from packages/applications/turbo-blog/src/build/handlers/post/output.tsx rename to packages/applications/blog/src/build/handlers/post/output.tsx diff --git a/packages/applications/turbo-blog/src/build/handlers/profile/generate.tsx b/packages/applications/blog/src/build/handlers/profile/generate.tsx similarity index 100% rename from packages/applications/turbo-blog/src/build/handlers/profile/generate.tsx rename to packages/applications/blog/src/build/handlers/profile/generate.tsx diff --git a/packages/applications/turbo-blog/src/build/handlers/profile/output.tsx b/packages/applications/blog/src/build/handlers/profile/output.tsx similarity index 100% rename from packages/applications/turbo-blog/src/build/handlers/profile/output.tsx rename to packages/applications/blog/src/build/handlers/profile/output.tsx diff --git a/packages/applications/turbo-blog/src/build/model/blog/__fixture__/invalid-blog.md b/packages/applications/blog/src/build/model/blog/__fixture__/invalid-blog.md similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/__fixture__/invalid-blog.md rename to packages/applications/blog/src/build/model/blog/__fixture__/invalid-blog.md diff --git a/packages/applications/turbo-blog/src/build/model/blog/__fixture__/valid-blog.md b/packages/applications/blog/src/build/model/blog/__fixture__/valid-blog.md similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/__fixture__/valid-blog.md rename to packages/applications/blog/src/build/model/blog/__fixture__/valid-blog.md diff --git a/packages/applications/turbo-blog/src/build/model/blog/__snapshot__/extract-blog-metadata/valid-blog.txt b/packages/applications/blog/src/build/model/blog/__snapshot__/extract-blog-metadata/valid-blog.txt similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/__snapshot__/extract-blog-metadata/valid-blog.txt rename to packages/applications/blog/src/build/model/blog/__snapshot__/extract-blog-metadata/valid-blog.txt diff --git a/packages/applications/turbo-blog/src/build/model/blog/blog.entity.ts b/packages/applications/blog/src/build/model/blog/blog.entity.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/blog.entity.ts rename to packages/applications/blog/src/build/model/blog/blog.entity.ts diff --git a/packages/applications/turbo-blog/src/build/model/blog/blog.repository.ts b/packages/applications/blog/src/build/model/blog/blog.repository.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/blog.repository.ts rename to packages/applications/blog/src/build/model/blog/blog.repository.ts diff --git a/packages/applications/turbo-blog/src/build/model/blog/extract-blog-metadata.test.ts b/packages/applications/blog/src/build/model/blog/extract-blog-metadata.test.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/extract-blog-metadata.test.ts rename to packages/applications/blog/src/build/model/blog/extract-blog-metadata.test.ts diff --git a/packages/applications/turbo-blog/src/build/model/blog/extract-blog-metadata.ts b/packages/applications/blog/src/build/model/blog/extract-blog-metadata.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/extract-blog-metadata.ts rename to packages/applications/blog/src/build/model/blog/extract-blog-metadata.ts diff --git a/packages/applications/turbo-blog/src/build/model/blog/parse-blog-content.ts b/packages/applications/blog/src/build/model/blog/parse-blog-content.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/blog/parse-blog-content.ts rename to packages/applications/blog/src/build/model/blog/parse-blog-content.ts diff --git a/packages/applications/turbo-blog/src/build/model/content/content.entity.ts b/packages/applications/blog/src/build/model/content/content.entity.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/content/content.entity.ts rename to packages/applications/blog/src/build/model/content/content.entity.ts diff --git a/packages/applications/turbo-blog/src/build/model/language/language.entity.ts b/packages/applications/blog/src/build/model/language/language.entity.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/language/language.entity.ts rename to packages/applications/blog/src/build/model/language/language.entity.ts diff --git a/packages/applications/turbo-blog/src/build/model/m17n/m17n.entity.ts b/packages/applications/blog/src/build/model/m17n/m17n.entity.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/model/m17n/m17n.entity.ts rename to packages/applications/blog/src/build/model/m17n/m17n.entity.ts diff --git a/packages/applications/turbo-blog/src/build/plugin/language.ts b/packages/applications/blog/src/build/plugin/language.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/plugin/language.ts rename to packages/applications/blog/src/build/plugin/language.ts diff --git a/packages/applications/turbo-blog/src/build/util/addDOCTYPE.ts b/packages/applications/blog/src/build/util/addDOCTYPE.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/addDOCTYPE.ts rename to packages/applications/blog/src/build/util/addDOCTYPE.ts diff --git a/packages/applications/turbo-blog/src/build/util/generateHash.ts b/packages/applications/blog/src/build/util/generateHash.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/generateHash.ts rename to packages/applications/blog/src/build/util/generateHash.ts diff --git a/packages/applications/turbo-blog/src/build/util/getBlogPost.ts b/packages/applications/blog/src/build/util/getBlogPost.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/getBlogPost.ts rename to packages/applications/blog/src/build/util/getBlogPost.ts diff --git a/packages/applications/turbo-blog/src/build/util/getBlogPosts.ts b/packages/applications/blog/src/build/util/getBlogPosts.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/getBlogPosts.ts rename to packages/applications/blog/src/build/util/getBlogPosts.ts diff --git a/packages/applications/turbo-blog/src/build/util/getOmmit.ts b/packages/applications/blog/src/build/util/getOmmit.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/getOmmit.ts rename to packages/applications/blog/src/build/util/getOmmit.ts diff --git a/packages/applications/turbo-blog/src/build/util/getRss.ts b/packages/applications/blog/src/build/util/getRss.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/getRss.ts rename to packages/applications/blog/src/build/util/getRss.ts diff --git a/packages/applications/turbo-blog/src/build/util/getSitemap.ts b/packages/applications/blog/src/build/util/getSitemap.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/getSitemap.ts rename to packages/applications/blog/src/build/util/getSitemap.ts diff --git a/packages/applications/turbo-blog/src/build/util/getThirdPirty.ts b/packages/applications/blog/src/build/util/getThirdPirty.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/getThirdPirty.ts rename to packages/applications/blog/src/build/util/getThirdPirty.ts diff --git a/packages/applications/turbo-blog/src/build/util/writeFileWithDir.ts b/packages/applications/blog/src/build/util/writeFileWithDir.ts similarity index 100% rename from packages/applications/turbo-blog/src/build/util/writeFileWithDir.ts rename to packages/applications/blog/src/build/util/writeFileWithDir.ts diff --git a/packages/applications/turbo-blog/src/client/main.tsx b/packages/applications/blog/src/client/main.tsx similarity index 100% rename from packages/applications/turbo-blog/src/client/main.tsx rename to packages/applications/blog/src/client/main.tsx diff --git a/packages/applications/turbo-blog/src/react-env.d.ts b/packages/applications/blog/src/react-env.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/react-env.d.ts rename to packages/applications/blog/src/react-env.d.ts diff --git a/packages/applications/turbo-blog/src/stylesheet.ts b/packages/applications/blog/src/stylesheet.ts similarity index 100% rename from packages/applications/turbo-blog/src/stylesheet.ts rename to packages/applications/blog/src/stylesheet.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Button/Button.module.css b/packages/applications/blog/src/ui/components/Button/Button.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Button/Button.module.css rename to packages/applications/blog/src/ui/components/Button/Button.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Button/Button.module.css.d.ts b/packages/applications/blog/src/ui/components/Button/Button.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Button/Button.module.css.d.ts rename to packages/applications/blog/src/ui/components/Button/Button.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Button/Button.tsx b/packages/applications/blog/src/ui/components/Button/Button.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Button/Button.tsx rename to packages/applications/blog/src/ui/components/Button/Button.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Contact/Contact.module.css b/packages/applications/blog/src/ui/components/Contact/Contact.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Contact/Contact.module.css rename to packages/applications/blog/src/ui/components/Contact/Contact.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Contact/Contact.module.css.d.ts b/packages/applications/blog/src/ui/components/Contact/Contact.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Contact/Contact.module.css.d.ts rename to packages/applications/blog/src/ui/components/Contact/Contact.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Contact/Contact.tsx b/packages/applications/blog/src/ui/components/Contact/Contact.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Contact/Contact.tsx rename to packages/applications/blog/src/ui/components/Contact/Contact.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Counter/Counter.tsx b/packages/applications/blog/src/ui/components/Counter/Counter.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Counter/Counter.tsx rename to packages/applications/blog/src/ui/components/Counter/Counter.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/DecorationTag/DecorationTag.module.css b/packages/applications/blog/src/ui/components/DecorationTag/DecorationTag.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/DecorationTag/DecorationTag.module.css rename to packages/applications/blog/src/ui/components/DecorationTag/DecorationTag.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/DecorationTag/DecorationTag.module.css.d.ts b/packages/applications/blog/src/ui/components/DecorationTag/DecorationTag.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/DecorationTag/DecorationTag.module.css.d.ts rename to packages/applications/blog/src/ui/components/DecorationTag/DecorationTag.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/DecorationTag/DecorationTag.tsx b/packages/applications/blog/src/ui/components/DecorationTag/DecorationTag.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/DecorationTag/DecorationTag.tsx rename to packages/applications/blog/src/ui/components/DecorationTag/DecorationTag.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Divider/Divider.module.css b/packages/applications/blog/src/ui/components/Divider/Divider.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Divider/Divider.module.css rename to packages/applications/blog/src/ui/components/Divider/Divider.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Divider/Divider.module.css.d.ts b/packages/applications/blog/src/ui/components/Divider/Divider.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Divider/Divider.module.css.d.ts rename to packages/applications/blog/src/ui/components/Divider/Divider.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Divider/Divider.tsx b/packages/applications/blog/src/ui/components/Divider/Divider.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Divider/Divider.tsx rename to packages/applications/blog/src/ui/components/Divider/Divider.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Footer/Footer.module.css b/packages/applications/blog/src/ui/components/Footer/Footer.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Footer/Footer.module.css rename to packages/applications/blog/src/ui/components/Footer/Footer.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Footer/Footer.module.css.d.ts b/packages/applications/blog/src/ui/components/Footer/Footer.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Footer/Footer.module.css.d.ts rename to packages/applications/blog/src/ui/components/Footer/Footer.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Footer/Footer.tsx b/packages/applications/blog/src/ui/components/Footer/Footer.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Footer/Footer.tsx rename to packages/applications/blog/src/ui/components/Footer/Footer.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Header/Header.module.css b/packages/applications/blog/src/ui/components/Header/Header.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Header/Header.module.css rename to packages/applications/blog/src/ui/components/Header/Header.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Header/Header.module.css.d.ts b/packages/applications/blog/src/ui/components/Header/Header.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Header/Header.module.css.d.ts rename to packages/applications/blog/src/ui/components/Header/Header.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Header/Header.tsx b/packages/applications/blog/src/ui/components/Header/Header.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Header/Header.tsx rename to packages/applications/blog/src/ui/components/Header/Header.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Language/Language.module.css b/packages/applications/blog/src/ui/components/Language/Language.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Language/Language.module.css rename to packages/applications/blog/src/ui/components/Language/Language.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Language/Language.module.css.d.ts b/packages/applications/blog/src/ui/components/Language/Language.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Language/Language.module.css.d.ts rename to packages/applications/blog/src/ui/components/Language/Language.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Language/Language.tsx b/packages/applications/blog/src/ui/components/Language/Language.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Language/Language.tsx rename to packages/applications/blog/src/ui/components/Language/Language.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Layout/Layout.module.css b/packages/applications/blog/src/ui/components/Layout/Layout.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Layout/Layout.module.css rename to packages/applications/blog/src/ui/components/Layout/Layout.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Layout/Layout.module.css.d.ts b/packages/applications/blog/src/ui/components/Layout/Layout.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Layout/Layout.module.css.d.ts rename to packages/applications/blog/src/ui/components/Layout/Layout.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Layout/Layout.tsx b/packages/applications/blog/src/ui/components/Layout/Layout.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Layout/Layout.tsx rename to packages/applications/blog/src/ui/components/Layout/Layout.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Shell/shell.tsx b/packages/applications/blog/src/ui/components/Shell/shell.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Shell/shell.tsx rename to packages/applications/blog/src/ui/components/Shell/shell.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/ShinyaigeekAnimation/ShinyaigeekAnimation.tsx b/packages/applications/blog/src/ui/components/ShinyaigeekAnimation/ShinyaigeekAnimation.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/ShinyaigeekAnimation/ShinyaigeekAnimation.tsx rename to packages/applications/blog/src/ui/components/ShinyaigeekAnimation/ShinyaigeekAnimation.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css b/packages/applications/blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css rename to packages/applications/blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css.d.ts b/packages/applications/blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css.d.ts rename to packages/applications/blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.tsx b/packages/applications/blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.tsx rename to packages/applications/blog/src/ui/components/ShinyaigeekPortrait/ShinyaigeekPortrait.tsx diff --git a/packages/applications/turbo-blog/src/ui/components/Tag/Tag.module.css b/packages/applications/blog/src/ui/components/Tag/Tag.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Tag/Tag.module.css rename to packages/applications/blog/src/ui/components/Tag/Tag.module.css diff --git a/packages/applications/turbo-blog/src/ui/components/Tag/Tag.module.css.d.ts b/packages/applications/blog/src/ui/components/Tag/Tag.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Tag/Tag.module.css.d.ts rename to packages/applications/blog/src/ui/components/Tag/Tag.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/components/Tag/Tag.tsx b/packages/applications/blog/src/ui/components/Tag/Tag.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/components/Tag/Tag.tsx rename to packages/applications/blog/src/ui/components/Tag/Tag.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/Home.tsx b/packages/applications/blog/src/ui/pages/Home/Home.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/Home.tsx rename to packages/applications/blog/src/ui/pages/Home/Home.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css b/packages/applications/blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css rename to packages/applications/blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css.d.ts b/packages/applications/blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.tsx b/packages/applications/blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.tsx rename to packages/applications/blog/src/ui/pages/Home/components/FirstBoard/FirstBoard.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/Item/Item.module.css b/packages/applications/blog/src/ui/pages/Home/components/Item/Item.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/Item/Item.module.css rename to packages/applications/blog/src/ui/pages/Home/components/Item/Item.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/Item/Item.module.css.d.ts b/packages/applications/blog/src/ui/pages/Home/components/Item/Item.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/Item/Item.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Home/components/Item/Item.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/Item/Item.tsx b/packages/applications/blog/src/ui/pages/Home/components/Item/Item.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/Item/Item.tsx rename to packages/applications/blog/src/ui/pages/Home/components/Item/Item.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/StartStream/StarStream.module.css b/packages/applications/blog/src/ui/pages/Home/components/StartStream/StarStream.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/StartStream/StarStream.module.css rename to packages/applications/blog/src/ui/pages/Home/components/StartStream/StarStream.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/StartStream/StarStream.module.css.d.ts b/packages/applications/blog/src/ui/pages/Home/components/StartStream/StarStream.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/StartStream/StarStream.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Home/components/StartStream/StarStream.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/StartStream/StarStream.tsx b/packages/applications/blog/src/ui/pages/Home/components/StartStream/StarStream.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/StartStream/StarStream.tsx rename to packages/applications/blog/src/ui/pages/Home/components/StartStream/StarStream.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css b/packages/applications/blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css rename to packages/applications/blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css.d.ts b/packages/applications/blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.tsx b/packages/applications/blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.tsx rename to packages/applications/blog/src/ui/pages/Home/components/ThirdPirtyBlogItem/ThirdPirtyBlogItem.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/Post.module.css b/packages/applications/blog/src/ui/pages/Post/Post.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/Post.module.css rename to packages/applications/blog/src/ui/pages/Post/Post.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/Post.module.css.d.ts b/packages/applications/blog/src/ui/pages/Post/Post.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/Post.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Post/Post.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/Post.tsx b/packages/applications/blog/src/ui/pages/Post/Post.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/Post.tsx rename to packages/applications/blog/src/ui/pages/Post/Post.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/components/Anchor/Anchor.module.css b/packages/applications/blog/src/ui/pages/Post/components/Anchor/Anchor.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/components/Anchor/Anchor.module.css rename to packages/applications/blog/src/ui/pages/Post/components/Anchor/Anchor.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/components/Anchor/Anchor.module.css.d.ts b/packages/applications/blog/src/ui/pages/Post/components/Anchor/Anchor.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/components/Anchor/Anchor.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Post/components/Anchor/Anchor.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/components/Anchor/Anchor.tsx b/packages/applications/blog/src/ui/pages/Post/components/Anchor/Anchor.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/components/Anchor/Anchor.tsx rename to packages/applications/blog/src/ui/pages/Post/components/Anchor/Anchor.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css b/packages/applications/blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css rename to packages/applications/blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css.d.ts b/packages/applications/blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.tsx b/packages/applications/blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.tsx rename to packages/applications/blog/src/ui/pages/Post/components/PostMetaInfo/PostMetaInfo.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/Profile.module.css b/packages/applications/blog/src/ui/pages/Profile/Profile.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/Profile.module.css rename to packages/applications/blog/src/ui/pages/Profile/Profile.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/Profile.module.css.d.ts b/packages/applications/blog/src/ui/pages/Profile/Profile.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/Profile.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Profile/Profile.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/Profile.tsx b/packages/applications/blog/src/ui/pages/Profile/Profile.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/Profile.tsx rename to packages/applications/blog/src/ui/pages/Profile/Profile.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/Card/Card.module.css b/packages/applications/blog/src/ui/pages/Profile/components/Card/Card.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/Card/Card.module.css rename to packages/applications/blog/src/ui/pages/Profile/components/Card/Card.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/Card/Card.module.css.d.ts b/packages/applications/blog/src/ui/pages/Profile/components/Card/Card.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/Card/Card.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Profile/components/Card/Card.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/Card/Card.tsx b/packages/applications/blog/src/ui/pages/Profile/components/Card/Card.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/Card/Card.tsx rename to packages/applications/blog/src/ui/pages/Profile/components/Card/Card.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css b/packages/applications/blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css rename to packages/applications/blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css.d.ts b/packages/applications/blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalendar.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalender.tsx b/packages/applications/blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalender.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalender.tsx rename to packages/applications/blog/src/ui/pages/Profile/components/GitHubCalender/GitHubCalender.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css b/packages/applications/blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css rename to packages/applications/blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css.d.ts b/packages/applications/blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Profile/components/JobItem/JobItem.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/JobItem/JobItem.tsx b/packages/applications/blog/src/ui/pages/Profile/components/JobItem/JobItem.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/JobItem/JobItem.tsx rename to packages/applications/blog/src/ui/pages/Profile/components/JobItem/JobItem.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/Loading/Loading.module.css b/packages/applications/blog/src/ui/pages/Profile/components/Loading/Loading.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/Loading/Loading.module.css rename to packages/applications/blog/src/ui/pages/Profile/components/Loading/Loading.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/Loading/Loading.module.css.d.ts b/packages/applications/blog/src/ui/pages/Profile/components/Loading/Loading.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/Loading/Loading.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Profile/components/Loading/Loading.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/Loading/Loading.tsx b/packages/applications/blog/src/ui/pages/Profile/components/Loading/Loading.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/Loading/Loading.tsx rename to packages/applications/blog/src/ui/pages/Profile/components/Loading/Loading.tsx diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css b/packages/applications/blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css rename to packages/applications/blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css.d.ts b/packages/applications/blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css.d.ts similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css.d.ts rename to packages/applications/blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.module.css.d.ts diff --git a/packages/applications/turbo-blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.tsx b/packages/applications/blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.tsx similarity index 100% rename from packages/applications/turbo-blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.tsx rename to packages/applications/blog/src/ui/pages/Profile/components/ShinyaigeekCoreProfile/ShinyaigeekCoreProfile.tsx diff --git a/packages/applications/turbo-blog/src/universal/const.ts b/packages/applications/blog/src/universal/const.ts similarity index 100% rename from packages/applications/turbo-blog/src/universal/const.ts rename to packages/applications/blog/src/universal/const.ts diff --git a/packages/applications/turbo-blog/tsconfig.json b/packages/applications/blog/tsconfig.json similarity index 100% rename from packages/applications/turbo-blog/tsconfig.json rename to packages/applications/blog/tsconfig.json diff --git a/packages/applications/turbo-blog/webpack.config.client.ts b/packages/applications/blog/webpack.config.client.ts similarity index 100% rename from packages/applications/turbo-blog/webpack.config.client.ts rename to packages/applications/blog/webpack.config.client.ts diff --git a/packages/applications/turbo-blog/webpack.config.server.ts b/packages/applications/blog/webpack.config.server.ts similarity index 100% rename from packages/applications/turbo-blog/webpack.config.server.ts rename to packages/applications/blog/webpack.config.server.ts diff --git a/packages/applications/turbo-blog/src/articles/public/browser-on-browser.md b/packages/applications/turbo-blog/src/articles/public/browser-on-browser.md deleted file mode 100644 index 8339951a..00000000 --- a/packages/applications/turbo-blog/src/articles/public/browser-on-browser.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: ブラウザの上でブラウザを動かす -tags: [Programming, Rust, JavaScript, Web, Browser] -description: 自作ブラウザを実装した続きとして, Chrome ブラウザで自作ブラウザを動かす, ということをした際の学習ノートです. -publishedAt: 2021/12/10 -updatedAt: 2021/12/10 ---- - -## 初めに - -こんにちは, [しにゃい/Shinyaigeek](https://twitter.com/Shinyaigeek) です. - - -趣味でちまちまと作っていた自作ブラウザ [Shinyaic](https://github.com/shinyaigeek/shinyaic) を Chrome 上で動かすことができたので, それについて勉強ノートを書こうと思います. - -最初に, 実際に Chrome 上でどのように自作ブラウザが動いているかの様子を載せたいと思います. - -**`` の値が空の時は paint ボタンを押すとこちらで用意したHTML & CSSで描画される** - -![Shinyaic with default html](../../../assets/browser-on-browser/shinyaic.png) - -**example.com を入力に入れると, いい感じに描画される** - -![shinyaic with example.com](../../../assets/browser-on-browser/example.png) - -(実はそもそも自作ブラウザが開発途中で, example.comくらいしかまともに描画できませんがそこはご了承ください...) - -[Shinyaic Wasm Playground](https://shinyaic-wasm-playground.vercel.app/) から実際に Chrome ブラウザの上で自作ブラウザを動かすことができます. - -playground 自体のリポジトリは [https://github.com/Shinyaigeek/ShinyaicWasmPlayground](https://github.com/Shinyaigeek/ShinyaicWasmPlayground) です. - -また補足になるのですが, **ブラウザ** という言葉がどこまでを含むのか, についても先に決めておきたいと思います. 本稿ではブラウザは HTML や CSS を受け取って, それを元に描画するところ, ある種の HTML Rendering Engine とも言える部分をブラウザとして進めていきます. なので, JS Engine や HTTP 通信をする, といった部分は本稿の対象外となります. - -本稿ではこの自作ブラウザの実装についての詳細には触れるつもりがありません, 興味がある方は以下のスライドを見てくださると幸いです. - -[![](https://files.speakerdeck.com/presentations/f70e84d625ae44949d1a6f6a87909011/slide_0.jpg?19382839)](https://speakerdeck.com/shinyaigeek/burauzazuo-rifalsesu-me) - -## ブラウザの仕組み概略図 - -![browser system](/assets/browser-on-browser/sys.png) - -ブラウザの仕組みの概略図をおおまかに書くとこのようになっています. 本当は描画の処理はもう少し細かいんですし, ブラウザ固有の部分もあったりするのですがそこまで突っ込むと本題から外れてしまうため本稿では割愛します. - -まず HTML から DOM を構築, CSS から CSSOM を構築して, それらをもとに `RenderTree` を構築します. この `RenderTree` には描画に必要な情報が格納されます. DOM は **Document Object Model** という名の通り, HTML のマークアップの構造に基づいた情報が格納されています. 例えばこのノードはH1要素である...と言ったこと, あるいは `` 要素 や `` 要素など描画されるわけではない要素についてのノードも格納されています. 一方 `RenderTree` は描画に必要な情報のみが格納されるので, `display: none;` が付与されていたりあるいは `` 要素といった, 描画されない要素のノードは含まれません. また基本的にはそのノードが HTML における何タグであるか, といった情報も削げ落ちており, どんな Node であるか (Block か Inline か Scroll か etc...) か, そしてどんなスタイルが適応されるか, といった情報が格納されます. - - `RenderTree` を構築すれば, 次はそれを元に矩形情報を計算します. このノードがどれくらいの大きさで, どの位置に描画されるか, ということを計算して, それが完了すれば実際に描画処理を行います. - -## ブラウザ on ブラウザ - -このブラウザを動かすための処理のうち, 実際にブラウザ上で実行できる部分はシンプルなブラウザであれば意外に多いということに上のセクションで気付く方もいらっしゃるかと思います. - -HTML -> DOM にする処理や, `RenderTree` を構築する処理は OS のあれこれに依存している処理というわけではないので, 普通にブラウザ上のランタイムでも実行することができます. 今回は自作ブラウザを Rust で実装していたので, WASM へと compile した上でそれをブラウザで動かしていましたが, 普通に JavaScript で書けばそのまま動かすこともできます. - -単純に実装したブラウザがブラウザ上で動かすことが難しい主な箇所は, 描画処理と矩形情報を算出する処理となります. というのも僕の自作ブラウザや, 世の一般的なブラウザといったネイティブアプリが行う OS の低レイヤのAPIを用いて行われている描画処理をそのまま Web で行うってできなくない?となるのは至極当然のことと言えるでしょう. また矩形情報の算出も矩形情報を得るためにはこういった文をこのフォントサイズでこのフォントで描画するとどれくらいの幅, 高さをとるか, やあるいはどれくらいの window サイズで描画するか, といったことに依存してしまい, こうした処理も一筋縄ではいきません.(icedのように, for Web な出力もできるGUI Library for Native Appもありますが, 流石に即オチが過ぎるので今回はそれに頼りません) - -描画する処理, 矩形情報を算出する処理をブラウザ上で実行するために, これらの処理を for Web として [Canvas API](https://developer.mozilla.org/ja/docs/Web/API/Canvas_API) で行うよう実装できれば, Web上で, ブラウザ上で自作ブラウザを動かすことが可能なのでは? というのが本稿の概要であり, 今回の趣味開発(?)の原点発想となります. - -## nativeでの実装 - -僕の自作ブラウザでは, [iced](https://github.com/iced-rs/iced) という描画エンジンを利用しています. - -それありきで, 以下のような実装をしています (細かい実装は割愛しています). - -**textからそれがそのフォントでそのフォントサイズで描画されるとどれくらいの幅, 高さを取るか算出する処理** - -```rust -pub fn get_font_rendered_size(&self, width: f64, text: String) -> PaintFontRenderedRect { - let ctfont = self - .font - .native_font() - .clone_with_font_size(self.size as f64); - let font = ctfont.bounding_box(); - - // 細かい実装は割愛 - - PaintFontRenderedRect { - width: width, - height: height, - } -} -``` - -**RenderObject をもとに描画する処理** - -```rust -use iced_graphics::Primitive; - -fn create_block(render_object: RenderObject) -> Primitive { - Primitive::Quad { - ... - } -} - -fn create_text(render_object: RenderObject) -> Primitive { - Primitive::Text { - ... - } -} - -``` - -このように `RenderObject` をもとに, 矩形情報を計算しそれを元に `iced` の `Primitive` という単位に変換します. `create_block` では「この位置でこの大きさで, この背景色のブロック」というのを生成します. 同様に `create_text` では「この位置でこのフォントでこの文字」というのを生成します. - -これにより生成された `Primitive` を `iced` に食わせることによって実際にネイティブアプリとして描画することが実現されています. - -## Webでの実装 - -Web での実装では, これを Canvas API ベースのものに置き換えます. - -まず, `RenderTree` の構築処理までと Layout 処理の一部は, native で使われている実装と共通のものを使いまわせるので, それ以降の, - -* Layout処理におけるこの文をこのフォントで描画したときどれくらい幅, 高さをとるかの取得 -* 実際に描画する処理 - -をWebでも動くようにするために, Canvas APIによって実装します. - -* /core: RenderTreeの構築までと, 一部の句形情報算出のための処理 -* /native: nativeでの処理 -* /wasm: webでの処理 - -とpackageを分けて, native, wasm から core に依存する形で実装します. - -それありきで, Web で動かすための /wasm package では以下のような実装をしています. (細かい実装は割愛しています) - -**textからそれがそのフォントでそのフォントサイズで描画されるとどれくらいの幅, 高さを取るか算出する処理** - -```rust -pub fn get_font_rendered_size(&self, width: f64, text: String) -> PaintFontRenderedRect { - self.canvas_context.set_font(...); - let text_rect = canvas.measure_text(...).unwrap(); - let text_width = text_rect.width(); - let height = text_rect.actual_bounding_box_descent() + text_rect.actual_bounding_box_ascent(); - - // 割愛 - - PaintFontRenderedRect { - width: width, - height: height, - } -} -``` - -**RenderObject をもとに描画する処理** -```rust - -fn create_block(render_object: RenderObject, canvas_context: CanvasContext) -> Primitive { - canvas_context.set_fill_style(...); - canvas_context.fill_rect(...); -} - -fn create_text(render_object: RenderObject, canvas_context: CanvasContext) -> Primitive { - canvas.set_fill_style(...); - canvas.set_font(...); -} - -``` - -**web-sys** moduleから, Canvas APIにアクセスして, よしなに矩形情報の算出, 描画を行います. - -WASM から, このように HTML を入力にとり Canvas 上に描画するところまで実行することができました. やはり標準化されている仕様に則って当たり前のことを当たり前にすれば変な遊びもできてしまうので楽しいですね. - -## 終わりに - -本稿を通じて少しでも自作ブラウザ, 車輪の再発明って楽しそうだなと感じていただければ幸いです. また, 最近 OSS や卒論にかまけて開発が止まっていますが, 自作ブラウザ [Shinyaic](https://github.com/shinyaigeek/shinyaic) を見ていただいたり面白いと思ったなら star をつけてくださると励みになります! - -ブラウザの中でブラウザを動かせるようになったので, 次はブラウザの中でブラウザの中でブラウザを動かしたいと思います. diff --git a/packages/applications/turbo-blog/src/articles/public/composition-react-app-with-react-router.md b/packages/applications/turbo-blog/src/articles/public/composition-react-app-with-react-router.md deleted file mode 100644 index 967d8091..00000000 --- a/packages/applications/turbo-blog/src/articles/public/composition-react-app-with-react-router.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -title: Reactアプリ小さめ構成with react-router 編 -tags: [Programming, JavaScript, React] -description: | - この記事は前回の記事の続きという感じです。これまた初学者向け - [脱 create-react-app、React アプリの小さめ構築](https://www.shinyaigeek.com/p/22) - - この記事を読めば create-react-app なしで react アプリを構築できる様になるのですが、その続きとしてこの記事では react-router について扱おうと思います(開発していて思いの外どぶったので) - - react-router のエラー、割とありますよね. - ていうか公式の API なり Document なりがよくわからないって感じはします。 - なんかよくわからないけど 404 エラーが出たり、CANNOT GET URL みたいなエラーが出たり、僕もこれでどぶって、いい感じの日本語記事が見つからなかったのもあってじゃあ紹介しておこうかなという感じです。 -publishedAt: 2019/08/12 -updatedAt: 2019/08/12 ---- - -## はじめに - -この記事は前回の記事の続きという感じです。これまた初学者向け -[脱 create-react-app、React アプリの小さめ構築](https://www.shinyaigeek.com/p/22) - -この記事を読めば create-react-app なしで react アプリを構築できる様になるのですが、その続きとしてこの記事では react-router について扱おうと思います(開発していて思いの外どぶったので) - -react-router のエラー、割とありますよね. -ていうか公式の API なり Document なりがよくわからないって感じはします。 -なんかよくわからないけど 404 エラーが出たり、CANNOT GET URL みたいなエラーが出たり、僕もこれでどぶって、いい感じの日本語記事が見つからなかったのもあってじゃあ紹介しておこうかなという感じです。 - -## react-router とは - -react-router とは react でルーティングを実現してくれるというやつです。 -じゃあルーティングとは何か、この URL を渡されたらこんなのを表示して!!って教えこむことです。 - -例えば'なんちゃらなんちゃら/login'っていう URL ではログイン画面を見せたいじゃないですか、'なんちゃらなんちゃら/home'っていう URL ではホーム画面を見せたいじゃないですか、これを実現するお!!ってやつです。 - -英語読める人はここ読むと詳しくわかると思います。 -[REACT TRAINING/REACT ROUTER](https://reacttraining.com/react-router/web/guides/quick-start) - -## 導入 - -まずモジュールをインストールしましょう。 - -```TypeScript -npm install react-router-dom -``` - -でそれをインポートします。 - -```TypeScript -import { BrowserRouter, Route, Link, Switch, Redirect} from 'react-router-dom'; -``` - -この辺がよく使うやつですね。 -BrowserRouter は react-router-dom の親分めいたやつと言いますか、BrowserRouter のなかで Route や Link を使って行くという感じです。 -似た様なのに HashRouter と MemoryRouter,StaticRouter があります。 -MemoryRouter に関してはデバッグ用と言いますか、テストやクライアントサイドでない環境で遊びたい時に使うやつです(ほぼ使わないので忘れていいと思います)。 -StaticRouter については React をサーバーサイドレンダリングしたいときに使うやつです。だから Static っていう形容詞がついています。 -対照的に BrowserRouter ですとブラウザ上でのルーティングができます。ただこれは history API を採用していますのでレガシーな環境では利用できません。逆に HashRouter ですと URL hash を利用していますので環境の制限はありません。ただそのおかげで location.key や location.state はカバーされていません。 -長々と喋りましたが面倒くさい時は脳死で BrowserRouter で構いません。 - -書き方としては - -```TypeScript - -function Home(){ - return( -
ログインしました
- ) -} - -function Login(){ - return( -
ログインして下さい
- ) -} - -function Test(){ - return( -
- - Login - Home - - Login()} /> - Home()} /> - -
- ) -} -``` - -こんな感じでやれば取り敢えずの実装は出来ます。ただ色々と問題も生じます。 -例えば上の Route の path に引っかからない奴がでる(switch-case でいう default 的な)とき返す component を設定したい、あるいはそのときログイン画面へリダイレクトさせたい。 -あるいはこれをやったけど 404 エラーがでた、あるいは Cannot GET URL みたいなエラーがでたみたいなことがあると思います。以下でそれについて書いておこうかなと思います。 - -## Default を設定したい - -Route で引っ掛けるやつ以外の URL ではこのコンポーネントを表示させたい、あるいはリダイレクトさせたいってときのやつをここで紹介します。(要するにデフォルト設定) - -こんなときに役に立つのが Switch です。 - -以前のやつに加筆しますと - -```TypeScript -function Login(){ - 略 -} - -function Home() { - 略 -} - -function Default(){ - 略 -} - -function Test() { - return( -
- - Login - Home - - Login()} /> - Home()} /> - Default()} /> - - -
- ) -} -``` -これで/loginでも/homeでもないURLが渡されるとDefaultコンポーネントがレンダリングされます。 -でリダイレクトさせたいって時はRedirectを使います。 -この場合は上の -```TypeScript - Default()} /> -``` -を -```TypeScript - } /> -``` -って変えるだけ。これで/loginへとリダイレクトされていきます、やったね!! - -## Cannot GET URL エラーがでる -めっちゃ簡単です、webpack.config.jsの設定をほんのちょっと触るだけです。 - -```JavaScript -module.exports = { - 略 - devServer: { - historyApiFallback:true, - } -} -``` -webpackのdevServerにこれを加筆するだけです。 - -## 404エラーが出る -404エラーには2パターンあります、これにはブラウザ側で吐かれているエラーを確認してみて下さい。 -もし404になっているのがfavicon.icoでしたらそれはただのwebページのアイコンが見つからないよ!!っていうエラーです。この場合スルーして大丈夫です。 - -もし404になっているのがwebpackによってバンドルされた後の出力されたjsファイルでしたらそれはディレクトリミスです。 -相対パスで参照しているがために生じてしまったエラーです。 -この場合は -```JavaScript -module.exports = { - 略 - output: { - path: path.resolve(__dirname, '/dist/'), - publicPath: '/', - filename: 'bundle.js' - }, -} -``` -こんな感じにして絶対パスを指定してあげれば大丈夫です。 \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/eslint-plugin-for-orthographical-variants.md b/packages/applications/turbo-blog/src/articles/public/eslint-plugin-for-orthographical-variants.md deleted file mode 100644 index 5c0170fd..00000000 --- a/packages/applications/turbo-blog/src/articles/public/eslint-plugin-for-orthographical-variants.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: コードの表記揺れを縛るESLintプラグイン -tags: [Programming, JavaScript, DX, Frontend] -description: コードの表記揺れを縛るESLint Pluginを作ったので供養する. -publishedAt: 2022/03/15 -updatedAt: 2022/03/15 ---- - -## これは何 - -コードの表記揺れを縛るESLint Pluginを作った. 大体作り終えてテスト描いてる途中にいやコスト対効果が薄いなこれとなってしまい, 面白くもなければ技術的にすごくもない, かと言って便利というわけでもないいい感じに湿気る怪物を産んでしまったのでその供養. - -## plugin の概要 - -上述の通りコードの表記揺れを縛るESLint Pluginです. - -https://github.com/Shinyaigeek/eslint-plugin-ban-orthographical-variant - - -```json -{ - "Audio": { - "synonyms": ["Speech", "Music"] - }, - "Video": { - "synonyms": ["Movie", "TV Show", "Game", "Animation", "Documentary"] - }, - "Image": { - "synonyms": ["Photo", "Drawing", "Painting", "Photograph", "Illustration"] - } -} -``` - -こういう感じの辞書ファイルを用意しておくと, - -```javascript -const audioPath = "hoge"; // ok -const musicPath = "hoge"; // warning! -``` - -こういうJavaScript/TypeScriptにおけるコード中の表記ゆれを縛ってくれるESLint Pluginです. 縛る対象としては宣言可能なId的なやつほぼ全部で, -- 変数名 -- 関数名 -- class 名 -- メソッド名 -- enum 名 -- interface 名 -- etc... - -などなど, 多分大体網羅できてる気がします. - -## モチベーション - -コードの表記揺れ, 複数の手で作られるようなコードベースだとそこまで珍しいものでもないですが, 我々エンジニアという生き物は何事にも意味を見出そうとしてしまうため, 単なる表記揺れの意味を考えてしまったり, 地味に検索abilityも落ちるので辛いです. また事業ドメインの単語が, コードベース中だと別の言葉になってしまっている, と言ったこともたま〜によくあり, そうなると新しくプロジェクトに参画した人にとっては意味のわからない謎になってしまいます. - -そもそも事業ドメインの単語が多いと辛いよね, という話もあり, 辞書ファイルをみんなで管理している, と言った例も見かけます. これは辞書ファイルを管理するついでにこの表記揺れもしばれると嬉しいのでは, と思い作りました. - -## 仕組み - -わざわざ書くほどのものでもないですが, - -1. eslint の持つ AST 中の特定の Node にアクセスする -2. 変数名を取得する -3. 表記揺れチェック - - -という感じです. - -```typescript - VariableDeclarator(node) { - const identifier = node.id; - - const variableNames = getVariableNameFromBindingName(identifier); - - const dictionaryPath = getDictionaryPath(options[0].dictionaryPath); - const dictionary = getDictionary(dictionaryPath); - for (const variableName of variableNames) { - lintWithVariable( - variableName, - dictionary, - (originWord, synomsysWord) => - report({ - node, - messageId: "banOrthographicalVariant", - data: { - originWord, - synomsysWord, - }, - }) - ); - } - }, -``` - -上記のコードは一例ですが, VariableDeclarator (=変数宣言) の node にアクセスしています. - -VariableDeclarator のにおける `node.id` は - -- `Identifier` -```javascript -const hoge = "hoge"; -``` -- `ArrayPattern` -```javascript -const [hoge] = ["hoge"]; -``` -- `ObjectPattern` -```javascript -const { hoge } = { hoge: "hoge" }; -``` - -の3通り取り得ます. それぞれの場合においていい感じに変数名に当たるものを全て取得します. (`ObjectPattern` や `ArrayPattern` はネスとされていることもあるので再帰的に取得する必要があります) - -あとは辞書ファイルをロードして表記揺れかどうか判定するだけです. - -どんな感じに動いているかは, 僕の描きかけのテストを見てください. https://github.com/Shinyaigeek/eslint-plugin-ban-orthographical-variant/blob/main/src/__tests__/ban-orthographical-variant.test.ts - -## なぜいらないの? - -テストのためにmock用の辞書ファイル書いてたらそもそも辞書ファイル書きたくないことに気づいてしまった, やるならここをハックすべきだった気がする. \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/fatsify-header-with-raw-write-to-node-http-on-stream.md b/packages/applications/turbo-blog/src/articles/public/fatsify-header-with-raw-write-to-node-http-on-stream.md deleted file mode 100644 index d8cd04ca..00000000 --- a/packages/applications/turbo-blog/src/articles/public/fatsify-header-with-raw-write-to-node-http-on-stream.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: fastifyでstreamを配信する時生のnode/httpに書き込むとResponse Headerが書き込まれなくなる問題 -tags: [JavaScript,Nodejs, HTTP] -description: | - fastifyの `reply.header(key, value)` は header に書き込まれるべき key-value を呼び出されたタイミングで HTTP Response に書き込むのではなく, `res.send` のタイミングで書き込んでいます. - Stream を配信する際, `reply.raw.write` を呼び出してしまっていると Header は暗黙的に flush されてしまっており書き込めなくなってしまいます. - - workaroundとしては, `reply.raw.write` の前に `reply.raw.setHeader` を呼び出し header の書き込みを fastify に任せるのではなく自分で担ってしまいこれを回避するのが良さそう. -publishedAt: 2021/03/21 -updatedAt: 2021/03/21 ---- - -## TL:DR; - -fastifyの `reply.header(key, value)` は header に書き込まれるべき key-value を呼び出されたタイミングで HTTP Response に書き込むのではなく, `res.send` のタイミングで書き込んでいます. -Stream を配信する際, `reply.raw.write` を呼び出してしまっていると Header は暗黙的に flush されてしまっており書き込めなくなってしまいます. - -workaroundとしては, `reply.raw.write` の前に `reply.raw.setHeader` を呼び出し header の書き込みを fastify に任せるのではなく自分で担ってしまいこれを回避するのが良さそう. - -## どんな問題? - -小ネタです. - -[fastify](https://www.fastify.io/) を利用して stream を配信し, `reply.raw/write` で body の書き込みをしてしまうと, `reply.header()` で set した Header が反映されていないというエッジケースを踏んでいました. - -具体的な事例を挙げる(ここは飛ばしてもいいです)と, ReactDOM/server の renderToNodeStream を利用して stream を配信することで読み込み速度の向上を図っていました. -しかしその場合生成されるマークアップには `` が含まれていません. -`DOCTYPE` を指定することで, ブラウザがクオークモードで動作することを防ぐことができます. [[1]](#refer-1) -できることならばこの `DOCTYPE` も含めて配信したいですが, renderToNodeStream から返ってくる Readable Stream にこの String 値を書き込むのは当然厳しいため, workaraund的に node/http の response.write で DOCTYPE を書き込んでいました. -fastify だと `Reply.raw` で node の `http.ServerResponse` にアクセスし直接 header や body を書き込むことができます. [[2]](#refer-2) -一方 ETag や Cache-Control を書き込むために `Reply.headers()` を利用しますが, これで書き込んだはずの header field が反映されていないということが起きました. - -エッジケース of エッジケースという感じがしますね. - -再現レポは https://github.com/Shinyaigeek/test-fasity-header/blob/master/main.js ここで可能です, `/stream_prefix` にアクセスすると `res.header()` で set したはずの `Content-Type: text/html` が set されておらず text/plain として表示されることがわかります. これは直感に反しますね. -`/stream_prefix_raw` にアクセスすると, しっかり text/html として表示されることがわかります. -これと `/stream_prefix` との違いは Header の set を fastify に任せているか `node/http` にアクセスして自分でやってるかだけです. - -## なぜこんなことが生じているのか - -fastify が Response Header を書き込むタイミングが `reply.header()` が呼ばれたタイミングではなく, `reply.send(body)` が呼ばれ body が配信される直前であることに起因しています. - -https://github.com/fastify/fastify/blob/master/lib/reply.js#L222 (2021/3/21時点) - -```javascript -Reply.prototype.header = function (key, value) { - const _key = key.toLowerCase() - - // default the value to '' - value = value === undefined ? '' : value - - if (this[kReplyHeaders][_key] && _key === 'set-cookie') { - // https://tools.ietf.org/html/rfc7230#section-3.2.2 - if (typeof this[kReplyHeaders][_key] === 'string') { - this[kReplyHeaders][_key] = [this[kReplyHeaders][_key]] - } - if (Array.isArray(value)) { - Array.prototype.push.apply(this[kReplyHeaders][_key], value) - } else { - this[kReplyHeaders][_key].push(value) - } - } else { - this[kReplyHeaders][_key] = value - } - return this -} -``` - -fastify の `reply.header` の処理を見ると, これが呼ばれたタイミングで `http/ServerResponse` に書き込んでいるのではなく, `this[kReplyHeaders]` に格納しているということがわかります. - -ではどのタイミングで `http/ServerResponse` に書き込んでいるかというと, `reply.send` が呼ばれると `onSendHook` という関数が呼ばれます. その中でユーザー定義の hook 関数があればそれを呼び出した後, なければ直ちに `onSendEnd` という関数を呼びます. -その中で header や body の書き込みが行われます. - -https://github.com/fastify/fastify/blob/master/lib/reply.js#L391 -(見やすいように一部割愛しています) - -```javascript -function onSendEnd (reply, payload) { - const res = reply.raw - const req = reply.request - const statusCode = res.statusCode - - if (typeof payload.pipe === 'function') { - sendStream(payload, res, reply) - return - } - - reply[kReplySent] = true - - res.writeHead(statusCode, reply[kReplyHeaders]) - - res.end(payload, null, null) -} -``` - -payload が stream であるときはそれを `sendStream` に引き渡し, そうでないときは `reply.header()` で書き込んだ `kreplyHeaders` を元に Header を書き込んでから payload を配信していることがわかります. -stream でないときは Header が書き込まれるのは `reply.header()` が呼ばれたタイミングではなく payload が配信される直前であることがわかりました. - -では `sendStream` の処理ものぞいてみましょう. - -https://github.com/fastify/fastify/blob/master/lib/reply.js#L444 -(見やすいように一部割愛しています) - -```javascript -function sendStream (payload, res, reply) { - - if (!res.headersSent) { - for (const key in reply[kReplyHeaders]) { - res.setHeader(key, reply[kReplyHeaders][key]) - } - } - payload.pipe(res) -} -``` - -`res.headersSent` が false であれば Headerを書き込んでから, そうでなければ直ちに stream である payload に `http/ServerResponse` を pipe することで stream を配信しています. - -ここまで書けば大体の人がお気づきかと思いますが, 冒頭の - -> [fastify](https://www.fastify.io/) を利用して stream を配信し, `reply.raw/write` で body の書き込みをしてしまうと, `reply.header()` で set した Header が反映されていないというエッジケースを踏んでいました. - -の問題は `res.headersSent` が true なため生じていました. - -なぜそうなるかというと, `reply.raw` から `http/ServerResponse` にアクセスし, `reply.raw.write` を呼び出して body を書き込んでしまうと Header は暗黙的に flush されてしまい書き込めなくなってしまいます, Header -> Body であることを考えるとある種当たり前のことですね. [[3]](#refer-3) - -## 解決策 - -fastify にPRを出すという形での根本的な解決を図るアプローチは思いつかず, workaround 的に `reply.send`, `reply.raw.write` を呼び出す前に `reply.raw.setHeader` から Header を書き込んでしまうというので解決できました. -ただこの方法だとheaderをfastifyが内部的にキャッシュしてくれなくなるのがちょっと辛い... -(ちょっと辛いからなんとかしたい...) - -```javascript - -app.get("/", (req, res) => { - const stream = getMarkupStream(); - - // res.header("hoge", "asdf") - res.raw.setHeader("hoge", "asdf"); - - res.raw.write(""); - - res.send(stream); -}) - -``` - -## 終わりに - -マサカリ待ってます :pray: - -## 参考 - -*

\[1] Page lacks the HTML doctype, thus triggering quirks mode (https://web.dev/doctype/) 閲覧日: 2020/3/21

-*

\[2] Fastify Docs Reply .raw (https://www.fastify.io/docs/latest/Reply/#raw) 閲覧日: 2020/3/21

-*

\[3] node http ServerResponse write (https://nodejs.org/api/http.html#http_response_write_chunk_encoding_callback) 閲覧日: 2020/3/21

\ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/how-to-make-economic-ssr-with-clourflareworker.md b/packages/applications/turbo-blog/src/articles/public/how-to-make-economic-ssr-with-clourflareworker.md deleted file mode 100644 index 6381f9ca..00000000 --- a/packages/applications/turbo-blog/src/articles/public/how-to-make-economic-ssr-with-clourflareworker.md +++ /dev/null @@ -1,246 +0,0 @@ ---- -title: cloud flare workerで省エネSSRなBlogを目指す -tags: [Blog,Programming, Web] -description: | - 世は技術ブログ大時代. みんなはてなブログか[JAMstack](https://jamstack.org/)にその身を委ねていた. お手軽さを求めるならはてなブログ, あるいはそこにカスタマイズ性やスピードを求めてHeadlessCMSにコンテンツを追加して動的に静的サイトを更新していくJAMstackな構成を目指した. 実際今の時代, GatsbyjsなりNextjsでもcontentfulなどを組み込んだJAMstackのテンプレートがあるので, HeadlessCMSからAPIを取得して環境変数として設定して, 適切にCI/CDを組んであげればもうJAMstackによる高速でお手軽な技術ブログが完成します. すごい時代だ.でもそんな中, あえてSSRを用いた動的な構成にロマンを感じ動的なブログを構築しようとした男がいました, いや僕なんですけど. cloud runでNode.jsの上にexpressサーバーを生やして, そこでJSXをreact-domを通してhtmlにしています. - - しかし一回のアクセスごとにexpressが立ち上がると時間がかかる(特にTTFB), そもそも従量課金制なのでアクセスのたびにサーバーを立ち上げるのでなく, 出来るだけキャッシュを効かせたい. 特にこの場合本質となるブログ記事はCMS上にあるのでそこを参照したい. - - というのを叶えたく, edge-sideでスクリプトを動かしてキャッシュを動的に管理して更なる最適化を目指す, という取り組みをしてみます. -publishedAt: 2020/04/13 -updatedAt: 2020/04/13 ---- - -## はじめに - -世は技術ブログ大時代. みんなはてなブログか[JAMstack](https://jamstack.org/)にその身を委ねていた. お手軽さを求めるならはてなブログ, あるいはそこにカスタマイズ性やスピードを求めてHeadlessCMSにコンテンツを追加して動的に静的サイトを更新していくJAMstackな構成を目指した. 実際今の時代, GatsbyjsなりNextjsでもcontentfulなどを組み込んだJAMstackのテンプレートがあるので, HeadlessCMSからAPIを取得して環境変数として設定して, 適切にCI/CDを組んであげればもうJAMstackによる高速でお手軽な技術ブログが完成します. すごい時代だ.でもそんな中, あえてSSRを用いた動的な構成にロマンを感じて動的なブログを構築しようとした男がいました, いや僕なんですけど. cloud runでNode.jsの上にexpressサーバーを生やして, そこでJSXをreact-domを通してhtmlにしています. - -しかし一回のアクセスごとにexpressが立ち上がると時間がかかる(特にTTFB), そもそも従量課金制なのでアクセスのたびにサーバーを立ち上げるのでなく, 出来るだけキャッシュを効かせたい. 特にこの場合本質となるブログ記事はCMS上にあるのでそこを参照したい. - -というのを叶えたく, edge-sideでスクリプトを動かしてキャッシュを動的に管理して更なる最適化を目指す, という取り組みをしてみます. - -## Cloud flareってなんぞ - -一言で言い難いのですが, めちゃ簡単に使えるリバースプロキシを利用したCDNサービスとしておきましょう. サービスとしてはそこだけではないのですが, -* この記事ではCDN, リバースプロキシとして利用している -* 説明がしんどい, 記事の本質でない - -というのがありますので詳細は省かせてもらいます. 詳しく知りたい方は公式のwebページを参照してください. - -サーバーから配信される内容をCDNにキャッシュしておくことで, サーバーの負担を減らす, 帯域を減らしてパフォーマンス向上が図れたりします. コンテンツの配信元と, クライエントとなるブラウザの物理的距離が小さくなることも魅力です. え, そんなの影響する?と思うかもしれませんが, 適当に海外のカフェとかの個人webサイトとかを覗いてもらえば物理的距離の影響が見えると思います, CDNはこれを解消する一助になりますね. - -ちなみにですがJAMstack構成でブログ作っている人は, cloud flareにそのweb serverを登録するだけでその恩恵がかなり受けられます. 個人のweb siteなら無料で利用できますし, かなりお手軽に登録できるのでやってみてください. - -## cloudflare workerって何? - -そもそもCloudflare workerとはなんなんでしょう? ついさっき - -> ちなみにですがJAMstack構成でブログ作っている人は, Cloud flareにそのweb serverを登録するだけでその恩恵がかなり受けられます. - -といっていますが, 実はこれだけで僕のこのブログの動的な構成でも全然恩恵を受けることができます. -そもそもedge-sideを介すことでどんなことがおきてるかというと, - -![how-works-cdn](//images.ctfassets.net/6ib5avrqb1b0/3Me2xX0XcsXmpJzhWo0hCM/31f64cdc0e36942bad76d0b23ac7acf2/IMG_82073C6538F5-1.jpeg) - -こんな感じで, -1. clientからReqestが飛ぶ -2. Edge-serverでそれを受け取りキャッシュを見る -3. そのキャッシュされた内容をクライエントに返していいかどうかserverに確認しにいく -4. OKと返ってくる -5. キャッシュされた内容をクライエントに返す - - -みたいなことがおきています(といってもこの流れは過度に一般化されていて, もちろん状況によって分岐は生じますが) - -でもこれだとclientからアクセスが飛ぶたびにCloudRunが立ち上がってしまいます. いちいちサーバーを建ててhtmlを生成しても時間が勿体無いですし, 何よりお金がかかります. - -そもそも本質となるブログ記事はCMS上にあるので, キャッシュされているコンテンツをそのまま返していいか判定したければ, そもそもCMSだけ覗けば十分なはずです. - -これを可能にするのがcloudflareでservice worker的な, scriptを動かしてキャッシュを制御するcloud flare workerです. - -因みにJSだけでなくRustやCも動かす事が出来ます. - -## cloudflare workerを動かしてみる - -といってもやることは至極単純です. - -1. CMSから記事の更新状況をfetchしてくる -2. その結果をみてキャッシュされているコンテンツが最新のものか判断する -3. 最新のものだったらキャッシュされているコンテンツをクライエントに返す, 最新のものでなかったらCMS上のデータをもとにhtmlを生成してクライエントに返す, そしてそのhtmlとcmsから取ってきたデータをキャッシュしておく - -という感じです. - -まずcloudflare workerを編集するために**wrangler**を導入しましょう. - -```shell -npm i @cloudflare/wrangler -g -``` - -で**wrangler**をグローバルインストールします. - -で次にworkerのcodeを置いておきたいディレクトリで - -```shell -wrangler generate my-router-app -``` - -を実行してセットアップします. - -生成されるpackage.jsonをみてもらえれば分かる通り, mainとなるcodeは**index.js**ですので, そこのファイルが書き換える対象です. - -そこでは**fetch**に対するイベントリスナーとそのハンドラが生えています. -なのでがっつり触るべきはハンドラですね. -因みに初期のものから触っていなければ, - -```javascript -event.respondWith(handleRequest(event)) -``` - -としていますので, ハンドラとなるhandleRequestのなかで - -```javascript -return Response -``` - -という体になっていれば大丈夫です. - -因みにですが**wrangler**を使っていれば - -```shell -wrangler publish // publishされる - -wrangler preview --watch // dev-serverを建てる(HRM付き) -``` - -という感じです. - -## Routing - -まずこの場合(僕のブログ), 動的なスクリプトを効かせたいのは**https://~~~/index.html**だけです. このように, このメソッドだったらこういうハンドラで, このpathだったらこのハンドラでというのも勿論あるでしょう. -そのためにRoutingは不可欠ですね. - -といってもcloudflare workerの場合Routingはかなり原始的にする必要があり, - -```javascript -const url = new URL(event.request.url); -``` -でurlを取れるので, **url.method**でメソッドを取って, **url.pathname**でpathを取って, switch文で頑張りましょう. - -e.g. - -```javascript - -const handleRequest = (event) => { - const url = new URL(event.request.url) - - switch(url.method) { - case "GET": { - // handleGETMethod - break; - } - case "POST": { - // handlePOSTMethod - break - } - default: { - // asdf - break - } - } -} - -``` - -## Cache API - -**Cache API** を用いてキャッシュを制御します. 仰々しく聞こえますが, そんなややこしいことをする感じでもありません. そもそも利用可能なCacheに生えているメソッドはput, match, deleteだけです. -その内容も直感的に分かる通り - -* putでキャッシュする -* deleteで消す -* matchでキャッシュを探す - -という感じです. -引数も単純で例えばputは**put(Request, Response)**です. 因みにworker文脈でのRequestはstring値も受け取れます. 察しのいい人は気付いちゃうと思いますがなんか**Request**をkeyと見なせば**Map**っぽさが出てきますね. -matchについては**match(Request, options)**で該当Requestに対してキャッシュがあればそのキャッシュの**Response**を, なければ**undefined**を返します. optionについては割愛. -deleteについては**delete(Request, options)**で該当Requestに対してキャッシュがあればそのキャッシュを削除するという感じです. - -また**put**や**delete**を利用する時は, **event.waitUntil**で, putやdeleteが完了する前にサーバーが落ちないように制御しましょう. サーバーレス感があります -. -因みにCache APIのdocsはここにあります[https://developers.cloudflare.com/workers/reference/apis/cache/](https://developers.cloudflare.com/workers/reference/apis/cache/). - -またPreview modeについてはCacheAPIは未実装でまだ使えないっぽいので, 何度cache.putしてもキャッシュされていないという事態が起こります.注意してください(僕はここがわからず30分くらい溶かしました) - -因みに以下のtemplateではCache APIが実際にどう使われてるかのexampleがみれます. [https://developers.cloudflare.com/workers/templates/pages/cache_api/](https://developers.cloudflare.com/workers/templates/pages/cache_api/) - -## やっていき - -さあ材料はだいたい揃ったのでやっていきましょう. -といってもやることは本当に単純です. - -まず僕の場合, HeadlessCMSのcontentfulを使ってブログ記事を管理しています. -contentfulだと以下のAPIが生えているので, [https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/authentication](https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/authentication), あとはtokenを取って**fetch**でブログコンテンツを参照する準備をします. - -以下はかなり事例レベルでfittingされてる話なのであまり参考にならないと思いますが, 実装としては - -```javascript - -const handleRequest = (event) => { - - const cache = caches.default; - - switch(url.pathname){ - case "/": { - // 基本/index.htmlのみ動的にキャッシュを制御する, それ以外は適当に普通にキャッシュしとけばOK - - // CMS上にある最新のコンテンツのための一覧を得る - const res = await fetch("https://~~~~~~~contentfulのAPI~~~~~/"); - - const cachedRes = await cache.match("jsonのkey", options); - - const curJson = await res.json(); - if(cachedRes){ - const cachedJson = cachedRes.json(); - - // 手元にあるjsonによる, 過去取得してキャッシュしたコンテンツにまつわる一覧のデータを, CMS上にある最新のそれとが一致する時 - if(JSON.stringify(cachedJson) === JSON.stringify(curJson)) { - return await cache.match("htmlのkey"); - }else{ - // この時はキャッシュされているものが古い - - e// 最新のコンテンツにまつわるjsonをキャッシュする - vent.waitUntil(cache.put("jsonのkey", cachedRes.clone())); - - } // 最新のコンテンツにまつわるjsonをサーバーに投げてhtmlを生成してもらう - const curHTMLRes = await fetch("~~~serverのurl, この場合cloud run~~~", { - method: "PUT", - body: JSON.stringify({ - item: curJson - }) - }) - - event.waitUntil(cache.put("htmlのkey", curHTMLRes.clone())); - return curHTMLRes; - - - } - default: { - break - } - } -} -``` - - -みたいな感じです. - -正直上のコードを見たところで得られるものは少なく, 参考にもならないと思いますがcloudflare workerを用いてCacheを動的に最適化するということがそこまで難解なことでもなく, それ自体は単純で見慣れたものであるというのは伝わったかと思います. - -完全に余談ですが, 僕的にはserverにhtmlを生成してもらうためだけにRequest投げるのは勿体無いんじゃないかなって思っていて, それをなんとかedge-sideでできないかなと考えています. -wrangler自体はwebpackでbundleさせることができるので, 理論上react-dom/serverくらいなら動くんじゃないかなとは思っています. -今は忙しいのでやらないですが, 気が向いたら実験しては見ます... - -因みにですが僕はこの最適化でSpeedIndexが**15%**削減されました.みんなもやってみてね - - - diff --git a/packages/applications/turbo-blog/src/articles/public/introduction-to-AST.md b/packages/applications/turbo-blog/src/articles/public/introduction-to-AST.md deleted file mode 100644 index 89cf0f36..00000000 --- a/packages/applications/turbo-blog/src/articles/public/introduction-to-AST.md +++ /dev/null @@ -1,560 +0,0 @@ ---- -title: ASTで僕の考えた最強のDXを実現する 〜自分のDXは自分で守っていけ〜 -tags: [JavaScript,AST] -description: | - ASTイジイジするのはいいぞ!! - * 難しくない - * 自分のDXを自分で守るというエキサイティングな体験ができる - * 触れる範囲が広がる - * プログラミングをやる限りお世話になる - - と良いことづくめで最高なので布教したい - - また, このブログは [https://docs.google.com/presentation/d/1Ykka2_NvseClPO2J_oFqRUb_sD6rZfYBU-XWnsdTn9U/edit?usp=sharing](https://docs.google.com/presentation/d/1Ykka2_NvseClPO2J_oFqRUb_sD6rZfYBU-XWnsdTn9U/edit?usp=sharing) の補助資料です. まあこの記事の方を読めば大丈夫です大丈夫です. -publishedAt: 2020/09/12 -updatedAt: 2020/09/12 ---- - -## TL;DR - -ASTイジイジするのはいいぞ!! -* 難しくない -* 自分のDXを自分で守るというエキサイティングな体験ができる -* 触れる範囲が広がる -* プログラミングをやる限りお世話になる - -と良いことづくめで最高なので布教したい - -また, このブログは [https://docs.google.com/presentation/d/1Ykka2_NvseClPO2J_oFqRUb_sD6rZfYBU-XWnsdTn9U/edit?usp=sharing](https://docs.google.com/presentation/d/1Ykka2_NvseClPO2J_oFqRUb_sD6rZfYBU-XWnsdTn9U/edit?usp=sharing) の補助資料です. まあこの記事の方を読めば大丈夫です大丈夫です. - -## AST とは - -ASTとは **A**bstract **S**ntax **T**ree の略です. 日本語でいうと **抽象構文木** というやつです. -**Tree** とあるように, プログラムの文法構造を **Tree** 構造で表現したものになります. -Tree 構造なので, それぞれのプログラムの節々を **Node** と言います. - -```javascript - -if( hoge === "bar" ) { - foga(); -} - -``` - -例えばですが, 上記のコードの AST はどのようなものになるか見てみましょう. - -![ast](/assets/introduction-to-AST/ast-tree.png) - -if文を分解してみましょう. -if文は「もし〜〜なら、〜〜する」ということを記述できますね。 -コードを見てみると、「もし hoge が "bar" という string literal 値だったら, fuga という関数を引数なしで実行する」という感じですね. -AST上だと、まず `ifStatement` という Node が登場します. -そして, その `if` の子の Node として, `if` 文の「条件式」や, その「条件を満たす時に実行される処理」が入ります。 -そして条件式の中を見ていきましょう. -条件式の中は、まず `Binary Expression` という Node が登場します. これは二項演算式で, 二つの値を比較したり, ということをしているということがわかりますね(図では簡略のため省略しています) -で, `Binary Expression` で具体的に何をしているかという話になるのですが, -* 等しいかどうか -* `hoge` という変数 -* "bar" という string literal値 - -ということになりますね. - -このブログ(発表)では, ASTをイジイジするアプローチから code に対して介入し何らかの mutation を行なっていくプロセスを解説していきます. - -## ASTが使われているもの - -![ast-tool](/assets/introduction-to-AST/ast-tool.png) - -JSでいえば, babel, eslint, prettier, webpack, などなど, 私たちの開発者体験を潤す様々なツールがASTを用いています. - -僕はJSばかり書いているのでJSの例しか出せませんが, エンジニアがプログラムを扱う以上, ほぼほぼ必ずどこかでお世話になっているといっても過言はないはずです. - -## ASTでコードをいじいじするときのあれこれ - -![ast-process](/assets/introduction-to-AST/ast-overview.png) - -大まかに分けて以下の三つのプロセスがあります。 -* parse: JS -> AST -* transform: transform AST -* unparse: AST -> JS - -`parse` の段階で, JavaScriptのソースコードを AST へと変換します. -`transform` の段階で, AST の中身を弄っていきます. -そして最後に `unparse` の段階で transform された AST を JavaScript のソースコードへと変換してくれます. - -![ast_process2](/assets/introduction-to-AST/transform.png) - -また, 多くの場合先人の弛まぬ努力のおかげで, `parse`, `unparse` についてはライブラリがほぼほぼ担ってくれていて, 実装者がこのプロセスについて考えることは少ないです. - -では実際に `parse` と `unparse` だけ試してみましょう. - -## ASTを試してみる - -次のコードを試してみましょう。実行環境は Node.js 上です. - -```javascript -const { parse } = require("@babel/parser"); - -const code = ` -if(hoge === "bar") { - fuga(); -} -` - -// JSをASTにparseする -const ast = parser(code); - -console.dir(ast, { depth: null }); -``` - -するとこんな出力が出ると思います。(隅から隅まで読まなくても大丈夫です) - -```javascript -Node { - type: 'File', - start: 0, - end: 34, - loc: SourceLocation { - start: Position { line: 1, column: 0 }, - end: Position { line: 5, column: 0 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - errors: [], - program: Node { - type: 'Program', - start: 0, - end: 34, - loc: SourceLocation { - start: Position { line: 1, column: 0 }, - end: Position { line: 5, column: 0 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - sourceType: 'script', - interpreter: null, - body: [ - Node { - type: 'IfStatement', - start: 1, - end: 33, - loc: SourceLocation { - start: Position { line: 2, column: 0 }, - end: Position { line: 4, column: 1 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - test: Node { - type: 'BinaryExpression', - start: 4, - end: 18, - loc: SourceLocation { - start: Position { line: 2, column: 3 }, - end: Position { line: 2, column: 17 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - left: Node { - type: 'Identifier', - start: 4, - end: 8, - loc: SourceLocation { - start: Position { line: 2, column: 3 }, - end: Position { line: 2, column: 7 }, - filename: undefined, - identifierName: 'hoge' - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - name: 'hoge' - }, - operator: '===', - right: Node { - type: 'StringLiteral', - start: 13, - end: 18, - loc: SourceLocation { - start: Position { line: 2, column: 12 }, - end: Position { line: 2, column: 17 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: { rawValue: 'bar', raw: '"bar"' }, - value: 'bar' - } - }, - consequent: Node { - type: 'BlockStatement', - start: 20, - end: 33, - loc: SourceLocation { - start: Position { line: 2, column: 19 }, - end: Position { line: 4, column: 1 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - body: [ - Node { - type: 'ExpressionStatement', - start: 24, - end: 31, - loc: SourceLocation { - start: Position { line: 3, column: 2 }, - end: Position { line: 3, column: 9 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - expression: Node { - type: 'CallExpression', - start: 24, - end: 30, - loc: SourceLocation { - start: Position { line: 3, column: 2 }, - end: Position { line: 3, column: 8 }, - filename: undefined, - identifierName: undefined - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - callee: Node { - type: 'Identifier', - start: 24, - end: 28, - loc: SourceLocation { - start: Position { line: 3, column: 2 }, - end: Position { line: 3, column: 6 }, - filename: undefined, - identifierName: 'fuga' - }, - range: undefined, - leadingComments: undefined, - trailingComments: undefined, - innerComments: undefined, - extra: undefined, - name: 'fuga' - }, - arguments: [] - } - } - ], - directives: [] - }, - alternate: null - } - ], - directives: [] - }, - comments: [] -} -``` - -確かに, `ifStatement` のなかに, `test` (図で言うところの条件) があり, さらに `consequent` (図で言うところのthen) があり, `test` の中に `BinaryExpression` (図で言うところの二項演算子) があって, となっていることを確認できると思います. - -ライブラリに乗っかるだけで, JavaScriptのソースコードを AST へと簡単に `parse` できたのが体感できたと思います. - -次に `unparse` もやってみましょう. -先ほどのコードを次のように書き換えてみてください. - -```javascript -const { parse } = require("@babel/parser"); -const { default: generate } = require("@babel/generator"); - -const code = ` -if(hoge === "bar") { - fuga(); -} -` - -const ast = parser(code); - -// ASTをJSへとunparseする -const { code: output } = generate(ast); - -console.log(output) - -``` - -```javascript -if (hoge === "bar") { - fuga(); -} -``` - -このような, 入力したcodeと全く同じcodeが出力されたと思います. 簡単ですね. - -では次に実際にコードをいじいじしてみましょう. - -今回は簡単に, 変数を全部絵文字にしてくれる君を作ってみます. - -今回やりたいことの下準備として, 以下のようなclassを用意してください. -これはtextを渡すと絵文字に変換してくれる君です. -以前変換したことのあるtextを渡すと, そのときの絵文字を返してくれるようにしています. -このコード自体はこのブログの本旨から外れるので読む必要はないです. - -```javascript - -class Text2Emoji { - emojis; - textMap; - baseNumber; - idx; - - constructor(props) { - if(props.emojis.length < 1) { - throw new Error("emojis should be more than 1") - } - this.emojis = props.emojis; - this.textMap = new Map(); - this.textMap.set(); - this.baseNumber = this.emojis.length; - this.idx = 0; - } - - convert(text) { - if (this._isRegistered(text)) { - return this.textMap.get(text); - } - - const emoji = this._num2Emoji(this.idx); - this.idx += 1; - this.textMap.set(text, emoji); - return emoji; - - } - - _isRegistered(text) { - return !!this.textMap.get(text); - } - - _num2Emoji(num) { - const convertedNum = num.toString(this.baseNumber).split(""); - const key = convertedNum.map((el) => this.emojis[el]).join(""); - return key - } -} - -module.exports = { - Text2Emoji -} - -``` - -では, `transform` の部分のコードを書いていきましょう. -まずこのコードを実行してみてください. - -```javascript -const { parse } = require("@babel/parser"); -const { default: generate } = require("@babel/generator"); -// transform に必要な @babel/traverse をimport -const { default: traverse } = require("@babel/traverse"); - -// いじいじする対象のコード -const code = ` -const NAME = "Shinyaigeek"; -const JOB = "frontend engineer"; -const INTERESTS = ["web performance", "AST", "Usability"] -const AGE= 21; - -const hey = () => { - return \`Hi!! there!! My name is \${NAME}. I'm \${JOB}. I'm \${AGE} years old.My interests are \${INTERESTS.map(interest => interest + "/")}\` -} - -console.log(hey()); -` - -const ast = parser(code); - -const visitor = {}; - -// ASTを走査して, 特定Nodeについて処理を行う -traverse(ast, visitor); - -const { code: output } = generate(ast); - -console.log(output) -``` - -そうすると, さっき実行したJavaScriptと同じ出力がされたと思います. -`transform` で, astに対して破壊的変更を行い, その結果のASTを `generate` 関数に渡すのですが, 今回は変換の処理を何もしていません. - -次に変換の処理を書いていきます. - -`@babel/traverse` だと, visitor patternを採用しています. -visitor patternと言うのは, 走査対象の特定部分に **訪問** していく `visitor object` に処理を記述して, その処理を特定部分で実行していく, と言うパターンのことです. -テレビの集金を例に出すと, あるテレビ局の電波を受診している家庭に, 取り立て人が **訪問** して, 料金を取り立てると言う **処理** を実行していくと言うことになりますね. -取り立て人は, テレビ局の電波を受診していない家庭では取り立てと言う **処理** は実行しないですね. - -百聞は一見にしかずということで, 早速実際にコードを書いて試していきましょう. -次のコードを実行してみてください. - -```javascript -const { parse } = require("@babel/parser"); -const { default: generate } = require("@babel/generator"); -const { default: traverse } = require("@babel/traverse"); - -const code = ` -const NAME = "Shinyaigeek"; -const JOB = "frontend engineer"; -const INTERESTS = ["web performance", "AST", "Usability"] -const AGE= 21; - -const hey = () => { - return \`Hi!! there!! My name is \${NAME}. I'm \${JOB}. I'm \${AGE} years old.My interests are \${INTERESTS.map(interest => interest + "/")}\` -} - -console.log(hey()); -` - -const ast = parse(code); - -const { code: output } = generate(ast); - -// visitor patternを書き込んでいく -const visitor = { - // Identifier に訪問する visitor オブジェクト - Identifier(nodePath) { - // visitor objectで行う処理 - console.log(nodePath.node.type + ": " + nodePath.node.name) - } -}; - -traverse(ast, visitor); -``` - -すると次のような出力が出ると思います. - -```shell -Identifier: NAME -Identifier: JOB -Identifier: INTERESTS -Identifier: AGE -Identifier: hey -Identifier: NAME -Identifier: JOB -Identifier: AGE -Identifier: INTERESTS -Identifier: map -Identifier: interest -Identifier: interest -Identifier: console -Identifier: log -Identifier: hey -``` - -これで全ての識別子に **訪問** して, その識別子の名前をlogで出力しているというのがわかりますね. -次に, log に出すだけではなく, 実際に AST の transform を行なっていきましょう. - -次のコードを実行してみてください. - -```javascript -const { parse } = require("@babel/parser"); -const { default: generate } = require("@babel/generator"); -const { default: traverse } = require("@babel/traverse"); -const { Text2Emoji } = require("./Text2Emoji"); - -// textを絵文字にしてくれる君 -const converter = new Text2Emoji({ - emojis: ["🐈", "🦍", "🐵", "🐶"] -}) - -const code = ` -const NAME = "Shinyaigeek"; -const JOB = "frontend engineer"; -const INTERESTS = ["web performance", "AST", "Usability"] -const AGE= 21; - -const hey = () => { - return \`Hi!! there!! My name is \${NAME}. I'm \${JOB}. I'm \${AGE} years old.My interests are \${INTERESTS.map(interest => interest + "/")}\` -} - -console.log(hey()); -` - -const ast = parse(code); - -const { code: output } = generate(ast); - -const visitor = { - Identifier(nodePath) { - // visitor objectで行う処理 - // 識別子の名前を絵文字にする - const emoji = converter.convert(nodePath.node.name); - // 訪問した識別子を, 名前が絵文字になった識別子に置き換える - nodePath.replaceWith( - identifier(emoji) - ) - // 名前がすでに絵文字になった識別子を再度訪問しないように, skip する - nodePath.skip(); - } -}; - -traverse(ast, visitor); - -const { code: output } = generate(ast) -console.log(output); -``` - -するとこのような出力が出たと思います. - -```javascript -const 🐈 = "Shinyaigeek"; -const 🦍 = "frontend engineer"; -const 🐵 = ["web performance", "AST", "Usability"]; -const 🐶 = 21; - -const 🦍🐈 = () => { - return `Hi!! there!! My name is ${🐈}. I'm ${🦍}. I'm ${🐶} years old.My interests are ${🐵.🦍🦍((🦍🐵) => 🦍🐵 + "/")}`; -}; - -🦍🐶.🐵🐈(🦍🐈()); -``` - -お!!識別子が絵文字に変換されてくれてますね!! -各識別子がちゃんと対応していることを確認してみてください. - -今回は変数全部絵文字にする君というかなりしょうもないツールを作っただけですが, 賢い人ならあれもできそうこれもできそうと, 何かアイディアが浮かび上がったかもしれませんね. - -## まとめ - -ASTを触れるようになると, 自分の開発者体験を自分で守っていくというエキサイティングな体験ができるようになります. -Let's AST!! \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/introduction-treeche.md b/packages/applications/turbo-blog/src/articles/public/introduction-treeche.md deleted file mode 100644 index ac440405..00000000 --- a/packages/applications/turbo-blog/src/articles/public/introduction-treeche.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Treeche, Tree-Shakable Checker for JavaScript/TypeScript Application to reduce bundle size -tags: [Programming, JavaScript, DX, Frontend] -description: bundle size を減らすことに有用な, JavaScript/TypeScript 製 module が tree-shakable かどうかをチェックするnpmモジュール、treeche を開発したのでそれの紹介記事. -publishedAt: 2022/08/27 -updatedAt: 2022/08/27 ---- - -## Treeche とは? - -Treecheとは、**Tree** -Shakable **Che** ckerの略です. JavaScript/TypeScript module が Tree-Shakable かどうかを確認するためのツールです. バンドルサイズの削減やそれによるUserExperienceの最適化に有用です. - -[https://github.com/Shinyaigeek/treeche](https://github.com/Shinyaigeek/treeche) - -## Example - -```typescript -// this is not tree-shakable because have side-effect - -const currentYear = new Date().getFullYear(); - -export function getCurrentYear() { - return `Year ${currentYear}` -} -``` - -上記のような module は副作用を有しているため, tree-shakable ではありません。 - -このような場合、Treeche は以下のような出力をします. - -```shell -🚨 ~/application/side_effect.ts is not tree-shakable due to the following code: - - -const currentYear = new Date().getFullYear(); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``` - -下記のように, 副作用のある module を副作用のない module に修正して - -```typescript -export function getCurrentYear(currentDate: Date) { - return `Year ${currentDate.getFullYear()}` -} -``` - -treeche を実行すると下記のような出力がなされます. - -```shell -Congratulation 🎉 All files are tree-shakeable ✨ -``` - -## JavaScript の module バンドルにおいて副作用とは何なのか - -ECMAScript のモジュールコンテキストにおける副作用とは, module の外部に影響を与えるコードのことを指します. 例えば、以下のようにモジュールのトップレベルで `window` オブジェクトに変数を設定するのは副作用です. module は import 時に実行されるため, module の top-level で `window` オブジェクトなどに mutation が加えられていると, module の import 時に実行される必要があります. - -```javascript -window.m = 1; -export mod() { - return 1; -} -``` - -もちろん, この処理が `init` のような module から export される関数の中で実行された場合は, import 時にこれが実行されないので、副作用はなくなります。 - -## なぜ副作用で bundle-size が大きくなるのか? - -rollup の REPL で bundler の挙動を確認することができます。 - -URL: [https://rollupjs.org/repl/?version=2.78.1&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QiUyMGhvZ2UlMjAlN0QlMjBmcm9tJTIwJTVDJTIyLiUyRm1vZCU1QyUyMiUzQiU1Q24lNUNuY29uc29sZS5sb2coaG9nZSgpKSUyMiUyQyUyMmlzRW50cnklMjIlM0F0cnVlJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMm1vZC5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJleHBvcnQlMjBmdW5jdGlvbiUyMGhvZ2UoKSUyMCU3QiU1Q24lNUN0cmV0dXJuJTIwMSUzQiU1Q24lN0QlNUNuJTVDbmV4cG9ydCUyMGZ1bmN0aW9uJTIwZnVnYSgpJTIwJTdCJTVDbiU1Q3RyZXR1cm4lMjBuZXclMjBEYXRlKCkuZ2V0RnVsbFllYXIoKSUzQiU1Q24lN0QlMjIlN0QlNUQlMkMlMjJvcHRpb25zJTIyJTNBJTdCJTIyZm9ybWF0JTIyJTNBJTIyZXMlMjIlMkMlMjJuYW1lJTIyJTNBJTIybXlCdW5kbGUlMjIlMkMlMjJhbWQlMjIlM0ElN0IlMjJpZCUyMiUzQSUyMiUyMiU3RCUyQyUyMmdsb2JhbHMlMjIlM0ElN0IlN0QlN0QlMkMlMjJleGFtcGxlJTIyJTNBbnVsbCU3RA==](https://rollupjs.org/repl/?version=2.78.1&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QiUyMGhvZ2UlMjAlN0QlMjBmcm9tJTIwJTVDJTIyLiUyRm1vZCU1QyUyM) - - -**main.js** -```javascript -import { hoge } from "./mod"; - -console.log(hoge()) -``` - -**mod.js** -```javascript -export function hoge() { - return 1; -} - -export function fuga() { - return new Date().getFullYear(); -} -``` - -上記のようなコードを rollup で bundle した結果は以下のようになります. -```javascript -function hoge() { - return 1; -} - -console.log(hoge()); -``` - -`mod.js` 内の `fuga` 関数が bundle の結果に存在しないのは, bundler が `main.js` が `fuga` 関数をインポートしていない(そしてもちろん使っていない)ことを知っているからで, そのため `fuga` 関数をバンドル出力に含める必要がなく, バンドルサイズの減少につながります。 - -しかし以下のように `mod.js` を編集するとどうなるでしょう. -```javascript -export function hoge() { - return 1; -} - -const _fuga = new Date().getFullYear(); - -export function fuga() { - return _fuga; -} -``` - -バンドルされた出力は、上記のようになります。 -```javascript -function hoge() { - return 1; -} - -new Date().getFullYear(); - -console.log(hoge()); -``` - -[https://rollupjs.org/repl/?version=2.78.1&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QiUyMGhvZ2UlMjAlN0QlMjBmcm9tJTIwJTVDJTIyLiUyRm1vZCU1QyUyMiUzQiU1Q24lNUNuY29uc29sZS5sb2coaG9nZSgpKSUyMiUyQyUyMmlzRW50cnklMjIlM0F0cnVlJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMm1vZC5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJleHBvcnQlMjBmdW5jdGlvbiUyMGhvZ2UoKSUyMCU3QiU1Q24lNUN0cmV0dXJuJTIwMSUzQiU1Q24lN0QlNUNuJTVDbmNvbnN0JTIwX2Z1Z2ElMjAlM0QlMjBuZXclMjBEYXRlKCkuZ2V0RnVsbFllYXIoKSUzQiU1Q24lNUNuZXhwb3J0JTIwZnVuY3Rpb24lMjBmdWdhKCklMjAlN0IlNUNuJTVDdHJldHVybiUyMF9mdWdhJTNCJTVDbiU3RCUyMiU3RCU1RCUyQyUyMm9wdGlvbnMlMjIlM0ElN0IlMjJmb3JtYXQlMjIlM0ElMjJlcyUyMiUyQyUyMm5hbWUlMjIlM0ElMjJteUJ1bmRsZSUyMiUyQyUyMmFtZCUyMiUzQSU3QiUyMmlkJTIyJTNBJTIyJTIyJTdEJTJDJTIyZ2xvYmFscyUyMiUzQSU3QiU3RCU3RCUyQyUyMmV4YW1wbGUlMjIlM0FudWxsJTdE](https://rollupjs.org/repl/?version=2.78.1&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QiUyMGhvZ) - -バンドルされている出力に不要な `new Date().getFullYear()` が含まれていることを確認できますね. なぜなら `mod.js` が `new Date().getFullYear()` という副作用を孕むからです. JavaScript では、import されたモジュールは import 時に実行されるので、`new Date().getFullYear()` のような副作用のあるコードはそもそも実行されるべきであるため, bundler が削除することができません. しかしそもそも `fuga` 関数を import しないのであれば、`new Date().getFullYear()` がバンドルされた出力に含まれる必要はありません. なぜなら、もう一方の関数 `hoge` は `const _fuga = new Date().getFullYear()` を必要としないためです. なので理想としては `new Date().getFullYear()` というコードが出力からなくなっているべきです. - -## How to use? - -Treecheをグローバルインストールして使うのみです. - -```shell -npm install treeche -g -treeche "**/*.ts" --excludes "node_modules" "**/*.test.ts" -``` - -argument に入力のファイルを取ることができます. ここには Node glob pattern を利用することができます. また `--excludes` option で, 特定のファイル, フォルダを除外することができます. test ファイルや node_modules はノイズになるのでこれを用いて除外することが想定されています. また argument を省略した上で, `--entry-point` で単一のファイルを指定すると, そこを entrypoint として bundle した上で, その上で副作用があるかチェックしてくれます. - -## オプション - -|kind|name|description|example| -|:--:|:--:|:--:|:--:| -|argument|inputs|input files to check tree-shakable. you can use Node glob pattern| treeche "src/**/*.ts"| -|option|excludes|excludes files to filter from inputs. you can use Node glob pattern| treeche "src/**/*.ts" --e "node_modules"| -|option|entry point|the unique entry point to check tree-shakable. if you specify input with this, treeche will bundle so you can check tree-shakable also in node_modules| treeche --entry-point ./src/main.ts| - -## 動作原理は? - -動作原理はとても単純で, Treeche は JavaScript module bundler である rollup を内部で実行し、下記のように option で指定した入力モジュールを import している仮想エントリポイントコードをバンドルします。 - -```javascript - -import "./your-module" - -``` - -"./your-module" に副作用がある場合, import 以外のコードも出力されます. それをチェックしています. - -## Feedback - -これは欲しいと思ってサクッと作った試験的なものですので, 多分バグがあります. 先に謝っておきます. バグや要望などあればフィードバックいただけると嬉しいです! diff --git a/packages/applications/turbo-blog/src/articles/public/log-2020.md b/packages/applications/turbo-blog/src/articles/public/log-2020.md deleted file mode 100644 index dbc74ba7..00000000 --- a/packages/applications/turbo-blog/src/articles/public/log-2020.md +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: 2020年の振り返りと次やりたいこと -tags: [Blog,Poem] -description: 今年の一年を一言で表すと「深化」の一年でした, 去年なあなあで理解していた部分など, 細かく突き詰めて理解できそれを元にわかる領域の問題に対して自分なりの意見考察をもって考えられるようになったような気がします. -publishedAt: 2020/12/24 -updatedAt: 2020/12/24 ---- -## はじめに - -こんにちは, しにゃいです. - -!tweet[](https://twitter.com/sanpo_shiho/status/1341760993584541696) - -さんぽし君がこんな記事を書いていて, 触発されて僕も今年の振り返り兼抱負を書いていこうと思い筆をとりました. - -!tweet[](https://twitter.com/Shinyaigeek/status/1341770719844167682) - -いつものように, 「書いてる(publishするとは言ってない)」芸をやっていたのですが, 今回はちゃんとpublishすることができそうです, 偉い. - -## 2020年の振り返り - -### インターン - -絶賛就活中で, 色々なところに顔を出していました. - -* 大手町にある謎の企業(長期インターン) -* CyberAgent(2days) -* VOYAGE GROUP(2weeks) -* Recruit (1 month) -* Cybozu (1 week) -* wantedly (3 weeks) - -長期インターン以外は全て夏に行っていました. -夏にこれだけのインターンを詰め込むとなると当然夏休みは休みなしでインターンでした(いうたらリクルートでのインターンは夏休み終わりに行っていたので学業と並行して, って感じでした). -ですがそこまで大変だったという印象もなく, 寧ろインターンで多くの方々と交流できてめちゃくちゃ楽しかったです. 普段の大学の授業がまあまあ詰まっていてサマーインターン中よりも忙しかったというのもありそうですが. - -正直エンジニアになることは特殊なケースというか大学の周りのみんなとは全く別の道を選ぶことになっていたのである種の不安感, 将来の不透明感は覚えていたのですが, インターンもありこの1年間で**プロ** として働いているエンジニアの方と喋ることも増え,最前線で道を切り拓いていっているような人たちを目の当たりにして俺もやっていくぞと勇気が出ました, ここが何よりもの収穫かなとは思っています. - -インターンでお世話になった方々, 本当にありがとうございました. - -### 開発 - -ここ一年で作ってたやつです, starしてくれると嬉しい...💓 - -#### Shinyapack - -https://github.com/Shinyaigeek/Shinyapack - -夏休みの自由研究のテーマが, Webのエコシステムの再発明で, その一環でやっていました. -ちょうどhiroppyさんの書かれた 『module bundlerの作り方(準備編)』([https://blog.hiroppy.me/entry/create-module-bundler-preparation](https://blog.hiroppy.me/entry/create-module-bundler-preparation)) を読んで, タイミングの良さに運命を感じおいらもmodule bundlerを作ろう!!と思い至り作ってみました. - -中身は, どうせなら気になったdenoを触ってみようと思いTSで書いて, parserやgeneratorはbabelのものを利用していました. moduleはskypackからimportしていた気がします. -確か当時query paramでtypes={型定義のURL}を付ければいい感じに型定義がつくと聞いていたのにうまくいかなくてイライラして完全趣味且つ勉強目的の開発だしいいだろ!!とか言いながら型をぶっ壊しながらコードを書いていったのはいい(?)思い出です. - -これを作るにあたりwebpackのコードもちょこちょこ読んで書き方とかそういう面での学びがあったり, webpackのinterfaceにちょっと詳しくなったりもしました. -また中身を知ることで, 複雑怪奇なJSのエコシステムへの解像度がちょっと上がった気もしています. - -前述の通り, 夏はインターンで忙しかったのがあり最低限の実装しかできなかったのですが, terserを実装してその気持ちになってコードを書けるようになりたいとは考えています. - -#### Shinyact - -これは未完成のためprivate repositoryです... - -これも夏休みの自由研究の一環でReactを再発明しようとして作ったものです. これは記事などは一切参照せずReactをコードリーディングしつつ頑張っていました. - - - -mountできるところまでは持っていったのですが, Reactがどのようにして状態を持っているかや, どうやって状態の初期化が複数回起きないようにしているかなど, 結局コード読んでも解読しきれずそこで止まってしまっています. - -VDOMの構造などは結構学べた気がしていて, そこは良かったです. - -これまたタイミングよくsaddnessOjisanがちょうどpreactを再実装したoreactを作っていたので, preactのコードリーティングを進めつつまた再チャレンジしたいと考えています. 宿題ですね. - -#### Next.js 非公式日本語翻訳プロジェクト - -https://github.com/Nextjs-ja-translation/Nextjs-ja-translation-docs - -もともと非公式のNext.jsの日本語翻訳サイト自体はあってOSSとして運用されていたのですが, ドキュメントの中身やデザインが古いもののまま更新が止まっていたので, 「更新せえへん?(意訳)」という旨のissueを作った結果作り直そうとなりました. - -当時よく話していた [かみむらさん](https://twitter.com/kamimura_th) にやってみませんかと相談してみたところ, 快諾していただき, そのあとNext.jsを作っているVercelの中のShu Uesugiさんにnext-siteをfolkして日本語翻訳していって良いか確認を取りスタートしました. - -僕は翻訳のレビューやCI,linterの整備, 移行作業やトップページの翻訳などを行っていました. - -最近Next.jsが大盛り上がりしているような印象を持っていますが, それに一役買えたのであれば幸いです. - -https://nextjs-ja-translation-docs.vercel.app/ - -余談ですが, 本家のドキュメントサイトであるnext-siteのリポジトリは今見えない状況になっています. -このリポジトリはNext.js confあたり, つまりNext.jsのv10が発表されたタイミングで見えなくなっていました. -これは邪推ですが, i18n routingにNext.jsが対応したことを受けて, vercel側で「これが18nのベストプラクティスや!!」とドキュメントサイトを翻訳もするのではとは思っています. - -#### babel-plugin-lit-jsx - -https://github.com/Shinyaigeek/babel-plugin-lit-jsx - -これはJSXで書かれている, hooks(というよりReact)に依存しないFunctional Componentをlit-htmlで動くようにしてくれるbabel-pluginです. - -僕の技術ブログはJSXでコンポーネントを書いて, SSRして生成されたhtmlをCDNにキャッシュして, client-sideでhydrationはしないという構成になっています. -これは僕の技術ブログの場合clientにおける状態変化は少なく, Reactを使うとしたらtemplate engineとしての利用がメインとなってしまいますが, そのためにReactをclient-sideで使うのはI/Oコストを無駄に増やすだけではないかという考えのもとフロントエンドではhydrationしないという実装にしました. - -ですがNext.jsなどにあるようなprefetch僕も欲しい!となり, htmlのbodyの部分をprefetchしてページ遷移のタイミングでinnerHTMLを置き換えるだとか, あらかじめリソースをfetchしておいてそれをブラウザにcacheさせるとか色々方法は思いついていたのですが, 最終的にviewに必要なJSONをprefetchして, それをclinet-sideのJSでレンダリングしようとなりました. - -レンダリングはlit-htmlで行おうとなったのですが, 正直型などの面で書き味がよろしくなく, やっぱり @types/react のJSXの型定義の恩恵は受けたいという話になり「でもhooksに依存しないFunctional Componentだったらlit-htmlに自動で置き換えられるんじゃね」という発想の元それを実現するためのbabel-pluginを作っていました. - -原理的には babel/traverse でASTをみてゴリゴリ変換しています. - -具体的にはこのようなjsxを - -```typescript -import Header from "./Header"; -import Footer from "./Footer"; -import BlogPost from "./BlogPOst"; - -const Layout = (props: { content: string }) => { - return ( -
-
- -
-
- ) -} -``` - -```typescript -import Header from "./Header"; -import Footer from "./Footer"; -import BlogPost from "./BlogPost"; -import { html } from "lit-html"; - -const Layout = (props: { content: string }) => { - return ( - html`
- ${Header({})} - ${BlogPost({ - content, - })} - ${Footer({})} -
` - ) -} -``` - -こういう感じに変換してくれます. - -ある程度できたんじゃないかとは感じていて, テスト書きつつこのブログでこれを使いつつprefetchを実装しているのですが, うまくいったらreleaseしようとは考えています. - -もともと shinyapack でASTは触っていたのですが, これの開発でゴリゴリ触ることになり知見がたまりました. - -JSはECMAScript, TypeScript, module bundlerなどの存在のおかげか他の言語に比べ(**個人的な素人感想です**)ASTを触りやすいようライブラリが整っていることもありやりやすかったですし, 自分の開発者体験を自分で守っていくぞという意識が高まったなとは考えています. - -#### 深層学習 - -大学の研究の関係で12月くらいから深層学習の勉強をスタートしていました. -僕が触れていたのは画像処理の分野で, 主にSemantic Segmentationなどを扱っていました. -TAに聞いたり論文を読んだりまとめを読んだりしつつ悪戦苦闘していました. - -なんだかんだ短時間である程度のものを作れてエンジニアとしての基礎体力の伸びを感じていました. - -根本的な理論などは正直まだ理解できていなくて, モデルにこのレイヤを足したからこうなるといったことも理解があやふやで, モデルの改善などはでたらめに行なっているのでちゃんと理解したいですね. - -### WriteCodeEveryDay - -リクルートでサマーインターンをしていた時, メンターの方に勧められ良いタイミングだしということでやってみました. - -https://github.com/Shinyaigeek/WriteCodeEveryDay - -↑のリポジトリでWriteCodeEveryDayをやっていくぞという誓いを立て, 毎日何らかのコードを書くようにしました. -やってみると意外と楽というか, もともとコーディング自体好きで基本的に余裕があるときには毎日書いていたのであとはそれを0時までにコミットするよう意識するということを心がけるくらいでした. - -どちらかというと, 課題などに追われ余裕がないときや疲れている時などは意識的に机に向かいコードを書く必要がありかなりしんどいですが, これは「クソみたいな日に良いもの作る」ための訓練だと思って頑張っています. - -![kusa](/assets/log-2020/kusa.png) - -二日ほどベロンベロンに酔っ払ってしまい結局コミットできずじまいだった日もありましたが, 10月中旬くらいからある程度順調に進んでいるかなという感じです. - -### LeetCode - -WriteCodeEverydayをやっていたわけですがまあまあ余裕があったので, それに加えSolveLeetCodeEveryDayもやってみることにしました. - -(といってもまだ8日間ですが...) - -![newkusa](/assets/log-2020/newkusa.png) - -実はこのLeetCodeを毎日やろうという取り組み自体は人生なんども挑戦しては失敗しています. - -なぜ続かなかったか考えてみた結果 - -* 無理して習熟度の低いRustで解こうとしていた -* 解いた問題をGitHubで管理しており, 問題を解くためにいちいちcheckoutしてcommitしてとやる必要がありめんどくさい - -というのが考えられたため, 今回は書き慣れたTypeScriptで問題を解き解いた問題をgithubで管理なども特にしない方針で進めています. - -### OSS - -[東京都 新型コロナウイルス感染症対策サイト](https://github.com/tokyo-metropolitan-gov/covid19), [blitz.js](https://github.com/blitz-js/blitz) にかなり小さくではありますがcommitしていました. - -geist-ui(旧zeit-ui)など仕事, プライベートでお世話になっていたライブラリにもライブラリにもバグを見つけ次第修正してPRを出したりissueを出したりしていました. あとは前述のNext.jsのドキュメント翻訳くらいでしょうか. 学生らしく可愛らしいOSS活動ですね. - -### 同世代との交流 - -今年で同世代の仲良いエンジニアが一気に増えたなと感じています(仲良いと思っているのは僕だけかもしれませんが) - -コロナによって就活はオンライン前提になることは予想できていたので, こんな中で同世代のエンジニア友達とかできるんだろうかと大学に友達がいない僕は不安になっていましたが, むしろオンライン前提だからこそ大学も地域も超えて色々な人と仲良くなれたなとは感じています. - -3月の逆求人のタイミングからポツポツと交流が始まり, - - - -僕が勢いで22卒交流slackを作ってみたらそこから一気に交流の輪が広がり交流も増え楽しかったです. - -オンラインで飲んだりもしていましたし, ましくんが主催してくれた22卒サマーインターン前にツヨツヨになっちゃおうLTなど, イベントも結構あってかなり楽しかったです. - - - -とある会社の人事さんと飲んでいた時に, 今年のエンジニア学生は大学とか地域を超えて仲良くなっている感じがあると仰っていて, おお〜〜〜〜ってなっていました. - -## やっていくこと - -### 就活 - -はい, 考えないといけませんね. - -めちゃくちゃスローペースで進めています. -とはいっても受ける会社とかはある程度決まっていてあとはやっていくだけという感じです. 就活終了できるタイミングが結構遅くなりそうでドキドキしています. -ちゃんと満足のいく結果を出したいですね. - -### 技術ブログの改善 - -これはやり残しちゃったタスクですね. -さっき言及したbabel-plugin-lit-jsxを用いてprefetchを実装するとかもできていませんし, Algoriaを用いて全文検索を実装するとか, OGPを動的に生成するとか, Fieldデータを収集するとかやるべきこと/やりたいことがまだまだあります. -これもちゃんとやってその上でやったことの詳細を技術ブログに書きたいですね. - -### OSS - -今年こそはもっとOSS活動をがっつりやっていきたいなというお気持ちです(多分毎年言ってる). -誰かのブログでnode.jsのcode & learnが紹介されてたんですが, まだやってないかなぁ。。。 - -### 卒業 - -多分これが一番難しい. -頑張ります - -### ブラウザ作り - -これは来年やりたいことというよりも, 次の春休みの自由研究の課題です. - -Webフロントエンドエンジニアを名乗っているのにブラウザのことを知り尽くしてはいないし作ったこともないことにちょっとした引っ掛かりを感じていて, それを解消しようという意図があります. - -春休みの自由研究のテーマを考えていた時にちょうど keiya sasaki さんがTLでブラウザを作っているのが目に入った, 12月24日(今日ですね!!)発売のWeb + DB Pressに自作ブラウザ特集がある, 『[Go言語でつくるインタプリタ](https://www.amazon.co.jp/Go%E8%A8%80%E8%AA%9E%E3%81%A7%E3%81%A4%E3%81%8F%E3%82%8B%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%97%E3%83%AA%E3%82%BF-Thorsten-Ball/dp/4873118220)』をちょうど勧められていた, など諸々タイミングがよくて運命を感じブラウザ作りを春休みの自由研究のテーマにしました. - -## 終わりに - -ノリで書き始めましたが, 意外と書く内容が多くてびっくりしました. 充実した一年間だったのかもしれません. - -今年の一年を一言で表すと「深化」の一年でした, 去年なあなあで理解していた部分など, 細かく突き詰めて理解できそれを元にわかる領域の問題に対して自分なりの意見考察をもって考えられるようになったような気がします. - -こういう話をするということは来年は何の年にしたいかという話をするということなのですが, 来年何の年にしたいかということよりも, 2年後何の年にしたいかということの方が明確に決まっているためそこから逆算した目標を来年何の年にしたいかとして掲げたいと思います. - -僕はUX, DX周りを改善していくことが大好きなのですが, ここら辺はトレードオフや人的リソース, 開発者の意識など様々な問題が絡み合う多目的問題だと考えています. こうした開発現場における多目的問題の全体最適化を目指していきたいのですが, そのためには「こうすればこうなる」だけではなく, 「こうすればこうなるはずだけどそれによってどれくらい改善されたのか」まで, 仮説に対して検証を行いそれを元に次の意思決定を下して...ということが求められると考えています.. こうしたことは実際に企業に入って動かないと実践できない(特に僕は大学関係で何らかの組織に属しているといったこともないので...)ことだと思っているので, これを2年後の目標に掲げています. つまり2年後は「進化」の年にしたいです. - -2年後は「進化」の年にしたいんですが, そこから逆算して来年は「レベリング」の年にしたいです(「深化」, 「進化」といい感じに踏みたかったけどいいのが思いつかなかった...) -僕はまだまだWebについて理解できないことがたくさんあると思っていて, Web Developerとして深さも広さも足りていないと感じています. (深さで言えばブラウザそのものへの理解など, 広さで言えばUIデザイン, サーバーサイドなど...) -これらの足りてないところを補い2年後の「進化」のための土台づくりとなる, 「レベリング」をしていきたいなと考えています. - -来年もこう思えるような一年間にしたいですね, やっていきましょう!!!!!良いお年を!!!!!!! \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/log-ca-web-speed-hackathon.md b/packages/applications/turbo-blog/src/articles/public/log-ca-web-speed-hackathon.md deleted file mode 100644 index 1063260c..00000000 --- a/packages/applications/turbo-blog/src/articles/public/log-ca-web-speed-hackathon.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: CyberAgent主催『Web Speed Hackathon Online』参加ログ -tags: [Web,Programming] -description: | - Cyber Agent主催のWeb Speed Hackathon Online 4/25, 4/26に参加してきました. 結果は残念ながらレギュレーション違反で選外でしたが, とても楽しく刺激を得られたイベントになりました. - - この混乱した情勢の中オンラインという形でシステムを整えて実施してくださったCyber Agentの皆さん, ありがとうございました. -publishedAt: 2020/04/26 -updatedAt: 2020/04/26 ---- - -## はじめに - -Cyber Agent主催のWeb Speed Hackathon Online 4/25, 4/26に参加してきました. 結果は残念ながらレギュレーション違反で選外でしたが, とても楽しく刺激を得られたイベントになりました. - -![hackathon-res](/assets/log-ca-web-speed-hackathon/hackathon-res.png) - -この混乱した情勢の中オンラインという形でシステムを整えて実施してくださったCyber Agentの皆さん, ありがとうございました. - -## イベント内容 -あらかじめ用意されている, 架空のブログサービスのパフォーマンスをどれだけ高められるかというものです. -ランタイムのパフォーマンスの最適化ももちろん必要でしたが, チューニング対象がメディアという特性上やはりI/Oコストをどれだけ抑えられるかが大きな鍵で, フロントエンドだけでなくインフラ, バックエンドも触れるところがありました. - -得点づけはlight houseにより計測される得点や, TTI, Speed Index等に重み付けを行なってホニャホニャするそうです. - -レギュレーションは**Google Chrome で機能落ちやデザイン差異が生じない**ことです. -具体的には画像のアスペクト比等が崩れない, いいね機能などが落ちない等で結構厳し目だった印象があります(あと個人で進めていたこともあって気付きにくかった) - -僕のレギュ違反はmoment, lodash, jQueryを剥がした時に機能落ちが生じたか, 画像のresizeを行なった時にアスペクト比がずれたかかなと。。悔しい。。 - -## 経緯 - -スタート時 - - -1日目終了 - - - - -調子乗ってる時 - - -終わった直後(審査中) - - -死んだあと - - -## やった施策 - -雑に箇条書きです. 効果が顕著だったものは**太字**にします -よろしければ他の参加者の皆さんもどんなことをやったか教えて欲しいです🤲 - -* webpackのbuild最適化 - * **source map剥がす** - * **modeをnone -> productionにする** ([https://webpack.js.org/configuration/mode/](https://webpack.js.org/configuration/mode/)) -* code splitting - Reactに頼りました. Router levelでchunkしてさらにcomponentレベルでもいくつかchunkしました. fetch, contextの更新のためのscriptも切り出そうと思いましたが, webpackをゴリゴリ考える必要が出てきてしんどくなって諦めました - * **Lazy, Suspense** ([https://ja.reactjs.org/docs/code-splitting.html](https://ja.reactjs.org/docs/code-splitting.html)) - ちなみにですが, 遅延読み込みをする時, **main.bundle.js**から相対パスで必要なjsを読み込むっぽくて, それはサーバーのどこにmain.jsがあるかでなくそのスクリプトが評価された時点のパスから相対的にパスが決定されるっぽくて, 例えばReact routerとかを使っているとダイレクトに **/asdf/hogehoge/barbar/celcel/**みたいなところにアクセスするとchunkされているjsが迷子になってエラーが出ます. これをなんとかするために, サーバー上で, jsへのRequestのうち迷子になりそうなものは, catchしてよしなに返すというものを実装しました.多分webpackでこういうのをいい感じに解決するものがありそうでしたけど, 見つからなかった。。 ちなみにhtmlファイルの配信にも似たようなことをしなければならないです. -* 画像の最適化 - * 用いられている画像のresize, webp化(画像があるリポジトリからcloneしてcloud storageにアップロードしました) -> ここでやらかした可能性ありますね。。 - * **webpackによりbase64にencodeされて埋め込まれているものもあったのを, encodeさせずに普通にpathで画像を指定する.** -* 一部ライブラリの削除 - * jQuery, moment, lodashを剥がしました -> ここでやらかした可能性もありますね。。 - * [webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer)で剥がすべきライブラリを洗い出しました - ![webpack-bundle-analyzer](/assets/log-ca-web-speed-hackathon/webpack-bundle-analyzer.png) - * immutable.jsとbluebird.jsについては辛そうだったので諦めました。。 -* html, cssのminify - * htmlはHtmlWebpackPluginに任せました - * cssはpost-cssに任せました -* google fontの最適化 - google fontsはquery paramaterでこの文字のフォントだけ欲しい!という指定ができます, それをやりました [https://developers.google.com/fonts/docs/getting_started](https://developers.google.com/fonts/docs/getting_started) -* fontawesomeの読み込みを最小限にする -* service workerでfetch時にキャッシュ -* 配信されるコンテンツにとても強いCacheを効かせる -* react importの最適化 - import React fromよりもimport * as React fromの方が余計なプロパティアクセスが生じなくてちょっと早くなるらしいです, まじで?(未検証) - -* 配信時に圧縮をかける - expressでcompressionするあれです -* 画像の遅延読み込み - [https://developers.google.com/web/updates/2016/04/intersectionobserver](https://developers.google.com/web/updates/2016/04/intersectionobserver), [https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video?hl=ja](https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video?hl=ja), [https://blog.jxck.io/entries/2019-05-20/lazyloading.html](https://blog.jxck.io/entries/2019-05-20/lazyloading.html)この辺 - 実装は時間がなかったので良さそうなReact Componentを採用しました [https://www.npmjs.com/package/react-lazy-load-image-component](https://www.npmjs.com/package/react-lazy-load-image-component) - -## やれなかったこと -* SSR - そもそもメディアだったらSSRしたくない?ってなって1時間ほど作業しましたが, React-routerやreact-reduxといったfor clientのライブラリが多く, シンプルにserver上でレンダリングまでが既にしんどい, client, server間でcontextやstate, routerの共有が沼いという理由で諦めました -* ブログの記事をfetchを並列でRequestを投げる - -```javascript -useEffect(() => { - await fetchASDF() - await fetchHOGE() - await fetchBAR() -},[]) -``` -となっていて, これだとfetchASDFが終わったらfetchHOGEのRequestを投げてそのResponseが返ってきたらfetchBarを投げてという感じでブロッキングになっちゃって辛いので -```javascript -Promise.all([fetchAsdf(), fetchHOGE(), fetchBAR()]) -``` - -という感じにしてRequestをまとめて投げてもらうようにして, こうすれば多分fetchにかかる時間が短くなってTTI減らせるんじゃないかのと思っていたのですが, なぜかTTIが大幅に落ち込んだので辞めました。。。何故だ。。知見求むです。。 - -## 結局 - - - -パフォーマンスチューニングをする時, (パフォーマンスでなくとも何らかのチューニングを行う時), ただパフォーマンスについてだけ数字をとって考えればいいというわけではなく, デザイン差分や機能差分についても目を配りそれらに落ちがないようにする必要がもちろんあるんですが, その際**僕のような注意力散漫な人間であっても, そして別に特段注意を払わなくとも**差異が発生した時は気づけるようなシステムを作っていくべきだと感じました. せっかくPlaywright, puppeteer, GitHub Actionsといった便利なツールがあるし, エンジニアを志望する以上こういう仕組みづくりをして行くべきで, 逆に普段のプロダクトでこういったことを怠っていた | Review任せにしていたというのが今回のレギュレーション違反に繋がったかなと反省があります. - -最後に主催してくれたCyber Agent, 競い合った参加者の皆さんに感謝を述べて終わりたいと思います.ありがとうございました!! - -(次は優勝したいのでまたやってください) - \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/m17n-with-cloudflare-workers.md b/packages/applications/turbo-blog/src/articles/public/m17n-with-cloudflare-workers.md deleted file mode 100644 index e25539eb..00000000 --- a/packages/applications/turbo-blog/src/articles/public/m17n-with-cloudflare-workers.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: cloudflare workers で多言語対応を行う -tags: [Programming,CDN,CloudFlare] -description: 弊ブログで多言語対応を行なった。その際 cloudflare workers を利用したが体験が良かったのでメモとして残しておく。 -publishedAt: 2022/02/19 -updatedAt: 2022/02/19 ---- - -こんにちは、しにゃいです。卒業論文を無事倒し入社まで暇になり、暇つぶしに気になってる OSS にPRを投げていたところ、そのメンテナやPRで会話した人から Twitter でDMが飛んでくる機会が増え、また cloudflare のアナリティクスを見ても最近如実に国外からのアクセスが増えていました。クローラーbotの存在を考えても明らかに数が増加していたためこれなら弊ブログ(shinyaigeek.dev)も多言語対応を進めた方がいいんだろうな、という気持ちになり多言語対応を進めました。要件の中にあった, HTTP Request Header の "accept-language" を見てよしなにコンテンツを振り分ける, という処理に cloudflare workers を利用したのですが、30分程度いじいじしたらいい感じにできて体験が良かったので備忘録程度に書いておこうと思い本記事の執筆を始めました。 - -## ブログの構成 - -まず弊ブログの構成から述べていきます。弊ブログはコンポーネントを JSX で記述し、記事自体は markdown で書いています。それをオレオレ静的サイトビルダーでHTMLとしてVPSに立てたh2oサーバーから配信しています。ブログにそこまでの機能は求めておらず、ブログの場合はページ遷移も少ないだろうという想定から hydration は行わず、React 抜きのWebページになっています。一部動的に JavaScript を使っている部分がありますが、そこは customElements でカプセル化しています。 - -ひとまず対応する言語はデフォルトの日本語と、英語として、ビルドするときに英語用のHTML、日本語用のHTMLの二種類を吐き出すようにしました。JSも使っていないため完全にURLベースで英語用のページ、日本語用のページを振り分けるようにしています。サブドメインとして "en.shinyaigeek.dev" と "ja.shinyaigeek.dev" を用意し、前者からは英語用のページ、後者からは日本語用のページを配信するようにしています。また "shinyaigeek.dev"、"www.shinyaigeek.dev" からは日本語用のページを配信するようにしています。 - -## 技術選定 - -まずHTTP Request を見て "accept-language" によってよしなにHTMLを振り分けるかよしなにリダイレクトさせるか、という選択肢がありました。よしなにHTMLを振り分ける方式だとshared cache周りが面倒になる、また、振り分けも cloudflare worker でURL Rewritesを行えばその心配は無くなりますが、静的なWebページとして運用している以上あるURLを叩くと同じResponseが返される、というようにしたかったのでこの方針は取らずによしなにリダイレクトさせるようにしました。HTTP Requestを送信してきたクライアントにリダイレクトしてもらうためにはもちろん301 HTTP Responseを返却する必要があります。それをOrigin Serverから返却する、といったことももちろん可能なのですが現状Origin Serverは日本にしかなく、"accept-language" で英語になるようなユーザー、すなわちこの対応で掬い上げたいクライアントは多くが日本国外からHTTP Requestを飛ばしてくると想定すると、地理的な要因で生じ得る遅延をなくしたく、cloudflare workers を用いてネットワークエッジで捌いてしまおう、となりました。 - -## やり方 - -至極単純です。 "accept-language" をパースしてよしなにより好まれる言語を決定する君はnpmにいくつか出ていますので、最も適格なものをインストールして、振り分けるだけです。 - -- [accept-language](https://www.npmjs.com/package/accept-language) -- [accept-language-parser](https://www.npmjs.com/package/accept-language-parser) -- [resolve-accept-language](https://www.npmjs.com/package/resolve-accept-language) - - -注意点としては、 -- HTML 以外への HTTP Request については特に何もしない - - 今回はRequestのURLが `.html` で終わるか, `/` で終わる時をターゲットとしました -- 無限ループに注意する - - en 向けのページにリダイレクトしてそれに応じてそのクライアントからHTTP Requestが飛んできてそれによってまた以下のような cloudflare workers が発火してまた en 向けのページにリダイレクトして...という無限ループは生じ得ます - - 本ブログでは en 向けのページ、ja向けのページはそれぞれ別ドメインにしてあり、そのドメインへの HTTP Request にはそもそも cloudflare workers が発火しないようになっています。これは上記の無限ループ対策でもありますが、こうしたURLにアクセスしてくる人は accept-language 関係なくその言語で読みたいであろう、という意図もあります。 - - 例えばサブドメインではなく pathname に `/en/` といったprefixをつけて対応している人は注意が必要になるでしょう。 - -以下に簡単なコードを載せておきます。 - -### コード - -```typescript -import resolveAcceptLanguage from 'resolve-accept-language' - -const handler = function (event: FetchEvent) { - // HTTP Request からURLを取得 - const { url } = event.request - // URLから pathname とクエリを取得 - const { pathname, search } = new URL(url) - - // HTMLに対してのHTTP Requestではない時は特に何もしない - if (!pathname.endsWith('.html') && !pathname.endsWith('/')) { - return fetch(event.request) - } - - // HTTP Request Headerからaccept-languageを取得 - const acceptLanguage = event.request.headers.get('accept-language') - if (!acceptLanguage) { - return fetch(event.request) - } - // 言語を決定する - const preferredLanguage = resolveAcceptLanguage( - acceptLanguage, - ['en-US', 'ja-JP'], - 'ja-JP', - ) - - // 英語が好ましいとなったときは "en.shinyaigeek.dev" にリダイレクトする - if (preferedLanguage === 'en-US') { - return Response.redirect( - `https://en.shinyaigeek.dev${pathname}${search}`, - 301, - ) - } - - return fetch(event.request) -} - -addEventListener('fetch', (event) => { - event.respondWith(handler(event)) -}) -``` - -## まとめ - -一才のフレームワークを使わずにブログを作っているので、こうした多言語対応も自分で考えてあれこれしなければいけないですが、修行になって楽しいですね。また最近は cloudflare workers や Compute@Edge など、フロントエンドエンジニアがサクッと reverse proxy 的なことをしかも馴染みあるJSで制御できるようになっていていい時代です。また一切フレームワークを使わずに力技で対応しているので、実はこういうこともした方がいいよ、これはこうした方がいい、などあれば教えていただけると幸いです。 diff --git a/packages/applications/turbo-blog/src/articles/public/nice-to-meet-you.md b/packages/applications/turbo-blog/src/articles/public/nice-to-meet-you.md deleted file mode 100644 index 6a234b46..00000000 --- a/packages/applications/turbo-blog/src/articles/public/nice-to-meet-you.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: 初めまして -tags: [Blog,Poem] -description: | - 初めまして、しにゃいこと、林仁と言います。 ブログ始めてみました。 なんでアメブロやはてなブログなど既存のブログサービスを使わずにこんなダサくめんどくさそうなことをしたかというと単純に面白いかなと今日の朝思っちゃいまして -publishedAt: 2018/10/21 -updatedAt: 2018/10/21 ---- - -初めまして、しにゃいこと、林仁と言います。 ブログ始めてみました。 なんでアメブロやはてなブログなど既存のブログサービスを使わずにこんなダサくめんどくさそうなことをしたかというと単純に面白いかなと今日の朝思っちゃいまして - -とりあえず自己紹介でも。 東京大学文科3類 1 年林仁です。趣味はダーツと水泳、読書、アニメ。いわゆるくそ陰キャです。 最近趣味でプログラミングを齧ってる候、その一環として、とりあえず自分で何かページを成形したいなと今日の朝思い至ってこうなります。 さっきまで友達と遊んでてクソ疲れた状態で深夜からこの作業始めたんでクッソ適当です、いいね機能もなければコメント機能もない、実はこのヘッダーのロゴは僕が 20 分くらいで適当に書いた何か、まじでクソやる気ないブログですけどちょっとずつ時間を縫って改良していきます。 今仕事の関係で HTML を弄ることが多いのでこれくらいはサクッとやりたいなと思います(唐突なイキリ) タイトルにもなっているように僕の将来の夢は今んとこ技術やさんなんすよね。理由はかっこいいからです。 まあ実は技術やさんというよりコンピューターサイエンスに携わりたいという欲望もありますけど まあとりあえずこのブログをあろうことか読んで時間をドブに捨ててしまったエンジニアやコンピューターサイエンスに携わっているよ!という方、とにかくイキってください、めっちゃアドバイスとか欲しいです。 下にコメント機能がわりに Twitter と Insta のアカウント貼っとくんでまぁじでお願いします。。。 あとなんか依頼があれば多分言い値でやります。 とりあえずもう眠いんで成形だとかは今度また気が向いたらします。 とりあえず今のうちにやるべきこと、やったことをまとめておくと次僕が気まぐれでこのサイトを開いたときのためにまとめておきやす。 ☆ やったこと ・ヘッダー作成(適当) ・初めましてを書く ・よくわからないロゴ作成 ・GoogleAnalytics 導入 ☆ やるべきこと (上から) ・コメント機能 ・デザイニング ・サイドメニュー ・いいね機能 ・文章書く ・楽になるような CGI 作成 こんな感じですかね、駄文でしたがここまで読んでくれた方ありがとうございました。多分3日後くらいに更新します。 \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/pnpm-outdated-command-supports-json-format.md b/packages/applications/turbo-blog/src/articles/public/pnpm-outdated-command-supports-json-format.md deleted file mode 100644 index 2e6a577b..00000000 --- a/packages/applications/turbo-blog/src/articles/public/pnpm-outdated-command-supports-json-format.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: pnpm outdated コマンドが JSON format をサポートした -tags: [Blog,JavaScript,TypeScript,OSS] -description: pnpm で古くなったパッケージを検知する outdated コマンドで, JSON 形式での出力をサポートしました. -publishedAt: 2022/11/06 -updatedAt: 2018/11/06 ---- - -## TL;DR - -- pnpm outdated コマンドが JSON 形式の出力をサポートした -- これでプロジェクト中の依存パッケージの自動アップデートなどがやりやすくなる -- 実装を担当していたので, 実装や変化, ユースケースをブログに示す - - -## pnpm とは - -[https://pnpm.io/](https://pnpm.io/) - -pnpm とは Node.js 環境におけるパッケージマネージャーの一つです. パッケージマネージャーとして, 他のツールだと npm や yarn が挙げられます. - -pnpm は symlink を用いて, npm モジュールの高速で省容量なダウンロードを提供しています. 通常あるプロジェクトで npm モジュールをインストールすると, `node_modules` 以下にそれらのモジュール, とさらにネストされた依存モジュール群が全て展開されます. pnpm はプロジェクトを跨いで, それらのモジュールを単一のディスク領域へと保存し, プロジェクト配下にはそれへのハードリンクが展開されるようになります. また, 異なるバージョンのモジュールに依存している際, それら一つ一つを丸々 install するのではなく, それらのモジュールごとの更新の差分のみを保存します. これらの方法により省容量で高速なモジュールのインストールを実現しています. - -また, pnpm の特徴として大胆に他のパッケージマネージャーにはない utility コマンドやオプションを追加して行っている, といったことも挙げられます. - -[![tweet i have joined pnpm](../../../assets/pnpm-outdated-command-supports-json-format/tweet.png)](https://twitter.com/Shinyaigeek/status/1577947254916550656) - -pnpm のメンバーとして, `pnpm outdated` コマンドに JSON 形式での出力機能を実装したので, それについてブログに書き起こそうと思います. - -## pnpm outdated コマンドについて - -`pnpm outdated` コマンドは, プロジェクト中の依存モジュールのうち, deprecate されていたり新しいバージョンが publish されているなどで, 古くなったモジュールを洗い出すためのコマンドです. - -例えばこのブログで `pnpm outdated` を実行すると以下のような出力が得られます. - -![pnpm outdated を実行した結果](../../../assets/pnpm-outdated-command-supports-json-format/pnpm-outdated.png) - -また list 形式での出力もサポートしており, `pnpm outdated --table false` と実行すると以下のような出力が得られます. - -![pnpm outdated --table false を実行した結果](../../../assets/pnpm-outdated-command-supports-json-format/pnpm-outdated-with-list.png) - -## pnpm outdated コマンドに JSON 形式の出力をサポートしたかったモチベーション - -モチベーションとしては, 上記のような table 形式, list 形式での出力だとパッケージのアップデートを自動化したい, となったときにそれら形式はヒューマンフレンドリーに偏っており, 逆に自動化しにくい, といった背景がありました. -自動化しやすいように, 出力フォーマットとして JSON 形式をサポートすることになりました. - -## format オプションについて - -JSON 形式の出力のサポートのために, `--format` が追加されました. 一方これは `--table {boolean}` と責務が微妙に被ってしまいます. また `--table` は boolean 値を取るため, 命名的にも機能的にも `--table` で JSON 形式での出力を指定できるようにすべきではありません. また責務も被るため, その解消として `--format {table | list | json}` と取れるようにし, `--table` は削除されました. ([実装](https://github.com/pnpm/pnpm/blob/main/packages/plugin-commands-outdated/src/outdated.ts#L43) - -## JSON 形式の出力例 - -`pnpm outdated --format json` を実行します. - -```json -{ - "uglify-es": { - "current": "3.3.9", - "latest": "3.3.9", - "wanted": "3.3.9", - "isDeprecated": true, - "dependencyType": "dependencies" - }, - "highlight.js": { - "current": "11.3.1", - "latest": "11.6.0", - "wanted": "11.3.1", - "isDeprecated": false, - "dependencyType": "dependencies" - }, - "@types/highlight.js": { - "current": "9.12.4", - "latest": "10.1.0", - "wanted": "9.12.4", - "isDeprecated": true, - "dependencyType": "devDependencies" - }, - ... -``` - -自動化しやすそうでハッピーですね. 2022/11/06 時点ではまだリリースされていませんが, 次の minor release で出ると思うので待ち遠しいです. \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/remake-blog-with-nextjs-nowsh.md b/packages/applications/turbo-blog/src/articles/public/remake-blog-with-nextjs-nowsh.md deleted file mode 100644 index 867a8ecb..00000000 --- a/packages/applications/turbo-blog/src/articles/public/remake-blog-with-nextjs-nowsh.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: Next.jsとnow.shでブログを新しく作り替えた -tags: [Blog,Programming, JavaScript,React] -description: | - [Next.js 9](https://nextjs.org/blog/next-9) - 7月8日Next.jsのv9リリースが発表されました。 - - 実はこのブログの前身もNext.jsで書かれていて書いた当時はまだv8でした。でv9リリースからおよそ5ヶ月が経ってやっと、重い腰を上げて自分のブログのアップデートを試みました。 - ですが蓋を開けるとあら不思議、あまりの~~クソ~~コードぷりになかなか作業が進まない。 - 具体的に言ってしまうと@ts-ignoreとanyのオンパレードで下手したらJSのまま作業するよりも酷い代物が出来上がっていました。 - そんなものをアップデートしようとしても全然コンパイルが通らず、しかもバカ遅い。 - ちなみにこれが書き換える前のlighthouseのスコア、無慈悲な0点に涙を禁じ得ません。 - そしてもう何もかもが無理になり一から作り直してしまうことにしました() -publishedAt: 2019/12/14 -updatedAt: 2019/12/14 ---- - -asdfasdfasdfasdf## 作り替えに至った経緯 - -[Next.js 9](https://nextjs.org/blog/next-9) -7月8日Next.jsのv9リリースが発表されました。 - -実はこのブログの前身もNext.jsで書かれていて書いた当時はまだv8でした。でv9リリースからおよそ5ヶ月が経ってやっと、重い腰を上げて自分のブログのアップデートを試みました。 -ですが蓋を開けるとあら不思議、あまりの~~クソ~~コードぷりになかなか作業が進まない。 -具体的に言ってしまうと@ts-ignoreとanyのオンパレードで下手したらJSのまま作業するよりも酷い代物が出来上がっていました。 -そんなものをアップデートしようとしても全然コンパイルが通らず、しかもバカ遅い。 -![27-1](/assets/remake-blog-with-nextjs-nowsh/27-1.jpeg) -ちなみにこれが書き換える前のlighthouseのスコア、無慈悲な0点に涙を禁じ得ません。 -そしてもう何もかもが無理になり一から作り直してしまうことにしました() - -## やったこと -ここからだらだらと箇条書きになります。 - -* SSRした - -実は以前のブログはstatic file exportしたものを一々FTPしてました(ぇ -Next.jsのSSR (with rehydration) はTTFBがちょっと辛いというのはありましたが、以前のぐっちゃぐちゃになっていたものに比べるとかなり早くなりました。 -(~~それでもまだ速さが物足りないしブログにSSRはミスマッチな気がするからGatsbyに乗り換えたい~~) - -* ダークモードに対応した - -スマホやブラウザのダークモード、ライトモードそれぞれによって微妙に異なる配色を採用するようにしています。 -cssのprefers-color-schemeというメディアクエリで対応できたので、そこでcss変数作ってよしなにやりました。 -prefers-*はユーザーの閲覧環境に関するメディアクエリで、まだ実装はされてない(はず)ですけど今後はアニメーションの動きを減らすか否か、コントラストが高いか低いかというのにも対応できるようになるっぽい? - -* 画像の遅延読み込み - -ブログのコンテンツ一覧のページのアイキャッチ?画像の読み込みがボトルネックになっていたので、低解像度のデフォルトとなる画像をあらかじめ読み込んで表示させておき、Intersection Observer APIというターゲットとなる要素について、それが指定された要素あるいはビューポートと*交差*するたびに呼ばれるコールバック関数を定められるAPIを用いています。 -僕はuseEffect(componentDidMound)の中で、windowのloadイベントでIntersectionObserverを定め〜って感じの実装にしました。 -これにより、ファーストビューではブログのアイキャッチ画像は低解像度のものが表示され、帯域の節約になりもちろんロード時間も減ります。そして下にスクロールしてそれが表示される!!ってなると(ビューポートと交差すると)新たに普通の解像度のその記事のアイキャッチ画像が読み込まれ差し込まれるという具合です。 -僕の場合これがかなり速度に貢献した。 - -* webフォントとの別れ - -Unicode-rangeで帯域減らしたといえど4.7MBは辛かった、以上 - -* animationをkeyframesで表現 - -以前は[Ant Motion](https://motion.ant.design/components/tween-one)のtween oneというライブラリを用いてアニメーションを表現していたけれど、僕のCSS習熟度が上がりこれ別にkeyframesで表現できるくねってなった、あとはやるだけ。 -ちなみにトップページの惑星の公転周期っぽいアニメーションは - -```JSX -
-
- -
-
-``` - -みたいな感じで二つのdivでラッピングして、target_{x|y}にそれぞれx軸,y軸方向のtransformを与えて、animation-timing-functionにease-in-outを与えてあげると、x軸方向、y軸方向に同時にease-in-outに動き〜となってその二つの動きが合成されて円周上を回転する(語彙力) -あとはz-indexの魔法をかけておしまい。 - -* now.shでデプロイ - -zeitの提供する静的サイトプラットフォームの[now.sh](https://zeit.co/dashboard)を使ってデプロイした。 -githubと連携できて、各コミットごとにデプロイされて、master pushで本番環境に反映されるという感じでとてもDXが良い - -* any, @ts-ignoreとの別れ - -用法用量見極められるようになるまでは。。 - -* textlintの導入 - -markdownと言った文章の推敲をしてくれるというもの。 -こんな感じで怒られる -![27-3](/assets/remake-blog-with-nextjs-nowsh/27-3.png) -僕はGithub Actionsを使ってプルリクごとに走らせている。 -自分の日本語力のNASAに直面させられて辛い。 - -* sitemapの自動生成 - -今まではブログのコンテンツの追加のたびにsitemapも書き換えていたけれど、API routesでapiを用意して、そこを叩くとsitemap.xmlが生成されて返されるという仕組みにした。 - -* AntDesignは続投 - -一番好きなUIライブラリーまである。Headings Anchorとか変態だと思う。 - -* MathJaxを突っ込む - -Texで数式を描けるようにしました。やったね!ブログでも数学ができるよ!(~~やるとは言ってない~~) - -## やらなかった/やれなかったこと - -* webp対応 - -力尽きた。。 -safariさんはwebp対応をやな。。 - -* server push - -nextjsでserver pushするのどうするんや。。ってなって詰んでます。。 -求)知見 - -* cache - -同上、Cache-Control触ってない。。 - -* CDN - -Fastly触りたかったけど月50$-は貧乏学生には厳しい。。 - -## 結果 - -![27-2](/assets/remake-blog-with-nextjs-nowsh/27-2.png) -一応ここまではスコアが伸びた。 -ただブログでこのスコアか。。って辛さはある。 - -元気がでたらまたいろいろ触ってみます。 -とりあえずしばらくは数学と物理の試験に追われます。 \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/what-is-TypeScript-s-reversal.md b/packages/applications/turbo-blog/src/articles/public/what-is-TypeScript-s-reversal.md deleted file mode 100644 index 334ebfb1..00000000 --- a/packages/applications/turbo-blog/src/articles/public/what-is-TypeScript-s-reversal.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: TypeScriptの反変とどう向き合うか -tags: [Programming,JavaScript] -description: | - お久しぶりです、しにゃいです。 - TypeScript いいですよね、静的型付けにより今あなたが触っているプロジェクトをより安全に進めて行くことができます。 - しかしそんな TypeScript さんもなんだこれは、といってしまうような一見よくわからない挙動をすることがあります。 - この記事ではその中の一つともいえよう反変について扱っておこうかなと思います。 -publishedAt: 2019/08/28 -updatedAt: 2019/08/28 ---- - -## はじめに -お久しぶりです、しにゃいです。 - TypeScript いいですよね、静的型付けにより今あなたが触っているプロジェクトをより安全に進めて行くことができます。 -しかしそんな TypeScript さんもなんだこれは、といってしまうような一見よくわからない挙動をすることがあります。 -この記事ではその中の一つともいえよう反変について扱っておこうかなと思います。 - -## 反変とは -まず反変とはについてから知りましょう。そのために共変、反変という概念を知りましょう。 -それぞれ - -* 共変:型の順序関係を維持する -* 反変:型の順序関係を反転させる - -となっています。 -もうちょっと言うと -Cat ⊆ Animal(この例だと真部分集合になりますのでこの記号は不適切ですが)となるような奴に対して、 Cat , Animal に何かしようとなってその時に型の順序関係が維持されるか否かが共変、反変となります。 -でもパッと辞書的な意味を見せられてもいまいちピンと来ないですよね。 -なので TypeScript さんに共変と反変の例を見せてもらいましょう。 - -## 教えてTypeScriptさん - -```TypeScript -type Animal = "Cat" | "Dog" | "Pig" | "Cow" | "Chicken" -type Cat = "Cat" - -declare let cat:Cat; -declare let animal:Animal; - -cat = animal; //Error -animal = cat; //OK - -declare let catArray:Cat[]; -declare let animalArray:Animal[]; - -catArray = animalArray; // Error -animalArray = catArray; // OK -``` - -まずこれは共変の一例です。Cat Type に Animal Type を代入しようとしてエラーが生じています。逆に Animal Type に Cat Type を代入してもエラーは生じません。 -これは直感的に理解しやすい事象かなとは思います。 Cat Type に Animal Type を代入しようとするともしかすると Cow が入ってくるかもしれませんしこれを弾いてくれるのは感謝の極みでしょう。逆に Animal Type に Cat Type が入り得るのも至極妥当な話といえましょう。 -因みに TypeScript はこんなエラーを吐いてくれています。 - -![25-3](/assets/what-is-TypeScript-s-reversal/25-3.png) - -Animal Type を Cat Type へは入れられないよと教えてくれて、その一例として Dog をあげてくれています。因みにこの時Animal Type は Cat Type の SuperType (より上位の概念といった感じ)といったりします(この逆は SubTypeです)。 - -そして上記の型の理由から catArray は animalArray で置き換え不可能です(なんどもいうように Cow とかがくる可能性があるので) -しかしその逆に animalArray は catArray で置き換え可能です。 -そしてその Cat Type から構成される配列と Animal Type から構成される配列とを比較すると型の順序関係が Cat Type と Animal Type の関係から維持されていることがわかり、配列を構成する演算子は共変であるといえましょう。 - -では次に反変の例を見て見ましょう。 - -```TypeScript -type Animal = "Cat" | "Dog" | "Pig" | "Cow" | "Chicken" -type Cat = "Cat" - -declare let cat:Cat; -declare let animal:Animal; - -cat = animal; //Error -animal = cat; //OK - -declare let catFunc:(cat:Cat) => void; -declare let animalFunc:(animal:Animal) => void; - -catFunc = animalFunc; // OK -animalFunc = catFunc; // Error -``` - -こういう感じになります。 -前もって触れておきますが、実は上で Error となっているところはデフォルトの TypeScript さんはスルーします。これはv2.6から追加された --strictFunctionTypes によってこれを弾いてくれるようになります。もちろん --strict でも弾くことができます。 -でも上記の例とは逆に、catFunc に animalFunc を入れると TypeScript はエラーを投げず、 animalFunc に catFunc を投げるとエラーを投げます。これはちょっと直感に反することかもしれません。 -だって!!上で!! Cat Type に Animal Type を入れると!!エラーになるやんゆうてたやん!!ってなるじゃないですか。 -実はこれ根本的には共変の時に起こるエラーと雰囲気は変わりません。 - -![25-4](/assets/what-is-TypeScript-s-reversal/25-4.png) - -因みに TypeScript が吐くエラーはこんな感じ。 -この時 catFunc の引数である Cat と、 animalFunc の引数である Animal について、 Animal は Cat のSuperTypeですから、より引数として寛容といえましょう。 -つまり catFunc は animalFunc で置き換え可能ということです。そしてその逆は不可能ということになります。 -もうちょっと詳細にいえば catFunc を animalFunc に置き換えても catFunc が受け取るはずだった Cat Type の引数は全部受け止められます。 -でもその逆に animalFunc を catFunc に置き換えると animalFunc が受け取り得る Dog Type 等の引数を受け止められなくなります。 -それがTypeScriptが警告している文面の意味です。 -こう考えると逆に --strictFunctionTypes が効いていないと Error が生じないのも変というか型保全性の面から考えると怖い話なような気がしますね(公式曰くただぱっと見ありえそうな感じがするからみたいな理由があった気がする) -一つ誤解しないで欲しいのは TypeScript が反変性をフォローしているのは全然厄介なことではなくて、むしろ型保全性の面から見ればヒューマンエラーをより減らせる素晴らしいことです。 -因みにですが反変が起こってエラーが生じたときは TypeScript の吐くエラー文も順序が反転しています。 -ていうか基本的に関数引数の型と関数は反変の関係になるっぽい(?)です。(だからこその--strictFunctionTypesなのかなと) - -個人的にはこの辺のややこしさと上手く付き合って行くには深いところでの「型を保ったまま置き換えが可能か」という意識と、ゆるふわな浅いところでの「関数引数の型と関数は反変の関係になる」っていう意識を持つとよくて、さすればいい感じに TypeScript とその反変性に向き合って、より安全にコードを無駄に沼にはまったりせず書けるでしょう。 \ No newline at end of file diff --git a/packages/applications/turbo-blog/src/articles/public/without-create-react-app.md b/packages/applications/turbo-blog/src/articles/public/without-create-react-app.md deleted file mode 100644 index 36029ddf..00000000 --- a/packages/applications/turbo-blog/src/articles/public/without-create-react-app.md +++ /dev/null @@ -1,319 +0,0 @@ ---- -title: 脱create-react-app、Reactアプリの小さめ構築 -tags: [Programming, JavaScript, React] -description: | - 突然ですがみなさん、React アプリ構築に create-react-app 使わないと出来ないのにフロントエンジニア名乗ってるなんてまさかですけどないですよね???webpack の設定いつも適当にコピペしてたりなんてしていませんよね??? - (まあ僕も割とこんな感じだったので人の事は言えませんが) - 今回は上記の煽りであ、やばいかもと思った人向けの記事です。 - タイトルの通り create-react-app 無しでの React アプリ構築の手順(というか比較的小さい構築)をやっていこうかなと思います。(思ったより適当な日本語記事がなかったので) - webpack,TypeScript あたりを使ってやって行く予定です。 - 目標は"Hello React"と書き出すとこまでです。 - え??しょぼくない??と思う方もいると思われますが、これ以降の簡単なアプリ作ったりってのは結構どの記事でもやられているのでそちらを参考にしてほしいなという感じです。 - - また特にモジュール積みのところでガンガン module についての記事を載せたり、公式のドキュメントを載せていますが、これはイマイチわからない人は読んだ方がいいんじゃない?というくらいの気持ちで載せたので読む体力がないのであれば今は飛ばしても結構かと思われます。いつか思い出した時にでも読んでください。 -publishedAt: 2019/08/10 -updatedAt: 2019/08/10 ---- - - -## はじめに - -突然ですがみなさん、React アプリ構築に create-react-app 使わないと出来ないのにフロントエンジニア名乗ってるなんてまさかですけどないですよね???webpack の設定いつも適当にコピペしてたりなんてしていませんよね??? -(まあ僕も割とこんな感じだったので人の事は言えませんが) -今回は上記の煽りであ、やばいかもと思った人向けの記事です。 -タイトルの通り create-react-app 無しでの React アプリ構築の手順(というか比較的小さい構築)をやっていこうかなと思います。(思ったより適当な日本語記事がなかったので) -webpack,TypeScript あたりを使ってやって行く予定です。 -目標は"Hello React"と書き出すとこまでです。 -え??しょぼくない??と思う方もいると思われますが、これ以降の簡単なアプリ作ったりってのは結構どの記事でもやられているのでそちらを参考にしてほしいなという感じです。 - -また特にモジュール積みのところでガンガン module についての記事を載せたり、公式のドキュメントを載せていますが、これはイマイチわからない人は読んだ方がいいんじゃない?というくらいの気持ちで載せたので読む体力がないのであれば今は飛ばしても結構かと思われます。いつか思い出した時にでも読んでください。 - -## 賽の河原で module 積み - -取り敢えず最低限必要な module をガンガン積んで行きます。 -Node 使えないピヨという方は以下の記事を読んでから進んでください(Node からやってはこの記事の目指すところからズレるので)。 -[Node.js を 5 分で大雑把に理解する](https://qiita.com/hshimo/items/1ecb7ed1b567aacbe559) - -以下の記事では npm で module を積んで行きますが yarn をお使いの方は適宜読み替えてください。 - -まず作業するディレクトリを作っちゃいましょう。 -取り敢えず初期化だけやっちゃいます。 - -```Console -mkdir without-create-react-app -cd without-create-react-app -npm init -``` - -これするといくつか質問が飛んでくると思います。これは今から作ろうとしているものがどんなものなのかという基本情報です。チュートリアルとかで作るものにそれらは不要なので今回の場合は面倒であれば適当に Enter 連打して大丈夫です。(後から書き換えられますし) - -こっから module 積みの時間です。いい感じに小分けして行きますが多分大変です() -ある程度流し見しても大丈夫かと思われます。 - -```Console -npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin -``` - -[webpack](https://webpack.js.org/)はバンドルツールのことです。バンドルという言葉からもわかりそうですが、要するにいくつものモジュールからなるものを一つに纏め上げるツールです。 -もっと言えば CommonJS の持つ module を読み込む require 機能をブラウザ上でも使えるようにするためのものです。 -webpack-cli は webpack4 から、webpack から分離されたものだそうです。 -webpack-dev-server は開発用のローカルサーバーを建てるために要るやつです。 -html-webpack-plugin は webpack 用のプラグインです。あとでその用途がわかります。 -この辺について詳しくは以下の記事がいいかと思います。 -[webpack 4 入門](https://qiita.com/soarflat/items/28bf799f7e0335b68186) - -```Console -npm install --save-dev react react-dom -``` - -はい、出ました[React](https://reactjs.org/)さんです。 -React さんは表示が得意な facebook 製のライブラリです。 -もっと言えば state(そのアプリの状態を表す変数的な?)に合わせて表示するのが得意って感じですかね。 -例えば簡単な計算機を実装するとして、計算結果を表すために、計算結果が入って要る変数を表すのって結構手間というかどうしても実装が汚くなってしまうんですよね(でもやろうと思えば初学者の方でも結構できてしまいますが)。 -それを React さんはそこをめっちゃ鮮やかに - -```TypeScript -return( -
{result}
-) -``` - -こんな感じでやればあとは result という state の値に変更を加えるだけでぽぽぽっと React さんが表示をやってくれるというやつです、末恐ろしや。 - -```Console -npm install --save-dev typescript -``` - -毎度おなじみ[TypeScript](https://www.typescriptlang.org/index.html)さんです。 -これは本来動的型付け言語であった JavaScript を静的に書いてより安全に書けるようにするお!!ってやつです。 -TypeScript に関してはうひょさんの記事がめちゃくちゃおすすめ -[TypeScript の型入門](https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a) - -```Console -npm install --save-dev babel-loader ts-loader path -``` - -webpack に渡す loader を積んで行きます、ついでに path も。 -これで長きに渡る賽の河原での module 積みは終わりです、お疲れ様でした。 -次からは設定ファイルを書いて行きましょう。 - -## config を書いて行く - -次は config ファイルを書いて行きます。 -退屈な時間ですがこれもめちゃくちゃ大事な作業ですので頑張りましょう。 -package.json,webpack.config.js,tsconfig.json を書いて行きます。 - -まず package.json ですがこれは書くというよりは一行書き足して欲しいだけで、 - -```JSON -"scripts": { - "test": "echo \"Error: no test specified\" && exit 1" -} -``` - -こうなって要るところを - -```JSON -"scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "dev": "webpack-dev-server -} -``` - -これは webpack-dev-server を呼び出すコマンドを決めるためです。 - -でお次に webpack.config.js ですがここには webpack の設定をゴリゴリ書いて行きます。 -でもどうせコピペすればいいんでしょう??と思ったあなた、そんな人生甘くありません。この記事では分割してうだうだ書いて行きます。(一応最後にこの記事で言われたことを全部やったら出来上がる git リポジトリ上げておくので困ったらそれを参照して見てください) -まず必要なものを読み込んで吐かせます。 - -```JavaScript -const path = require('path') -const HtmlwebpackPlugin = require('html-webpack-plugin') - -module.exports = { - (略) -} -``` - -でこの略の部分をガンガン埋めて行くというのが次の工程ですね。 - -```JavaScript -mode: 'development', - -entry: './src/index.tsx', -output: { - path: path.resolve(__dirname,'dist'), - filename: 'bundle.js' -}, - -devServer: { - port: '3000', - hot:true, - open:true -}, -``` - -mode には production か development を突っ込みます。この場合は開発中ですので development を突っ込みましょう。 -entry にはバンドルする際の始点とするファイルを教えます。 -output でバンドルさせた後そのファイルを出力する際の設定を教えます。この場合 dist/ディレクトリのなかに bundle.js というファイル名で出力されるということになります。 -devServer で webpack-dev-server 使って開発用のサーバー建てた時の設定を教えます。 -port には localhost のポート番号、hot を true にすることで hot reload(JavaScript ファイルに変更があった時更新する)を有効に、open を true にすることで localhost を建てた時ブラウザで開く様に設定しています。 - -```JavaScript -{ - module: { - rules:[ - { - test: /\.js(x?)$/, - loader:'babel-loader', - exclude: /node_modules/, - }, - { - test: /\.ts(x?)$/, - loader:'ts-loader', - exclude: /node_modules/, - } - ] - }, - plugins: [ - new HtmlwebpackPlugin({ - template: './src/index.html' - }) - ], - - resolve: { - extensions: ['.js','.ts','.tsx'] - } -} -``` -moduleのなかでこんな拡張子のファイルはこんな感じで処理して行くお!!ってのをwebpackに教えて行きます。 -pluginでプラグインを使っているのですが、このHtmlwebpackPluginを使うことでhtmlファイルも一緒にバンドルすることができます。 -要するにoutputに出力されるファイルにhtmlファイルも一緒になってくれるというやつです。 -resolveのextensionsで.js,.ts.tsxの三種類の拡張子を指定してあげることでmoduleをimportするときに拡張子を忖度してくれる様になります。(てかこれを書かないとまずtsエラーになる気がしますが) -これでwebpackの設定は終了です。 - -次はtsconfig.jsonでtypescriptの設定をやって行きましょう。 -tsconfig.jsonについては各オプションについて詳しく説明して要るとめっちゃ長くなってしまうので調べてください(~~僕も疲れてきたので~~) -```JSON -{ - "compilerOptions": { - "module": "commonjs", - "noImplicitAny": true, - "strictNullChecks": true, - "removeComments": true, - "preserveConstEnums": true, - "sourceMap": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "allowJs": true, - "esModuleInterop": true, - "jsx":"react" - }, - "exclude": [ - "node_modules", - "webpack.config.js", - "dist" - ] -} -``` -これで設定ファイルをあれこれは終わりです!!やったね!! - -## コードを書く -やっとコードを書いて行きましょう。 -ここまできたら後もう少しです(割とマジ) -まずはファイルの準備から - -```Console -mkdir src -cd src -``` -これで作られたsrcディレクトリの中で -```Console -touch index.html index.tsx -mkdir components -cd components -touch App.tsx -``` - -![21-2](/assets/without-create-react-app/21-2.png) -とりあえずこんな感じの構成になったらOKです。 -こっから書き込んで行きましょう。 -まずindex.htmlファイルから - -```HTML - - - - ReactApp - - -
- - - -``` - -こんな感じで書きます。id=appになってる要素に対してreactがrenderして行く感じです。 -あれ、jsファイル読み込んでなくないって思うじゃないですか?webpackにぶっこんだhtml-webpack-pluginがいい感じにjsファイルを読み込んだscriptタグを足して出力してくれるんですよね。いやめっちゃ便利。 -ちなみに出来上がるHTMLファイルはこんな感じ。 -![21-3](/assets/without-create-react-app/21-3.png) -で次はJavaScriptファイルをまとめて行きましょう。 -まずはcomponents/内のApp.tsxから。 - -```TypeScript -import React from 'react' - -export default function App() { - return ( -
- HELLO -
- ) -} -``` -ひとまずこんな感じでパッとコンポーネント作ってしまいます。 -ちなみにVSCode使ってる方でしたら、es7という拡張機能を入れればrfcと打ち込むだけでベースとなる部分を一括で作ってくれるのでめっちゃおすすめです。 -![21-4](/assets/without-create-react-app/21-4.gif) -で次はindex.tsxを書いて行きましょう。 - -```TypeScript -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './components/App'; - -const target = document.getElementById('app'); - -ReactDOM.render( - - ,target -) -``` -これでtargetに指定されたところにAppコンポーネントがレンダリングされます。 -まずターミナルにてwebpackを実行してみましょう。 -そうするとdistファイルが以下の様に出力されます。 -![21-5](/assets/without-create-react-app/21-5.png) -そして出力されたdist/以下のindex.htmlを開けばこんな感じになります、成功です。 -![21-6](/assets/without-create-react-app/21-6.png) -で次はターミナルにて -```Console -npm run dev -``` -を実行してください。これでwebpack-dev-serverが走ってくれます。 -でindex.htmlを開いた時とおんなじ様な表示がなされると思います。 -じゃあApp.tsxのHELLOの部分をHELLO React!!に書き換えてみましょう。 -```TypeScript -import React from 'react' - -export default function App() { - return ( -
- HELLO React!! -
- ) -} -``` -無事変更が検知されて以下の様になると思います、ようこそReactへ!! -![21-7](/assets/without-create-react-app/21-7.png) - -一応僕が作った、この記事の通りに作ればこうなるはずだよ!!!って感じのgitリポジトリを下に置いておきます。 -[完成品](https://github.com/Shinyaigeek/without-create-react-app) \ No newline at end of file