{"id":13432458,"url":"https://github.com/mattkrick/meatier","last_synced_at":"2025-05-15T09:05:04.128Z","repository":{"id":146576132,"uuid":"45485565","full_name":"mattkrick/meatier","owner":"mattkrick","description":":hamburger: like meteor, but meatier :hamburger:","archived":false,"fork":false,"pushed_at":"2018-03-16T12:08:37.000Z","size":1087,"stargazers_count":3041,"open_issues_count":36,"forks_count":172,"subscribers_count":114,"default_branch":"master","last_synced_at":"2025-04-07T03:17:51.806Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/mattkrick.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}},"created_at":"2015-11-03T18:07:09.000Z","updated_at":"2025-03-17T14:48:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"e55d4dc8-0853-4b16-b2ee-05b14859bdcf","html_url":"https://github.com/mattkrick/meatier","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/mattkrick%2Fmeatier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattkrick%2Fmeatier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattkrick%2Fmeatier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattkrick%2Fmeatier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mattkrick","download_url":"https://codeload.github.com/mattkrick/meatier/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248890820,"owners_count":21178513,"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-07-31T02:01:11.890Z","updated_at":"2025-04-14T13:48:15.413Z","avatar_url":"https://github.com/mattkrick.png","language":"JavaScript","readme":"\u003cimg src=\"https://cloud.githubusercontent.com/assets/5986600/12841730/d500562a-cc28-11e5-84d9-90ae6abd5486.png\" width=\"600\"\u003e\n\n[![Join the chat at https://gitter.im/mattkrick/meatier](https://badges.gitter.im/mattkrick/meatier.svg)](https://gitter.im/mattkrick/meatier?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![Circle CI](https://img.shields.io/circleci/project/mattkrick/meatier/master.svg)](https://circleci.com/gh/mattkrick/meatier)\n[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n\nMeteor is awesome! But after 3 years, it's starting to show its age. This project is designed to showcase \nthe exact same functionality as Meteor, *but without the monolithic structure.* \nIt trades a little simplicity for a lot of flexibility.\n\nSome of my chief complaints with Meteor\n - Built on Node 0.10, and that ain't changing anytime soon\n - Build system doesn't allow for code splitting (the opposite, in fact)\n - Global scope (namespacing doesn't count)\n - Goes Oprah-Christmas-special with websockets (not every person/page needs one)\n - Can't handle css-modules (CSS is all handled behind the scenes)\n - Tied to MongoDB for official support\n \n| Problem           | Meteor's solution                                               | My solution                                                         | Result                                                              |\n|-------------------|-----------------------------------------------------------------|---------------------------------------------------------------------|---------------------------------------------------------------------|\n| Database          | [MongoDB](https://www.mongodb.org/)                             | [RethinkDB](https://www.rethinkdb.com/)                             | Built in reactivity, but you can use any DB you like                |\n| Database schema   | [Simple Schema](https://github.com/aldeed/meteor-simple-schema) | [GraphQL](https://github.com/graphql/graphql-js)                    | Can't have a hipster webapp without GraphQL!                        |\n| Client validation | [Simple Schema](https://github.com/aldeed/meteor-simple-schema) | [Joi](https://github.com/hapijs/joi)                                | Clean API for client validation, although the package is HUGE       |\n| Database hooks    | [Collections2](https://github.com/aldeed/meteor-collection2)    | [GraphQL](https://github.com/graphql/graphql-js)                    | GraphQL is overkill for small apps (then again, so is meatier)      |\n| Forms             | [AutoForm](https://github.com/aldeed/meteor-autoform)           | [redux-form](https://github.com/erikras/redux-form)                 | state tracking awesomeness that works beautifully with react        |\n| Client-side cache | [Minimongo](https://www.meteor.com/mini-databases)              | [redux](http://redux.js.org/)                                       | Bonus logging, time traveling, and undo functionality               |\n| Socket server     | [DDP-server](https://www.meteor.com/ddp)                        | [socketcluster](http://socketcluster.io/#!/)                        | super easy scaling, pubsub, auth, middleware                        |\n| Authentication    | Meteor accounts                                                 | [JWTs](https://jwt.io)                                              | JWTs can also serve to authorize actions, too                       |\n| Auth-transport    | [DDP](https://www.meteor.com/ddp)                               | GraphQL (via HTTP)                                                  | Don't use sockets until you need to                                 |\n| Front-end         | [Blaze](https://www.meteor.com/blaze)                           | [React](https://facebook.github.io/react/)                          | Vdom, server-side rendering, async router, etc.                     |\n| Build system      | meteor                                                          | [webpack](https://webpack.github.io/)                               | using webpack inside meteor is very limited                         |\n| CSS               | magically bundle \u0026 serve                                        | [css-modules](https://github.com/css-modules/css-modules)           | component-scoped css with variables available in a file or embedded |\n| Optimistic UI     | latency compensation                                            | [redux-optimistic-ui](https://github.com/mattkrick/redux-optimistic-ui)  | written by yours truly                                         |\n| Testing           | Velocity (or nothing at all)                                    | [AVA](https://github.com/sindresorhus/ava)                          | awesome es2016 concurrent testing                                   |\n| Linting           | Your choice                                                     | [xo](https://www.npmjs.com/package/xo)                              | no dotfiles, fixes errors                                           |\n| Routing           | [FlowRouter](https://github.com/kadirahq/flow-router)           | [react-router-redux](https://github.com/reactjs/react-router-redux) | stick the route in the state, react-router SSR, async routes        |\n| Server            | Node 0.10.41                                                    | Node 5                                                              | Faster, maintained, not a dinosaur...                               |                             |\n \n##Installation\n- `brew install rethinkdb`\n- make sure you are using webpack@2.x (not a v1 installed globally)\n- `rethinkdb` (in second terminal window)\n- `git clone` this repo\n- `cd meatier`\n- `npm install`\n- `npm run quickstart`\n\n##Client-side development\n- `npm start`\n- http://localhost:3000\n\nRebuilds the client code in-memory \u0026 uses hot module reload so you can develop super fast!\nOn my 2013 MBA an initial build takes about 8 seconds and updates usually take 800ms\n\n##Server-side development\n- `npm run prod`\n- http://localhost:3000\n- If you edit any client or universal files, run `npm run bs` to rebuild \u0026 serve the bundle\n\nThis mode is great because you can make changes to the server ***without having to recompile the client code***\nThat means you only wait for the server to restart! GAME CHANGER!\n\n##Database development\n- http://localhost:8080 for RethinkDB\n- All tables are managed in `./src/server/setupDB.js`. Just add your tables \u0026 indices to that file and rerun\n- A standard ORM would check for tables \u0026 ensure indices at least once per build, doing it this way keeps your build times down\n- http://localhost:3000/graphql for testing out new queries/mutations\n\n##Webpack configs\n####Development config\nWhen the page is opened, a basic HTML layout is sent to the client along with a stringified redux store and a request for the common chunk of the JS.\nThe client then injects the redux store \u0026 router to create the page.\nThe redux devtools \u0026 logger are also loaded so you track your every state-changing action. \nThe routes are loaded async, check your networks tab in chrome devtools and you'll see funny js files load now \u0026 again. \nIf this isn't crazy amazing to you, then go away.\n\n####Production config\nBuilds the website \u0026 saves it to the `build` folder.\nMaps the styles to the components, but uses the prerendered CSS from the server config (below)\nSeparates the `vendor` packages and the `app` packages for a super quick, cachable second visit.\nCreates a webpack manifest to enable longterm caching (eg can push new vendor.js without pushing a new app.js)\nOptimizes the number of chunks, sometimes it's better to have the modules of 2 routes in the same chunk if they're small\n\n####Server config\nA webpack config builds the entire contents of the routes on the server side.\nThis is required because node doesn't know how to require `.css`.\nWhen a request is sent to the server, react-router matches the url to the correct route \u0026 sends it to the client.\nAny browser dependency is ignored \u0026 uglified away.\nTo test this, disable javascript in the browser. You'll see the site \u0026 css loads without a FOUC.\n\n##How it works\nWhen the page loads, it checks your localStorage for `Meatier.token` \u0026 will automatically log you in if the token is legit. \nIf not, just head to the 'Sign up' page. The 'Sign up' page uses redux-form, which handles all errors, schema validation,\nand submissions. Your credentials are set as variables in a GraphQL mutation \u0026 sent to the GraphQL endpoint and a user document (similar to Meteor's) and authToken is returned to your state.\n\nThe 'Kanban' app requires a login \u0026 websocket, so when you enter, your token will be used to authenticate a websocket.\nThat token is stored on the server so it is only sent during the handshake (very similar to DDP). Socket state is managed\nby `redux-socket-cluster`, just clicking `socket` in the devtools let's you explore its current state. \n\nWhen you enter the route, reducers are lazily loaded to the redux store and the `redux-optimistic-ui` reducer enhancer is applied to the store to enable an optimistic UI. To work, it requires some middleware that scans each redux action for an `isOptimistic` prop and reverts actions that fail server side.\n\nWhen the kanban component loads, it subscribes to `lanes` \u0026 `notes`, which starts your personalized changefeed.\nWhen you do something that changes the persisted state (eg add a kanban lane) that action is executed\noptimistically on the client \u0026 emitted to the server where it is validated \u0026 sent to the database. \nThe database then emits a changefeed doc to all subscribed viewers.\nSince the DB doesn't know which client made the mutation, it always sends a changefeed to the server.\nThe server is smart enough to ignore sending that document back to the originator, but it does send an acknowledgement.\n\nThe kanban lane titles \u0026 notes are really basic, you click them \u0026 they turn into input fields. \nThe notes can be dragged from lane to lane. This is to showcase a local state change that doesn't affect the persisted state.\nWhen the note is dropped to its new location, the change is persisted. \n\n##Tutorials (not for beginners...but then again, neither is meatier)\n - [A production-ready realtime SaaS with webpack](https://medium.com/@matt.krick/a-production-ready-realtime-saas-with-webpack-7b11ba2fa5b0#.bifdf5iz8)\n - [GraphQL Field Guide to Auth](https://medium.com/@matt.krick/graphql-field-guide-to-auth-ead84f657ab#.f3tg2sf3d)\n\n##Similar Projects\n - https://github.com/erikras/react-redux-universal-hot-example (Really nice, but no auth or DB)\n - https://github.com/kriasoft/react-starter-kit (nice, I borrowed their layout, but no sockets, no DB)\n - https://github.com/GordyD/3ree (uses RethinkDB, but no optimistic UI)\n - http://survivejs.com/ (A nice alt-flux \u0026 react tutorial for a kanban)\n\n##In Action\nI don't know of any place that hosts RethinkDB for free...so here's a gif. \n![Meatier](http://i.imgur.com/B3IErZr.gif)\n\n##Contributing\n - Pull requests welcomed!\n - Use the gitter for any questions\n - No donations necessary (but if you know of any jobs that'll let me move back to San Diego, let me know :wink:)\n\n##Changelog\n- 0.10\n - Use the redux devtools chrome extension \n - Update just about all the deps\n - Make deployments more configurable (deployment strategy coming soon)\n- 0.9\n - Upgraded to `redux-simple-router@2.0.3`\n - Now you can do cool things like time travel through routes!\n \n- 0.8\n - Move auth \u0026 mutations to GraphQL (changefeeds still go through WS subs)\n - Make the rest of the `state.auth` immutable\n - Add graphiql (http://localhost:3000/graphql) as a component \u0026 pattern to create an admin site\n - Break out auth, landing page, kanban page, and admin into 4 separate modules in the folder hierarchy\n  \n##License\nMIT\n","funding_links":[],"categories":["JavaScript","Web Frameworks","Marks"],"sub_categories":["[React - A JavaScript library for building user interfaces](http://facebook.github.io/react)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattkrick%2Fmeatier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmattkrick%2Fmeatier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattkrick%2Fmeatier/lists"}