{"id":20083658,"url":"https://github.com/marko-js/tutorial-blog","last_synced_at":"2025-03-02T13:44:40.331Z","repository":{"id":149788868,"uuid":"457148703","full_name":"marko-js/tutorial-blog","owner":"marko-js","description":"Blog site tutorial to demonstrate basic concepts in Marko","archived":false,"fork":false,"pushed_at":"2022-03-29T00:05:48.000Z","size":86,"stargazers_count":6,"open_issues_count":1,"forks_count":8,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-01-13T01:48:42.938Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Marko","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marko-js.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-09T00:15:09.000Z","updated_at":"2024-01-07T04:39:49.000Z","dependencies_parsed_at":"2023-06-02T15:15:20.834Z","dependency_job_id":null,"html_url":"https://github.com/marko-js/tutorial-blog","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Ftutorial-blog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Ftutorial-blog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Ftutorial-blog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marko-js%2Ftutorial-blog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marko-js","download_url":"https://codeload.github.com/marko-js/tutorial-blog/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241515959,"owners_count":19975140,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T15:48:20.695Z","updated_at":"2025-03-02T13:44:40.299Z","avatar_url":"https://github.com/marko-js.png","language":"Marko","funding_links":[],"categories":[],"sub_categories":[],"readme":"Marko Blog Tutorial w/ Vite + Cloudflare Workers\n==================================\n\nThis repo is setup to be a companion to Marko Blog Tutorial Workshop to teach the basics of Marko through building a simple blog site. It will cover component authoring, data fetching, mutation, and deployment to Cloudflare.\n\nThe repo itself is broken up into multiple branches one representing each step of the tutorial. The main branch will contain the final working version of the code as well.\n\nThis repo is meant to serve as reference. The tutorial workshop itself given in more detail is available here: `_______`\n\n## Tutorial\n\n### Step 1: Exploring the Template\n\nThis tutorial is adapted from Marko's Vite/Cloudflare template and the first step is clone down our starting point from the Step1 branch. After cloning navigate into the directory install and run the dev server:\n\n```bash\nnpm install\nnpm run dev\n```\n\nIf all is right when you open `http://localhost:3000` in the browser you should see a grey screen with `Hello Blog`.\n\nThis branch contains all the basic setup for the workers, routing, development environment, data bootstrapping, and our page layout that we will be using for the remainder of the tutorial.\n\n### Step 2: Fetching Blog Listings\n\nThis step updates the main index.marko entry point to add data fetching. It shows how the `\u003casync\u003e` tag is used to fetch and disply content loaded from the server.\n\n### Step 3: Creating Blog Posts with Forms\n\nThis step adds a \"New Blog Post\" page that shows how we can use the built in mechanism of Forms in the web platform to add new Blog posts. This shows how browser built in methods for posting Forms and Form validation can be used to your advantage.\n\n### Step 4: Adding Interactive JavaScript\n\nIn this step we add the details view of the Blog Post. It fetches the data for the Blog post as well as adds the ability to add Comments. This step introduces stateful components and will update the Comments completely in the browser using JavaScript. However, we still use forms so that the page is completely functional even when JavaScript is not available in the browser.\n\n### Step 5: Optimizing Hydration Performance\n\nIn this step we update our handling of Comments to better optimize the experience for end users. We will learn how to make Partial Hydration work for you.\n\n## Deploying to Cloudflare\n\nThis example uses a custom KV Storage on Cloudflare, that we emulate in the development environment. In addition to configuring your `wrangler.toml` with your account information and updating the project name you will need to allocate a new KV store on your cloudflare account.\n\n```sh\n\u003e wrangler kv:namespace create --preview \"STORAGE\"\n```\nThis will return the keys you need to add to your wrangler.toml like:\n\n```\nkv_namespaces = [\n  { binding = \"STORAGE\", preview_id = \"a33ce8e331f24b10a1e6bad43949f384\", id = \"aab664c75e4420639ddd6911a06ecaa4\" }\n]\n```\n\n## Base Template Reference\n\n### Production Preview\nFirst you'll need to authenticate with `cloudflare` and install the [`wrangler cli`](https://developers.cloudflare.com/workers/cli-wrangler). If you've not already done this, follow [the cloudflare workers getting started guide through step 3](https://developers.cloudflare.com/workers/get-started/guide#3-configure-the-workers-cli).\n\n```bash\nnpm run build\nnpx wrangler dev\n```\n\n### Routing\nThis simple example comes with file system based routing implemented using [Vite's glob imports](https://vitejs.dev/guide/features.html#glob-import). It follows similar conventions to [Remix](https://remix.run/docs/en/v1/guides/routing#review).\n\nAny top level `.marko` (and `.js`) file under the `./src/pages` directory will automatically be served according to it's path on disk.\nWe automatically exclude any `components` directories.\n\nFor dynamic routes you can prefix the file/folder name with `$`. Or to save creating a folder use an extension that starts with a `$`.\n`index` folders and files are also stripped from the path being matched.\n\nHere are some example file system paths, and what their route format ultimately becomes.\n\n```bash\n# Static routes\n./pages/index.marko =\u003e /\n./pages/story.marko =\u003e /story\n./pages/story/index.marko =\u003e /story\n./pages/api/user.js =\u003e /api/user\n\n# Dynamic routes\n./pages/story/$id.marko =\u003e /story/:id\n./pages/story.$id.marko =\u003e /story/:id\n```\n\nFor `.marko` files the `input` for the page component will be an object like the following:\n\n```js\n{\n  url: new URL(...), // a URL instance for the current request.\n  request: new Request(...), // The current Request object.\n  params: { ... } // An object containing all matched params for the dynamic paths.\n}\n```\n\nIf a `.js` file is used, it must `export default` a handler function that returns a web `Response` object.\nIt will receive the same object as described above, for example it may look like:\n\n```js\n// Handles `GET` requests to the current path.\nexport default ({ request, url, params }) =\u003e {\n  return new Response(\"Hello!\", { status: 200 });\n}\n```\n\n### Form Handlers / POST requests\nIn both `.marko` and `.js` files you can also expose an `action` export to handle `POST` requests.\n\n```js\n// Handles `POST` requests to the current path.\nexport async function action({ request, url, params }) {\n  await saveSomeData();\n  return Response.redirect(request.headers.get(\"referrer\") || \"/\", 303);\n}\n```\n\n### Common Template for multiple routes\nSometimes you may want to have the same `.marko` component used for multiple routes in your application.\nTypically this is done to make the URL a bit prettier and it may be best to simply use a query string or other mechanism instead of multiple pathnames.\n\nHowever this can be done simply by creating a `.js` file at the alternative paths and re-exporting the `.marko` component from there.\n\n```js\nimport Template, { action } from \"./another-template-path.marko\";\nexport { Template as default, action }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarko-js%2Ftutorial-blog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarko-js%2Ftutorial-blog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarko-js%2Ftutorial-blog/lists"}