{"id":14975528,"url":"https://github.com/niallobrien/hackathon-starter-plus","last_synced_at":"2025-07-26T09:37:58.970Z","repository":{"id":145589764,"uuid":"72442334","full_name":"niallobrien/hackathon-starter-plus","owner":"niallobrien","description":"A boilerplate for Node.js web applications","archived":false,"fork":false,"pushed_at":"2018-12-14T17:02:44.000Z","size":12471,"stargazers_count":19,"open_issues_count":2,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-13T23:35:55.309Z","etag":null,"topics":["bootstrap3","es2015","expressjs","jquery","laravel-mix","mongoosejs","nodejs","passportjs","pjax","pug","sass","socket-io","webpack2"],"latest_commit_sha":null,"homepage":null,"language":"CSS","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/niallobrien.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2016-10-31T14:06:02.000Z","updated_at":"2022-02-13T19:45:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"ce372dae-a94e-4d0d-a0b6-dda0668cf13e","html_url":"https://github.com/niallobrien/hackathon-starter-plus","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/niallobrien/hackathon-starter-plus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niallobrien%2Fhackathon-starter-plus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niallobrien%2Fhackathon-starter-plus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niallobrien%2Fhackathon-starter-plus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niallobrien%2Fhackathon-starter-plus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niallobrien","download_url":"https://codeload.github.com/niallobrien/hackathon-starter-plus/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niallobrien%2Fhackathon-starter-plus/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267145959,"owners_count":24042657,"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","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["bootstrap3","es2015","expressjs","jquery","laravel-mix","mongoosejs","nodejs","passportjs","pjax","pug","sass","socket-io","webpack2"],"created_at":"2024-09-24T13:52:10.174Z","updated_at":"2025-07-26T09:37:58.941Z","avatar_url":"https://github.com/niallobrien.png","language":"CSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Hackathon Starter+](/../screenshots/hackathon-starter-plus.png?raw=true \"Hackathon Starter+\")\nHackathon Starter+\n=======================\n\nThis is a project which builds off the foundations of a node.js boilerplate called [Hackathon Starter](https://github.com/sahat/hackathon-starter).\n\nHackathon Starter focuses on providing a simple and easy to use node.js boilerplate for you to hit the ground running.\nHowever, if you want to take your app to production, there are a few changes you will want to make to the boilerplate \nto take it beyond a hackathon project.  \nAlso, since Hackathon Starter is intended for everyone (including beginners), there are certain things that will never \nbe included out of the box, such as Socket.io (websockets) support.\n\nHackathon Starter+ aims to provide a **post hackathon guide** so that you can take your projects to the next level.\n\nTable of Contents\n-----------------\n\n- [Features](#features)\n- [Prerequisites](#prerequisites)\n- [Getting Started](#getting-started)\n- [Contributing](#contributing)\n- [License](#license)\n\nFeatures\n--------\n\n- **Asset Pipeline** using Laravel Mix, Webpack with styles and scripts project skeleton structure\n- **Websocket Support** via Socket.io\n\nPrerequisites\n-------------\nYou need to have an existing Hackathon Starter project in place (existing or new).  \nSee [Getting Started](https://github.com/sahat/hackathon-starter#getting-started) within the Hackathon Starter \ndocumentation.\n\n\nGetting Started\n---------------\nIf you intend to use any of the files included with Hackathon Starter+, I highly recommend that you **don't** clone \nthis repo into your current Hackathon Starter project.  \nInstead, download the `.zip` file of this repo or just manually adjust/create the files where needed in your project \nand `copy \u0026 paste` over whatever pieces you want.\n\n**Remember:** Make sure that you copy/rename `.env.example` to `.env` and populate the environment variables with your own \nkeys/secrets.\n\nAsset Pipeline\n--------------\nWe're going to continue to use Bootstrap 4, Font-Awesome etc. however, what we want is to be able to build a \nproduction-ready version of our app that utilises some best practices, such as: \n- Development vs Production: Handle development assets differently from production assets.\n- Filename Fingerprinting: Each client-side file will get have a unique string of characters added to the filename.\nWhenever the contents of a file changes, the fingerprinted filename for production will also change. This will provide\nus with a good cache-busting solution.\n- Sass File Location: Sass files are moved out of the `public` directory so that no one can access our source Sass \nfiles.\n- Client-side JavaScript: Provide a good initial structure for your custom JavaScript code using the [module revealing \npattern](https://toddmotto.com/mastering-the-module-pattern/).\n- Code Splitting: separate our vendor (3rd party) JavaScript dependencies from our own custom JavaScript code.\n- Pre-built Assets: All Sass and JavaScript files are processed by Webpack in advance and not at runtime (as is \nthe case with Sass middleware using the default Hackathon Starter setup).\n\n### What To Remove\n\n**Note:** Line locations may vary based on what you have added/removed.\n\n`npm uninstall jquery node-sass node-sass-middleware --save`\n\n**Delete these folders:**  \n`public/css`  \n`public/js`  \n`public/webfonts`  \n\nOpen `app.js` at the top level of your project and remove *line 20* and the middleware shown below from *lines 66-69*\n```javascript\napp.use(sass({\n  src: path.join(__dirname, 'public'),\n  dest: path.join(__dirname, 'public')\n}));\n```\n\n### What To Add\n\n**Note:** Line locations may vary based on what you have added/removed.\n\n`npm install cross-env bootstrap glob-all jquery laravel-mix popper.js purgecss-webpack-plugin tooltip.js simple-pjax \n@fortawesome/fontawesome @ladjs/bootstrap-social --no-optional --save-dev`\n\nCopy the `assets` folder from this repo to your project.  \nCopy the `.gitignore` file from this repo to your project.\nCopy the `.webpack.mix.js` file from this repo to your project.\n\nWe now need to modify our app to handle development and production assets as the file names will be different.  \nIn `app.js` (where we create our Express server), in between lines *64* and *65* \n(after `app.set('view engine', 'pug');`), add the following:\n```javascript\n// Middleware for Jade/Pug custom filter for use with Laravel Mix\napp.use((req, res, next) =\u003e {\n  app.locals.filters = {\n    'mix': (text, options) =\u003e {\n      if (!text) return\n      text = text.replace(/[\"']/g, '')\n\n      const manifest = require(__dirname + '/public/mix-manifest.json')\n      if (options.css) return `\u003clink rel=\"stylesheet\" href=\"${manifest[text]}\"\u003e`\n      if (options.js) return `\u003cscript type=\"text/javascript\" src=\"${manifest[text]}\"\u003e\u003c/script\u003e`\n    }\n  }\n  next()\n})\n```\n\nIn `views/layout.pug` replace *line 11* with \n```pug\n:mix(css) '/assets/styles/app.css'\n```\n\nAt *line 25* add\n```pug\n:mix(js) '/assets/scripts/manifest.js'\n:mix(js) '/assets/scripts/vendor.js'\n:mix(js) '/assets/scripts/app.js'\n```\n\nNow that our app is updated, we just need to update how we run these new tasks.\nOpen the `package.json` file at the top level of the project and replace the `scripts` section with the below:  \n\n```json\n\"scripts\": {\n    \"start\": \"node app.js\",\n    \"dev\": \"cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js\",\n    \"watch\": \"cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js\",\n    \"hot\": \"cross-env NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js\",\n    \"production\": \"NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js\",\n    \"prod\": \"npm run production\",\n    \"test\": \"nyc mocha --timeout=3000 --exit\",\n    \"lint\": \"eslint **/*.js\"\n  },\n```\n\n- `simple-pjax` is included by default to provide an experience that feels more like a single page app. You can\nread more about it [here](https://github.com/Mitranim/simple-pjax).  \n- If you are not going to use Websockets with Socket.io, feel free to remove references to socket.io from \n`assets/scripts/app.js`.  \n- Perhaps consider renaming `app.js` at the top level of the project to `server.js` so that you don't get confused \nbetween our server file and client-side JavaScript file with the same name. Also remember to update the `start` task \nwithin the `scripts` block in `package.json` if you do rename the file. Eg. `\"start\": \"node server.js\",`\n\nIf you are unsure of these changes, please see the example files within this repo for reference.\n\n#### Development\nWhen developing, it's best to have two terminal windows open. One window will be running your asset pipeline, watching \nfor changes and recompiling when necessary. The other window will have the Express server running (make sure you've \nalready started MongoDB). Also note, it's worthwhile to use [Nodemon](https://github.com/remy/nodemon) to start your \nserver as it will automatically detect changes and restart your server for you.  \nIf you opt to use Nodemon, replace `\"start\": \"node app.js\",` with `nodemon app.js`.\n\nIn the first terminal window, run `npm start`.  \nIn the second terminal run `npm run watch`. This will watch our Sass files and our client-side JavaScript for changes \nand automatically recompile when needed.\n\n#### Production\nTo compile your assets for production, run `npm run prod` and production ready versions of your assets will be \noutput in the `public` directory. Be sure to deploy these files.\n\nWebsocket Support\n--------------\n\n**Note:** Line locations may vary based on what you have added/removed.\n\n### What To Add\n`npm install socket.io --save`\n\nThere's a few pieces to be added to `app.js` to add websocket support.  \n\nFind this at *line 46*\n```javascript\nconst app = express();\n```\n\nAdd this after *line 46*\n```javascript\n/**\n * Create Express \u0026 Socket.io servers.\n */\nconst socketIoPort = 3001\nconst app = express()\nconst server = require('http').Server(app)\nconst io = require('socket.io')(socketIoPort)\n```\n\nFind this at *line 65*\n```javascript\napp.use(expressStatusMonitor());\n```\n\nReplace with this:\n```javascript\napp.use(expressStatusMonitor({websocket: io, port: socketIoPort}))\n```\n\nFind this at *line 93*\n```javascript\napp.use((req, res, next) =\u003e {\n  res.locals.user = req.user;\n  next();\n});\n```\n\nReplace with this:\n```javascript\napp.use((req, res, next) =\u003e {\n  // Construct url to socket.io (port 3001). Slice port number where not needed.\n  res.locals.hostname = process.env.BASE_URL.slice(0, -5) || req.protocol + '://' + req.hostname\n  res.locals.fullHostname = process.env.BASE_URL || req.protocol + '://' + req.hostname + ':' + req.app.settings.port\n  res.locals.user = req.user\n  next()\n})\n```\n\nAt *line 227* add\n```javascript\n/**\n * Socket.io.\n */\nio.on('connection', (socket) =\u003e {\n  socket.emit('greet', {hello: 'Hey there browser!'})\n  socket.on('respond', (data) =\u003e {\n    console.log(data)\n  })\n  socket.on('disconnect', () =\u003e {\n    console.log('Socket disconnected')\n  })\n})\n```\n\nThe following piece of jQuery will listen for a connection to our Socket.io server. Once established it will then \nlisten for the `greet` event and emit a `respond` event when a `greet` event is received.\n\n```javascript\n$(document).ready(function () {\n  // init socket.io\n  const socket = io.connect(window.location.hostname + ':3001')\n  socket.on('greet', (data) =\u003e {\n    console.log(data)\n    socket.emit('respond', { message: 'Hey there, server!' })\n  })\n})\n```\n\nTo summarise: When a websocket connection is established, our server emits a `greet` event over websockets with a \nmessage saying \"Hey there browser!\" and when our browser receives this event, it logs what was sent from the server \nto its (the browser's) console.  \nWe then emit an event from the client called `respond` and when the server receives this event, it logs the message \n(on the server) that was sent, in this case \"Hey there, server!\"\n\nContributing\n------------\n\nIf something is unclear, confusing, or needs to be refactored, please let me know.  \nPull requests are always welcome, but due to the opinionated nature of this project, I cannot accept every pull \nrequest. Please open an issue before submitting a pull request.  \nThis project uses [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) with a few minor exceptions.  \nIf you are submitting a pull request that involves Pug templates, please make sure you are using *spaces*, not tabs.\n\nLicense\n-------\n\nThe MIT License (MIT)  \nCopyright (c) 2018 Niall O'Brien  \nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  \nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  \n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniallobrien%2Fhackathon-starter-plus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniallobrien%2Fhackathon-starter-plus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniallobrien%2Fhackathon-starter-plus/lists"}