{"id":16836681,"url":"https://github.com/jaredreich/dowels","last_synced_at":"2025-04-11T05:11:09.338Z","repository":{"id":57215642,"uuid":"57150593","full_name":"jaredreich/dowels","owner":"jaredreich","description":"🔨 a tiny but powerful javascript library that performs client-side routing, templating, and REST API communication to help you get your single-page web applications running in seconds","archived":false,"fork":false,"pushed_at":"2016-10-23T17:30:52.000Z","size":329,"stargazers_count":14,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-03T11:37:33.291Z","etag":null,"topics":["fast","javascript","routing","single-page-applications","small","spa","template","templating"],"latest_commit_sha":null,"homepage":"https://jaredreich.com/dowels","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaredreich.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-26T18:02:09.000Z","updated_at":"2023-08-03T19:46:50.000Z","dependencies_parsed_at":"2022-08-26T13:31:36.270Z","dependency_job_id":null,"html_url":"https://github.com/jaredreich/dowels","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredreich%2Fdowels","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredreich%2Fdowels/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredreich%2Fdowels/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredreich%2Fdowels/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaredreich","download_url":"https://codeload.github.com/jaredreich/dowels/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248345266,"owners_count":21088244,"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":["fast","javascript","routing","single-page-applications","small","spa","template","templating"],"created_at":"2024-10-13T12:14:25.732Z","updated_at":"2025-04-11T05:11:09.316Z","avatar_url":"https://github.com/jaredreich.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"![Alt text](/dowels.png?raw=true \"logo\")\n\n[![codecov](https://codecov.io/gh/jaredreich/dowels/branch/master/graph/badge.svg)](https://codecov.io/gh/jaredreich/dowels)\n\ndowels is a tiny but powerful javascript library that performs client-side routing, templating, and REST API communication to help you get your single-page web applications running in seconds without having to learn huge fancy frameworks like Angular, React, etc. Demo: https://jaredreich.com/projects/dowels\n\n## Features\n- Pure JavaScript (no dependencies)\n- Tiny size (4kB minified)\n- Easy and intuitive routing (Express style, supports parameters and wildcards)\n- Simple and fast (caching) template rendering (Embedded JavaScript style)\n- Handy HTTP request helpers\n\n## Browser support\n- IE 10+\n- Firefox 4+\n- Chrome 5+\n- Safari 6+\n- Opera 11.5+\n\n## Installation\nHTML:\n```html\n\u003cbody\u003e\n\t...\n\t\u003cscript src=\"https://unpkg.com/dowels\"\u003e\u003c/script\u003e\n\u003c/body\u003e\n```\nnpm:\n```\nnpm install dowels\n```\nbower:\n```\nbower install dowels\n```\n\n## Important requirement: your server must allow a changing URL path\nThis means that your main application URL path (example.com/app) and any other subsequent URL paths (example.com/app/*) must always route to the main index.html file.\n\n### How to achieve this:\n#### Node.js \u0026 Express\n```\napp.use(express.static(__dirname + '/public'));\napp.get(['/app', '/app/*'], function(req, res) {\n\tres.sendFile('index.html', { root: __dirname + '/public' });\n});\n```\n\n#### Apache \u0026 .htaccess\n```\nRewriteEngine on\nRewriteCond %{REQUEST_FILENAME} -s [OR]\nRewriteCond %{REQUEST_FILENAME} -l [OR]\nRewriteCond %{REQUEST_FILENAME} -d\nRewriteRule ^.*$ - [NC,L]\nRewriteRule ^(.*) /index.html [NC,L]\n```\n\n#### NGINX\n```\nserver {\n\t...\n\tlocation /app/ {\n\t\t/path/to/index.html\n\t}\n}\n```\n\n## Usage\n```javascript\ndowels.config({\n    root: '/projects/dowels', // root path of your app\n    containerId: 'app', // HTML container of your app's content\n    titleBase: 'dowels: app', // base of HTML title for tabs/favorites/history\n    apiBase: 'https://jaredreich.com/api/todos', // base of API endpoint for requests\n    onLoadStart: function() {\n        document.getElementById('loader').style.display = 'block';\n    },\n    onLoadStop: function() {\n        document.getElementById('loader').style.display = 'none';\n    }\n});\n\ndowels.add('/', function() {\n    dowels.render('app-template-home');\n});\n\ndowels.add('/todos', function() {\n    dowels.renderAfterRequest('app-template-todos', {\n        method: 'get',\n        endpoint: '/todos'\n    }, 'todos');\n});\n\ndowels.add('/todos/:id', function(parameters) {\n    dowels.renderAfterRequest('app-template-todo', {\n        endpoint: '/todos' + '/' + parameters.id\n    }, 'todo');\n});\n\ndowels.add('/*', function() {\n    dowels.redirect('/');\n});\n\ndowels.initialize();\n```\n\n```html\n\u003cbody\u003e\n\n\t...\n\n\t\u003c!-- Templates --\u003e\n    \u003cscript id=\"app-template-home\" type=\"text/html\"\u003e\n        \u003ch1\u003ehome page!\u003c/h1\u003e\n        \u003cbutton onclick=\"dowels.route('/todos');\"\u003eview todos\u003c/button\u003e\n    \u003c/script\u003e\n\n    \u003cscript id=\"app-template-todos\" type=\"text/html\"\u003e\n        \u003cbutton onclick=\"dowels.route('/')\"\u003e\u0026#8592; back home\u003c/button\u003e\n        \u003cbr\u003e\n        \u003cinput id=\"todoInput\" type=\"text\" placeholder=\"add a todo\"\u003e\n        \u003cbutton onclick=\"addTodo(document.getElementById('todoInput').value)\"\u003e+ add\u003c/button\u003e\n        \u003c# if (todos.length \u003e 0) { #\u003e\n            \u003cul id=\"collection-todos\"\u003e\n        \u003c#\n            for (var i = 0; i \u003c todos.length; i++) {\n                var todo = todos[i];\n        #\u003e\n                \u003cli\u003e\u003cspan onclick=\"dowels.route('/todos/' + '\u003c#= todo.id #\u003e')\" style=\"cursor:pointer;text-decoration:underline;\"\u003e\u003c#= todo.text #\u003e\u003c/span\u003e\u003cbutton style=\"padding:0;height:20px;margin-left:10px;\" onclick=\"removeTodo('\u003c#= todo.id #\u003e');\"\u003ex\u003c/button\u003e\u003c/li\u003e\n        \u003c#\t\t} #\u003e\n            \u003c/ul\u003e\n        \u003c# } else { #\u003e\n            \u003ch3\u003enothing to do!\u003c/h3\u003e\n        \u003c# } #\u003e\n    \u003c/script\u003e\n\n    \u003cscript id=\"app-template-test\" type=\"text/html\"\u003e\n        \u003ch3\u003etodo selected: \u003c#= todo.text #\u003e\u003c/h3\u003e\n    \u003c/script\u003e\n\n    \u003cscript id=\"app-template-todo\" type=\"text/html\"\u003e\n        \u003cbutton onclick=\"dowels.route('/todos')\"\u003e\u0026#8592; back to todo list\u003c/button\u003e\n        \u003c# if (err) { #\u003e\n            \u003ch3\u003e\u003c#= err #\u003e\u003c/h3\u003e\n        \u003c# } else { #\u003e\n            \u003c# include app-template-test #\u003e\n        \u003c# } #\u003e\n    \u003c/script\u003e\n\n\t\u003cscript src=\"/path/to/dowels.js\"\u003e\u003c/script\u003e\n\n\t\u003cscript\u003e\n\n\t    function addTodo(text) {\n            document.getElementById('todoInput').value = '';\n            var data = {\n                text: text\n            }\n            dowels.request({\n                method: 'post',\n                endpoint: '/todos',\n                body: data\n            }, function(res) {\n                dowels.renderAfterRequest('app-template-todos', {\n                    method: 'get',\n                    endpoint: '/todos'\n                }, 'todos');\n            });\n\n        }\n\n        function removeTodo(id) {\n            dowels.request({\n                method: 'delete',\n                endpoint: '/todos/' + id\n            }, function(res) {\n                dowels.renderAfterRequest('app-template-todos', {\n                    method: 'get',\n                    endpoint: '/todos'\n                }, 'todos');\n            });\n        }\n\n    \u003c/script\u003e\n\n\u003c/body\u003e\n```\n\n## Configuration and Options\n```javascript\ndowels.config({\n\n\t// use hash in url instead of hard url\n\t// default = true\n\t// ***NOTE*** see important requirement above if hash is set to false\n\thash: true,\n\n\t// root path of your app\n\t// default = '/'\n\troot: '/app',\n\n\t// HTML container of your app's content\n\t// default = 'app'\n\tcontainerId: 'app-content',\n\n\t// base of HTML title for tabs/favorites/history\n\t// default = document.title\n\ttitleBase: 'dowels: app',\n\n\t// base of API endpoint for requests\n\t// default = document.location.protocol + '//' + document.location.hostname + '/api';\n\tapiBase: 'https://dowels.io/api',\n\n\t// your choice of delimiter for the EJS  style templating\n\t// default = '#'\n\tdelimiter: '#',\n\n\t// runs when HTTP requests are in progress\n\t// default = function(){}\n\tonLoadStart: function() {\n\t\tdocument.getElementById('loader').style.display = 'block';\n\t},\n\n\t// runs when HTTP requests change state\n\t// default = function(){}\n\tonLoadUpdate: function(percent) {\n\t\tdocument.getElementById('loader').style.width = percent + '%';\n\t},\n\n\t// runs when HTTP requests are in finished\n\t// default = function(){}\n\tonLoadStop: function() {\n\t\tdocument.getElementById('loader').style.display = 'none';\n\t}\n});\n```\n## To-do\n- custom delimiter (ex. #, %, etc...)\n- tests + coverage\n- hash option for routing\n- more control over changing of document.title while routing\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaredreich%2Fdowels","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaredreich%2Fdowels","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaredreich%2Fdowels/lists"}