├── .gitignore ├── README.md ├── client-main ├── index.js └── package.json ├── content-client ├── rendering.md ├── validation.md ├── webgl.md └── webrtc.md ├── content-server ├── authentication.md ├── caching.md ├── cookies.md ├── databases.md ├── events.md ├── index.md ├── logging.md ├── middleware.md ├── routing.md ├── static.md ├── tasks.md └── validation.md ├── index.css ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | tmp/ 4 | npm-debug.log* 5 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOFRAMEWORKFRAMEWORK 2 | It's time to toss frameworks out the window. 3 | 4 | ## What is a framework? 5 | It depends on who you ask. From a traditional point of view it's a set of 6 | boundries where in programs can communicate with each other. Shell, Node and 7 | HTTP are examples of frameworks. These frameworks are usually focused on 8 | _protocols_. 9 | 10 | Though usually when people talk about frameworks they mean something else: a 11 | set of libraries that trade flexibility for opinions, usually coupled with the 12 | promise of efficiency. It's these type of frameworks that we want to throw out. 13 | 14 | ## How to detect frameworks? 15 | There's an easy verbal test: if you need to use the word "and" to describe a 16 | package, you're dealing with a framework. Example: 17 | 18 | > This module implements ES6 compatible promises and adds 40 convenience 19 | > functions to make dealing with them easier. 20 | 21 | ## Why no frameworks? 22 | A framework is the code version of an author's opinions. Because framework's 23 | concerns are spread wide you'll always end up with more opinions than you 24 | wished for. Instead of frameworks it's better to use single-purpose packages 25 | that do one thing well. That way you can pick and choose the opinions that best 26 | fit the situation without compromising. 27 | 28 | Framework proponents will often argue that their method leads to more concise 29 | code. While this is true for smaller projects, once a project grows it will be 30 | inevitable that separate versions of the framework will be run in parallel or 31 | never upgraded at all. One of the observable symptomes of this in larger 32 | systems is the tendency to rewrite from scratch rather than refactor. 33 | 34 | Though modularity is no silver bullet, it sure helps in dealing with large 35 | systems. To paraphrase a famous quote: 36 | > The trick to writing large systems is to not write large systems but instead 37 | > write small systems that work together. 38 | 39 | ## This sounds reasonable. How do I get started? 40 | This guide is here to get you up to speed in coding without frameworks in 41 | JavaScript. It's recommended to start either on the 42 | [server](content-server/index.md) or [client](content-client/index.md). Happy 43 | coding! 44 | 45 | ## See Also 46 | - [http-framework](https://github.com/raynos/http-framework) 47 | - [yoshuawuyts/knowledge/modules](https://github.com/yoshuawuyts/knowledge/modules) 48 | 49 | ## License 50 | [MIT](https://tldrlegal.com/license/mit-license) 51 | -------------------------------------------------------------------------------- /client-main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/client-main/index.js -------------------------------------------------------------------------------- /client-main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client-main", 3 | "private": true, 4 | "browserify": { 5 | "transform": [ "babelify" ] 6 | }, 7 | "dependencies": { 8 | "css-wipe": "^4.0.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /content-client/rendering.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-client/rendering.md -------------------------------------------------------------------------------- /content-client/validation.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-client/validation.md -------------------------------------------------------------------------------- /content-client/webgl.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-client/webgl.md -------------------------------------------------------------------------------- /content-client/webrtc.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-client/webrtc.md -------------------------------------------------------------------------------- /content-server/authentication.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/authentication.md -------------------------------------------------------------------------------- /content-server/caching.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/caching.md -------------------------------------------------------------------------------- /content-server/cookies.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/cookies.md -------------------------------------------------------------------------------- /content-server/databases.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/databases.md -------------------------------------------------------------------------------- /content-server/events.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/events.md -------------------------------------------------------------------------------- /content-server/index.md: -------------------------------------------------------------------------------- 1 | # server 2 | 3 | Node is different from other languages because it ships with a native HTTP 4 | server in its standard library. This makes it great for creating interfaces 5 | with other systems, or writing scripts that do one thing well. 6 | 7 | - [Creating a server](#creating-a-server) 8 | - [Req Res](#req-res) 9 | - [Listen](#listen) 10 | - [browserify-server](#browserify-server) 11 | 12 | ## Creating a server 13 | Creating a server in Node goes as follows: 14 | 15 | ```js 16 | // require the 'http' module from stdlib 17 | const http = require('http') 18 | 19 | // create server that calls a function (callback) 20 | // on each request 21 | const server = http.createServer(function (req, res) { 22 | res.write('hello world') // write to response object 23 | res.end() // close the response and send it off 24 | }) 25 | 26 | // request server listen on port 1337 27 | // and log something once it's 28 | // started listening 29 | server.listen(1337, function () { 30 | console.log('port: 1337') 31 | }) 32 | ``` 33 | In this case we create a server, write 'hello world' to the response body, and 34 | close the response to send it off. In ES2015 we could do it in 3 lines: 35 | ```js 36 | import http from 'http' 37 | const server = http.createServer((req, res) => res.end('hello world')) 38 | server.listen(1337) 39 | ``` 40 | 41 | Because servers both EventEmitters that pass around streams, there are other 42 | ways of writing servers. Though these are less common (and by no means 43 | necessary to learn), they might be nice to have seen at least once. 44 | 45 | __EventEmitter style__ 46 | ```js 47 | const http = require('http') 48 | 49 | // listen to server events 50 | const server = http.createServer() 51 | server.on('request', function (req, res) { 52 | res.write('hello world') 53 | res.end() 54 | }) 55 | server.listen(1337) 56 | ``` 57 | 58 | __Stream style__ 59 | ```js 60 | const http = require('http') 61 | const fs = require('fs') 62 | 63 | // pipe a file to the response object 64 | const server = http.createServer(function (req, res) { 65 | fs.createReadStream('./my-file').pipe(res) 66 | }) 67 | server.listen(1337) 68 | ``` 69 | 70 | ## Req, Res 71 | Node's server callback has 2 arguments: 72 | - __req__: `Class:http.IncomingMessage`, the message received from the client. 73 | - __res__: `Class:http.ServerResponse`, the response that will be sent back. 74 | 75 | Both arguments are steams and have some properties on them. Probably the most 76 | important ones are: 77 | 78 | ### req 79 | - __.url__ 80 | - __.on('data', fn(value))__: pipe the request body as it comes in. 81 | 82 | ### res 83 | - __.statusCode(code)__: set the http statusCode 84 | - __.statusMessage(message)__: set the http status message 85 | - __.writeHeader(header, value)__: set a header 86 | - __.write(data)__: write a string or buffer to the response 87 | - __.end(data)__: send the response off. All operations on `res` after this 88 | will throw an error. 89 | 90 | ## Listen 91 | Once a server is created, all it needs to do is listen to a port. To do that 92 | there's the `.listen()` method which takes two arguments: 93 | - __port__: a valid HTTP port. If value is null or undefined, a random open 94 | port will be selected. 95 | - __callback__: an empty callback that will be called when the server starts 96 | listening. The value of `this` points to the server. 97 | 98 | ## browserify-server 99 | ```js 100 | const browserify = require('browserify') 101 | const http = require('http') 102 | 103 | const server = http.createServer(function (req, res) { 104 | const b = browserify('./index.js') 105 | b.bundle().pipe(res) 106 | }) 107 | server.listen(1337) 108 | ``` 109 | -------------------------------------------------------------------------------- /content-server/logging.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/logging.md -------------------------------------------------------------------------------- /content-server/middleware.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/middleware.md -------------------------------------------------------------------------------- /content-server/routing.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/routing.md -------------------------------------------------------------------------------- /content-server/static.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/static.md -------------------------------------------------------------------------------- /content-server/tasks.md: -------------------------------------------------------------------------------- 1 | # tasks 2 | When writing code there's a need to automate repetitive tasks. Npm has built in 3 | support for automation through `npm scripts`. These scripts live under the 4 | `scripts` key in `package.json`. In this section we'll cover some common 5 | scripting scenarios and how to deal with them. 6 | 7 | - [npm scripts]() 8 | - [Example: simple]() 9 | - [Example: testing]() 10 | - [Example: github-pages]() 11 | 12 | ## npm scripts 13 | Npm scripts is the task runner provided by npm. Scripts themselves are regular 14 | shell. For convenience all files in the `./node_modules/.bin` folder are 15 | imported and made available as globals within `npm scripts`. 16 | 17 | Common uses for scripts are: 18 | - compiling assets before uploading 19 | - reloading a server when files change 20 | - running tests 21 | - verifying dependencies 22 | - compiling static addons 23 | 24 | ## Example: simple 25 | __./package.json__ 26 | ```json 27 | { 28 | "name": "app-api", 29 | "version": "1.0.0", 30 | "scripts": { 31 | "hello": "echo hello world" 32 | }, 33 | "dependencies": {} 34 | } 35 | ``` 36 | 37 | __cli__ 38 | ```sh 39 | $ npm run hello 40 | ``` 41 | 42 | ## Example: testing 43 | This is a relatively complex test setup. `test` is the core script that's run, 44 | but I've included some other scripts to show off a real-world testing setup. 45 | 46 | - [`depencency-check`](https://github.com/maxogden/dependency-check) for 47 | validating dependencies. 48 | - [`tape`](https://github.com/substack/tape) for running tests (inside 49 | `test.js`). 50 | - [`standard`](https://github.com/feross/standard) for linting. 51 | - [`istanbul`](https://github.com/gotwarlost/istanbul) for test coverage. 52 | - [`watch`](https://github.com/mikael/watch) for rerunning tests on file 53 | change. 54 | 55 | __./package.json__ 56 | ```json 57 | { 58 | "name": "app-api", 59 | "version": "1.0.0", 60 | "scripts": { 61 | "deps": "dependency-check . && dependency-check . --extra --no-dev", 62 | "test": "standard && npm run deps && NODE_ENV=test node test", 63 | "test:watch": "watch 'npm test'", 64 | "test:cov": "standard && npm run deps && NODE_ENV=test istanbul cover test.js" 65 | }, 66 | "devDependencies": { 67 | "istanbul": "^0.3.17", 68 | "standard": "^5.0.2", 69 | "tape": "^4.2.0", 70 | "watch": "^0.16.0" 71 | } 72 | } 73 | ``` 74 | 75 | __cli__ 76 | ```sh 77 | $ npm run test:watch 78 | ``` 79 | 80 | ## Example: github-pages 81 | This script will build a browserify bundle, copy a `CNAME` and `index.html` to 82 | `./dist` and then deploy that folder to GitHub Pages when the version changes. 83 | When `npm version ` is run, an `npm hook` is triggered. 84 | Command are run in the following order: 85 | - `npm hook: preversion` - is triggered and runs `npm run clean` 86 | - `npm run clean` - removes previous build artifacts 87 | - `npm version` - updates the version 88 | - `npm run postversion` - is triggered and runs its first half: `npm run build` 89 | - `npm run build` - runs `build:browserify`, `build:cname` and `build:html`. 90 | - `npm run postversion` - resumes and deploys `./dist` to the `gh-pages` 91 | branch. 92 | 93 | For the sake of example 94 | we've broken up `build` into separate scripts, but feel free to use tools such 95 | as `gasket` or `brick-router` for more complex scenarios. 96 | 97 | __./package.json__ 98 | ```json 99 | { 100 | "name": "app-api", 101 | "version": "1.0.0", 102 | "scripts": { 103 | "build": "npm run build:{browserify,cname,html}", 104 | "build:browserify": "browserify index.js -o dist/bundle.js", 105 | "build:cname": "cp CNAME ./dist/CNAME", 106 | "build:html": "cp index.html ./dist/index.html", 107 | "clean": "rm -rf dist", 108 | "postversion": "npm run build && gh-pages -d ./dist -b gh-pages", 109 | "preversion": "npm run clean", 110 | }, 111 | "devDependencies": { 112 | "istanbul": "^0.3.17", 113 | "standard": "^5.0.2", 114 | "tape": "^4.2.0", 115 | "watch": "^0.16.0" 116 | } 117 | } 118 | ``` 119 | 120 | ```sh 121 | $ npm version patch 122 | ``` 123 | -------------------------------------------------------------------------------- /content-server/validation.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/content-server/validation.md -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshuawuyts/noframeworkframework/cecb6c977755b6faf909c719e45ff09cf55e5f69/index.css -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const watchifyRequest = require('watchify-request') 2 | const toServer = require('wayfarer-to-server') 3 | const hyperstream = require('hyperstream') 4 | const httpNdjson = require('http-ndjson') 5 | const summary = require('server-summary') 6 | const html = require('simple-html-index') 7 | const browserify = require('browserify') 8 | const match = require('pathname-match') 9 | const wayfarer = require('wayfarer') 10 | const watchify = require('watchify') 11 | const http = require('http') 12 | 13 | const router = toServer(wayfarer('404')) 14 | const staticRouter = toServer(wayfarer()) 15 | 16 | router.on('static', staticRouter) 17 | router.on('404', { 18 | all: function (req, res) { 19 | res.statusCode = 404 20 | res.end() 21 | } 22 | }) 23 | 24 | router.on('/', { 25 | get: function (req, res) { 26 | const htmls = html({ 27 | title: 'noframeworkframe.work', 28 | entry: 'static/bundle.js', 29 | css: 'static/bundle.css' 30 | }) 31 | 32 | const tag = ` 33 | 34 | 35 | ` 36 | const hs = hyperstream({ body: { _appendHtml: tag } }) 37 | 38 | htmls.pipe(hs).pipe(res) 39 | } 40 | }) 41 | 42 | var b = browserify({ 43 | cache: {}, 44 | packageCache: {}, 45 | entries: [ require.resolve('client-main') ], 46 | fullPaths: true 47 | }) 48 | if (process.env.NODE_ENV === 'development') b = watchify(b) 49 | const handler = watchifyRequest(b) 50 | 51 | staticRouter.on('/bundle.js', { 52 | get: function (req, res) { 53 | handler(req, res) 54 | } 55 | }) 56 | 57 | // create server 58 | const server = http.createServer(function (req, res) { 59 | httpNdjson(req, res).pipe(process.stdout) 60 | router(match(req.url), req, res) 61 | }) 62 | 63 | server.listen(1337, summary(server)) 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "noframeworkframework", 3 | "description": "no framework framework", 4 | "private": true, 5 | "scripts": { 6 | "clean": "rm-modules", 7 | "dev": "linklocal link -r && linklocal list -r | bulk -c 'npm install --production'", 8 | "start": "node .", 9 | "prepublish": "if [ \"$NODE_ENV\" != \"production\" ]; then npm run dev; fi", 10 | "start:watch": "nodemon -i 'node_modules/' -i 'client*' -i 'component*' -- ./index.js | garnish", 11 | "watch": "npm run start:watch" 12 | }, 13 | "repository": "yoshuawuyts/noframeworkframework", 14 | "license": "MIT", 15 | "dependencies": { 16 | "browserify": "^11.0.1", 17 | "client-main": "file:client-main", 18 | "http-ndjson": "^1.1.0", 19 | "hyperstream": "^1.2.2", 20 | "pathname-match": "^1.1.0", 21 | "server-summary": "^3.2.0", 22 | "simple-html-index": "^1.1.0", 23 | "watchify": "^3.4.0", 24 | "watchify-request": "^2.0.0", 25 | "wayfarer": "^5.0.1", 26 | "wayfarer-to-server": "^2.0.2" 27 | }, 28 | "devDependencies": { 29 | "babelify": "^6.3.0", 30 | "bulk": "^2.0.0", 31 | "garnish": "^3.0.0", 32 | "linklocal": "^2.5.2", 33 | "nodemon": "^1.4.1", 34 | "rm-modules": "^1.0.2" 35 | } 36 | } 37 | --------------------------------------------------------------------------------