├── LICENSE.md
├── README.md
└── package.json
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2015 Jam3
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
20 | OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##### [jam3-lesson](https://github.com/Jam3/jam3-lesson) » module-basics
2 |
3 | ---
4 |
5 | # Modules for Frontend JavaScript
6 |
7 | This is a brief intro to modules for modern frontend development. It will introduce Node, npm, and browserify. After this guide, you should be equipped to [create your first npm module](https://github.com/Jam3/jam3-lesson-module-creation).
8 |
9 | # # sections
10 |
11 | - [concepts](#concepts)
12 |
13 | - [modules](#modules)
14 |
15 | - [dependencies](#dependencies)
16 |
17 | - [semantic versioning](#semantic-versioning)
18 |
19 | - [tools](#tools)
20 |
21 | - [node](#node)
22 |
23 | - [npm](#npm)
24 |
25 | - [browserify](#browserify)
26 |
27 | - [basics](#basics)
28 |
29 | - [local modules](#local-modules)
30 |
31 | - [other tools](#other-tools)
32 |
33 | - [further reading](#further-reading)
34 |
35 | # # concepts
36 |
37 | ## modules
38 |
39 | In this context, "modular" JavaScript refers to a piece of code that operates independently of the applications which surround it. A "module" — sometimes just a single function — is written, tested, and published in isolation, and often a good candidate for re-use across projects.
40 |
41 | The goal is to build *small programs that do one thing, do it well, and compose easily with other programs* (the Unix Philosophy).
42 |
43 | Some examples:
44 |
45 | - [xhr](https://www.npmjs.com/package/xhr) - an XMLHttpRequest abstraction
46 | - [seed-random](https://www.npmjs.com/package/seed-random) - deterministic seeded pseudo-random number generator
47 | - [object-assign](https://www.npmjs.com/package/object-assign) - a polyfill for `Object.assign`
48 | - [gl-matrix](https://www.npmjs.com/package/gl-matrix) - vector & matrix math, ideal for 2D and 3D applications
49 |
50 | There are a few different formats for authoring and publishing modules, such as ES6, AMD, and CommonJS. This article will focus on CommonJS (used by Node).
51 |
52 | ## dependencies
53 |
54 | Each module can have a formalized set of "dependencies" — that is, other modules it needs to work. Dependencies can help reduce repetition and share code across many modules. The tooling will figure out how to download and consume these dependencies under the hood. In turn, those modules can have their own dependencies, and so forth.
55 |
56 | For example, the earlier mentioned [xhr](https://www.npmjs.com/package/xhr) module has a dependency graph that looks a little like this, where each is a separate module:
57 |
58 | ```ruby
59 | xhr
60 | ├── once # run a function once
61 | └─┬ parse-headers # parse http headers
62 | ├─┬ for-each # forEach() but works on objects
63 | │ └── is-function # test if value is a function
64 | └── trim # string trim utility
65 | ```
66 |
67 | ## semantic versioning
68 |
69 | As you re-use the same piece of code across many projects, bugs and limitations with the original module begin to emerge. The code evolves and changes to better suit the new use cases, and sometimes it leads to a breaking API (i.e. renaming a public function).
70 |
71 | This is where semantic versioning can help us. A version is broken down into `major.minor.patch` numbers, separated by decimals:
72 |
73 | - `major` denotes a breaking change in the documented API (e.g. renaming or removing a public function)
74 | - `minor` denotes a new feature was added in a backwards-compatible manner
75 | - `patch` denotes a bug was fixed in a backwards-compatible manner
76 |
77 | Modules typically start at version `1.0.0`. When you bump one number, you must reset the numbers to the right of it back to zero. For example:
78 |
79 | - making a bug fix to `1.0.0` -> `1.0.1` (patch change)
80 | - adding a new feature to `1.0.1` -> `1.1.0` (minor change)
81 | - changing a method name in `1.1.0` -> `2.0.0` (major change)
82 |
83 | When we install a module, we are also opting in for all of its `patch` and `minor` versions within the same `major` version. This way, we get the latest bug fixes, but our code won't break if a dependency decides to change its API. Later, we will explore how to configure this option and "lock down" our application's dependencies.
84 |
85 | # # tools
86 |
87 | To bring these concepts together, we will primarily be using these three open source tools:
88 |
89 | - [node](https://nodejs.org/) - a platform built on Chrome's JavaScript engine (V8)
90 | - [npm](https://npmjs.com/) - a package manager for JavaScript modules
91 | - [browserify](https://github.com/substack/node-browserify) - a tool which bundles Node modules into something browsers understand
92 |
93 | ## node
94 |
95 | The first step is to install Node; you can download it from [nodejs.org](https://nodejs.org/). Among other things, it provides a command-line interface for executing JavaScript source.
96 |
97 | Once it's installed, open Terminal and try entering the following:
98 |
99 | ```sh
100 | node -e "console.log(10 * 2)"
101 | ```
102 |
103 | If all goes well, the above should print `20` (where `-e` is for eval).
104 |
105 | 
106 |
107 | (if that doesn't work, you may need to re-install Node [via homebrew](http://shapeshed.com/setting-up-nodejs-and-npm-on-mac-osx/))
108 |
109 | Now you can run JavaScript files with `node path/to/file.js`, or start a REPL (read-eval-print-loop) with `node`.
110 |
111 | 
112 |
113 | **Tip:** You can quit the REPL with `Control + C`
114 |
115 | This is a great way to quickly test some generic JavaScript code without booting up a browser.
116 |
117 | Since we are running in Node, we also have access to a standard library for things like File I/O and backend programming.
118 |
119 | For example, let's use Node's built-in [url](https://nodejs.org/api/url.html) module to parse the URL string `"http://google.com/"`
120 |
121 | 
122 |
123 | Here we are *requiring* a built-in module called `url`. Require statements are part of Node, and look like this:
124 |
125 | ```js
126 | const url = require('url');
127 |
128 | //... use url.parse()
129 | ```
130 |
131 | ## npm
132 |
133 | The next tool we need is [npm](http://npmjs.com/). If you installed Node through the site above, you should already have npm set up! We can test that with the following command:
134 |
135 | ```sh
136 | npm -v
137 | ```
138 |
139 | (if that doesn't work, you may need to re-install Node and npm [via homebrew](http://shapeshed.com/setting-up-nodejs-and-npm-on-mac-osx/))
140 |
141 | Node bundles with a very outdated version of npm, so it's best to update it to get the latest features and security fixes:
142 |
143 | ```sh
144 | sudo npm install npm -g
145 | ```
146 |
147 | Let's try installing our first module: [http-server](https://www.npmjs.com/package/http-server). This helps us get a static site up quickly without a bloated GUI tool like MAMP.
148 |
149 | ```sh
150 | npm install http-server -g
151 | ```
152 |
153 | *Note:* The `-g` flag tells npm to install the module globally.
154 |
155 | If you get an `EACCESS` error, you need to fix your permissions:
156 |
157 | [Fixing npm permissions](https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-1-change-the-permission-to-npms-default-directory)
158 | [More Details (Stackoverflow)](http://stackoverflow.com/questions/16151018/npm-throws-error-without-sudo)
159 |
160 | Once it installs, you should be able to run it like so:
161 |
162 | ```sh
163 | http-server -o
164 | ```
165 |
166 | This should open the browser on `http://localhost:8080/`.
167 |
168 | 
169 |
170 | Awesome! You just used your first module. This one is a command line tool, which is why we installed it globally with `-g`. When we install code dependencies (like [xhr](https://www.npmjs.com/package/xhr)), we typically install them locally.
171 |
172 | ## browserify
173 |
174 | To bridge the gap between Node/npm and the browser, we will use a tool called [browserify](https://github.com/substack/node-browserify). It transforms Node `require()` statements into something the browser can execute, and bundles different modules into a single script. This allows us to use built-in Node modules like [url](https://nodejs.org/api/url.html), as well as modules on [npm](https://www.npmjs.com/).
175 |
176 | Close the earlier process (`Control + C`), and then stub out a folder where we can write some demos. In Linux/OSX shell:
177 |
178 | ```sh
179 | #go to your projects folder
180 | cd ~/Documents
181 |
182 | #make a new test folder
183 | mkdir test-browserify
184 |
185 | #move into that folder
186 | cd test-browserify
187 |
188 | #make an empty JavaScript file
189 | touch index.js
190 | ```
191 |
192 | On Windows, it might look like this:
193 |
194 | ```sh
195 | cd `%HOMEPATH%/Documents`
196 | mkdir test-browserify
197 | cd test-browserify
198 | type NUL > index.js
199 | ```
200 |
201 | ### basics
202 |
203 | Open the empty `index.js` file we created above in your favourite editor (like [SublimeText](http://www.sublimetext.com/)). Add the following and save it:
204 |
205 | ```js
206 | const url = require('url');
207 |
208 | const parts = url.parse(window.location.href);
209 | console.log(parts);
210 | ```
211 |
212 | The above code won't work yet in the browser, since it uses Node APIs. For our demo, we will use a tool called [budō](https://github.com/mattdesl/budo) to transform our Node `require()` statements into something the browser can understand. Install the tool like so:
213 |
214 | ```sh
215 | npm install budo -g
216 | ```
217 |
218 | Now start `budo` on our source file, like so:
219 |
220 | ```sh
221 | budo index.js --live
222 | ```
223 |
224 | This will start a browserify development server on port `9966`. When `index.js` is requested, it will get "browserified" and transformed into something the browser can run. It will also serve you a basic `index.html` if you didn't write one, with a `