├── .gitignore ├── .idea ├── book.iml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── jsLibraryMappings.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── 01 NodeJS Introduction ├── 1. NodeJS前世今生.md └── 2. NodeJS运行机制.md ├── 02 CommonJS └── demo │ ├── 01_self.js │ ├── 02_buildin.js │ ├── 03_npm_module.js │ ├── copy.js │ ├── css │ ├── min │ │ └── test.css │ └── test.css │ ├── gulpfile.js │ ├── less │ └── test.less │ ├── modules │ ├── mod1.js │ └── mod2.js │ ├── package.json │ └── wrapper.js ├── 03 Async & callback └── demo │ ├── 01_ajax.js │ ├── 02_jQuery_ajax.js │ ├── 03_jQuery_ajax2.js │ ├── 04_deferred.js │ ├── 05_Promise.js │ ├── 06 async │ ├── .babelrc │ ├── source.js │ └── starter.js │ └── package.json ├── 04 Inherits & Events └── demo │ ├── 01_browser_inherits.js │ ├── 02_nodejs_inherits.js │ ├── 03_inherits.js │ ├── 04_events.js │ ├── 05_extends.js │ ├── 06_event_params.js │ ├── 07_envet_once.js │ └── 08_remove_listeners.js ├── 05 Buffer & FileSystem ├── 1. Buffer.md ├── 2. FileSystem.md └── demo │ ├── 0. buffer.js │ ├── 1. badchar.js │ ├── 2. string_decoder.js │ ├── 3. buffer_concat.js │ ├── 4. file_exist.js │ ├── 5. file.js │ ├── 6. file2.js │ ├── 7. watchFile.js │ ├── test.md │ └── test3.txt ├── 06 Stream ├── cus_stream │ ├── du1.js │ ├── du2.js │ ├── du_test.js │ ├── package.json │ ├── read1.js │ ├── read2.js │ ├── read3.js │ ├── read_test.js │ ├── ret.js │ ├── tr1.js │ ├── tr2.js │ ├── tr_ret1.js │ ├── tr_ret2.js │ ├── tr_test.js │ └── write1.js ├── demo │ ├── duplex.js │ ├── files │ │ ├── message.txt │ │ └── transform.js │ ├── package.json │ ├── readable.js │ ├── readable2.js │ ├── readable3.js │ ├── readable4.js │ ├── rw_stream.js │ ├── server.js │ ├── transform1.js │ ├── writeable1.js │ └── writeable2.js ├── function.png ├── gulp_plugin │ ├── dist │ │ ├── a.js │ │ └── b.js │ ├── gulpfile.js │ ├── package.json │ ├── plugin1.js │ ├── plugin2.js │ ├── plugin3.js │ └── src │ │ ├── a.js │ │ └── b.js └── processing.svg ├── 07 HTTP Server ├── cache-control.png ├── connect │ ├── app1.js │ ├── app2.js │ ├── app3.js │ ├── app4.js │ ├── app5.js │ ├── app6.js │ ├── index.js │ ├── mid404.js │ ├── package.json │ ├── public │ │ ├── a.js │ │ ├── a │ │ │ └── t.txt │ │ ├── b.js │ │ ├── c.css │ │ └── d.html │ └── serve-index.js ├── demo │ ├── 01_base_http.js │ ├── 02_argv.js │ ├── 03_readfile.js │ ├── 04_directory.js │ ├── 05_mime.js │ ├── 06_status_code.js │ ├── 07_public.js │ ├── 08_compress.js │ ├── 09_secure.js │ ├── 10_chche.js │ ├── 11_argv2.js │ ├── package.json │ └── template │ │ ├── 404.tmpl │ │ ├── directory.tmpl │ │ └── logo.png ├── exp │ ├── 01_start.js │ ├── 02_routing1.js │ ├── 03_static.js │ ├── 04_static2.js │ ├── 05_routing2.js │ ├── 06_sendFile.js │ ├── 07_route.js │ ├── 08_router.js │ ├── files │ │ └── 1.js │ ├── package.json │ ├── public │ │ └── 1.js │ └── userRouter.js ├── http2.gif ├── https.jpg ├── midleware.gif ├── ss │ ├── conf.json │ ├── index.js │ └── mime.json └── 缓存.png ├── 08 Build ├── 1_gulp │ ├── all.txt │ ├── dest │ │ ├── css │ │ │ ├── index.min.css │ │ │ └── lib │ │ │ │ └── main.css │ │ ├── image │ │ │ ├── head.jpg │ │ │ └── search.png │ │ ├── index.html │ │ └── js │ │ │ ├── index.min.js │ │ │ └── lib │ │ │ └── store.js │ ├── fs_through2.js │ ├── gulp1.js │ ├── gulp2.js │ ├── gulp3.js │ ├── gulp4.js │ ├── gulp5.js │ ├── gulp6.js │ ├── gulpfile.js │ ├── out.txt │ ├── package.json │ └── src │ │ ├── css │ │ ├── button.css │ │ ├── index.css │ │ ├── index.min.css │ │ └── lib │ │ │ └── main.css │ │ ├── image │ │ ├── head.jpg │ │ └── search.png │ │ ├── index.html │ │ ├── js │ │ ├── index.js │ │ ├── index.min.js │ │ ├── lib │ │ │ └── store.js │ │ └── main.js │ │ └── less │ │ └── lib │ │ └── main.less ├── 2_npm_scripts │ ├── bin │ │ ├── app │ │ ├── build │ │ └── pre │ ├── dist │ │ └── css │ │ │ └── test.css │ ├── package.json │ └── src │ │ ├── js │ │ ├── test.js │ │ └── test2.js │ │ └── scss │ │ └── test.scss ├── 3_webpack │ ├── 01 │ │ ├── bundle.js │ │ ├── entry.js │ │ └── index.html │ ├── 02 │ │ ├── bundle.js │ │ ├── content.js │ │ ├── entry.js │ │ └── index.html │ ├── 03 │ │ ├── bundle.js │ │ ├── content.js │ │ ├── entry.js │ │ ├── index.html │ │ └── style.css │ ├── 04 │ │ ├── bundle.js │ │ ├── content.js │ │ ├── entry.js │ │ ├── index.html │ │ ├── style.css │ │ └── webpack.config.js │ ├── 05 │ │ ├── app │ │ │ ├── AppComponent.js │ │ │ └── main.js │ │ ├── build │ │ │ ├── bundle.js │ │ │ └── index.html │ │ ├── package.json │ │ └── webpack.config.js │ ├── 06 │ │ ├── app │ │ │ ├── AppComponent.jsx │ │ │ └── main.jsx │ │ ├── build │ │ │ └── index.html │ │ ├── package.json │ │ └── webpack.config.js │ ├── 07 │ │ ├── app │ │ │ ├── AppComponent.jsx │ │ │ └── main.jsx │ │ ├── build │ │ │ └── index.html │ │ ├── package.json │ │ └── webpack.config.js │ ├── 08 │ │ ├── app │ │ │ ├── AppComponent.jsx │ │ │ ├── common.css │ │ │ ├── main.css │ │ │ └── main.jsx │ │ ├── build │ │ │ └── index.html │ │ ├── package.json │ │ └── webpack.config.js │ └── package.json └── 4_gulp_webpack │ ├── app │ ├── AppComponent.jsx │ ├── common.css │ ├── main.css │ └── main.jsx │ ├── build │ ├── bundle.css │ ├── bundle.js │ ├── index.html │ └── vendor.bundle.js │ ├── gulpfile.js │ ├── package.json │ └── webpack.config.js ├── 09 Process ├── child.js ├── clu │ ├── c1.js │ ├── c2.js │ └── w1.js ├── cp │ ├── master1.js │ ├── master2.js │ ├── master22.js │ ├── master3.js │ ├── master4.js │ ├── worker1.js │ ├── worker2.js │ └── worker3.js ├── p1.js ├── p2.js ├── p3.js ├── p4.js ├── p5.js ├── p6.js ├── package.json └── pm2 │ └── index.js ├── 10 Net ├── c1.js └── n1.js ├── 11 App ├── config.js ├── package.json └── src │ ├── app.js │ ├── models │ ├── mongodb.js │ └── user.js │ ├── public │ ├── images │ │ └── favicon.ico │ ├── scripts │ │ ├── bootstrap.min.js │ │ └── jquery-2.2.3.min.js │ └── styles │ │ ├── bootstrap.min.css │ │ ├── bootstrap.theme.min.css │ │ └── common.css │ ├── routes │ ├── home.js │ ├── index.js │ ├── login.js │ └── register.js │ └── views │ ├── home.hbs │ ├── layouts │ └── main.hbs │ ├── login.hbs │ └── register.hbs ├── README.md ├── SUMMARY.md ├── clean.js ├── temp ├── .editorconfig ├── .gitignore ├── config.js ├── package.json └── src │ ├── app.js │ ├── public │ ├── images │ │ └── favicon.ico │ ├── scripts │ │ ├── bootstrap.min.js │ │ └── jquery-2.2.3.min.js │ └── styles │ │ ├── bootstrap.min.css │ │ ├── bootstrap.theme.min.css │ │ └── common.css │ └── views │ ├── home.hbs │ └── layouts │ └── main.hbs └── test ├── learnyounode └── 1.js └── stream ├── 1.js ├── 2.js ├── 3.js ├── 4.js ├── 5.js ├── 6.js ├── 7.js ├── 8.js ├── 9.js ├── a.js ├── b.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.mp4 3 | *.mov 4 | node_modules 5 | npm-debug.log 6 | video 7 | qrsync 8 | upload.json 9 | .idea 10 | npm-debug.log 11 | -------------------------------------------------------------------------------- /.idea/book.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /01 NodeJS Introduction/1. NodeJS前世今生.md: -------------------------------------------------------------------------------- 1 | # NodeJS简介 2 | 3 | -------------------------------------------------------------------------------- /01 NodeJS Introduction/2. NodeJS运行机制.md: -------------------------------------------------------------------------------- 1 | # NodeJS运行机制 2 | 3 | -------------------------------------------------------------------------------- /02 CommonJS/demo/01_self.js: -------------------------------------------------------------------------------- 1 | var mod1 = require('./modules/mod1.js'); 2 | var mod2 = require('./modules/mod2.js'); 3 | 4 | mod1.fn(); 5 | console.log(mod2.name); 6 | -------------------------------------------------------------------------------- /02 CommonJS/demo/02_buildin.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | fs.readFile('./02_buildin.js', function(err, data){ 4 | if(err) return false; 5 | console.log('read done!'); 6 | 7 | fs.writeFile('./copy.js', data, (err) => { 8 | if(err) return false; 9 | console.log('write done!'); 10 | }); 11 | 12 | console.log('hi'); 13 | }); 14 | 15 | console.log('ok'); 16 | -------------------------------------------------------------------------------- /02 CommonJS/demo/03_npm_module.js: -------------------------------------------------------------------------------- 1 | var less = require('less'); 2 | var fs = require('fs'); 3 | 4 | fs.readFile('./less/test.less', (err, data) => { 5 | if(err) return false; 6 | 7 | less.render(data.toString(), (e, output) => { 8 | fs.writeFile('./css/test.css', output.css, (err) => { 9 | if(err) return false; 10 | console.log('write done!'); 11 | }); 12 | }); 13 | }); 14 | 15 | // (name) => {console.log(name);} 16 | 17 | // function(name){console.log(name);} 18 | 19 | // less.render('.class { width: (1 + 1) }', function (e, output) { 20 | // console.log(output.css); 21 | // }); 22 | -------------------------------------------------------------------------------- /02 CommonJS/demo/copy.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | console.log(Date.now()); 4 | fs.readFile('./02_buildin.js', function(err, data){ 5 | if(err) return false; 6 | console.log(Date.now()); 7 | console.log('read done!'); 8 | 9 | fs.writeFile('./copy.js', data, (err) => { 10 | if(err) return false; 11 | console.log('write done!'); 12 | }); 13 | 14 | console.log('hi'); 15 | }); 16 | 17 | console.log(1); 18 | 19 | console.log('ok'); 20 | -------------------------------------------------------------------------------- /02 CommonJS/demo/css/min/test.css: -------------------------------------------------------------------------------- 1 | .box{color:#fe33ac;border-color:#fdcdea}.box div{-webkit-box-shadow:0 0 5px rgba(0,0,0,.3);box-shadow:0 0 5px rgba(0,0,0,.3)} -------------------------------------------------------------------------------- /02 CommonJS/demo/css/test.css: -------------------------------------------------------------------------------- 1 | .box { 2 | color: #fe33ac; 3 | border-color: #fdcdea; 4 | } 5 | .box div { 6 | -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 7 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 8 | } 9 | -------------------------------------------------------------------------------- /02 CommonJS/demo/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var less = require('gulp-less'); 3 | var del = require('del'); 4 | var minifyCss = require('gulp-minify-css'); 5 | 6 | del.sync(['css/*']); 7 | 8 | gulp.task('less', function() { 9 | gulp.src('less/test.less') 10 | .pipe(less()) 11 | .pipe(gulp.dest('css')); 12 | }); 13 | 14 | gulp.task('min', function() { 15 | gulp.src('less/test.less') 16 | .pipe(less()) 17 | .pipe(minifyCss()) 18 | .pipe(gulp.dest('css/min')); 19 | }); 20 | 21 | 22 | 23 | gulp.task('default', ['less', 'min']); 24 | -------------------------------------------------------------------------------- /02 CommonJS/demo/less/test.less: -------------------------------------------------------------------------------- 1 | @base: #f938ab; 2 | 3 | .box-shadow(@style, @c) when (iscolor(@c)) { 4 | -webkit-box-shadow: @style @c; 5 | box-shadow: @style @c; 6 | } 7 | .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) { 8 | .box-shadow(@style, rgba(0, 0, 0, @alpha)); 9 | } 10 | .box { 11 | color: saturate(@base, 5%); 12 | border-color: lighten(@base, 30%); 13 | div { .box-shadow(0 0 5px, 30%) } 14 | } 15 | -------------------------------------------------------------------------------- /02 CommonJS/demo/modules/mod1.js: -------------------------------------------------------------------------------- 1 | var name = 'mod1'; 2 | 3 | function print(str){ 4 | console.log(`Hi ${str}!`); 5 | } 6 | 7 | exports.name = name; 8 | 9 | exports.fn = print; 10 | -------------------------------------------------------------------------------- /02 CommonJS/demo/modules/mod2.js: -------------------------------------------------------------------------------- 1 | 2 | // var exports = module.exports; 3 | 4 | module.exports = { 5 | name: 'mod2', 6 | fn: (str) => { 7 | console.log(`Hello ${str}!`); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /02 CommonJS/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "npm modules test", 5 | "main": "01_self.js", 6 | "scripts": { 7 | "test": "node 03_npm_module.js" 8 | }, 9 | "author": "Byron", 10 | "license": "MIT", 11 | "dependencies": { 12 | "del": "~2.2.0", 13 | "gulp": "~3.9.1", 14 | "gulp-less": "~3.0.5", 15 | "gulp-minify-css": "~1.2.4", 16 | "less": "~2.6.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /02 CommonJS/demo/wrapper.js: -------------------------------------------------------------------------------- 1 | (function(exports, require, module, __filename, __dirname){ 2 | var math = require(‘math’); 3 | exports.area = function(radius){ 4 | return Math.PI * radius * radius; 5 | }; 6 | }); 7 | -------------------------------------------------------------------------------- /03 Async & callback/demo/01_ajax.js: -------------------------------------------------------------------------------- 1 | function createXHR(){ 2 | var xhr = null; 3 | 4 | if(XMLHttpRequest){ 5 | xhr = new XMLHttpRequest(); 6 | }else{ 7 | try{ 8 | xhr = new ActiveXObject("Msxml2.XMLHTTP"); 9 | }catch(ex){ 10 | try { 11 | xhr = new ActiveXObject("Microsoft.XMLHTTP"); 12 | } 13 | catch (e) { 14 | xhr = null; 15 | } 16 | } 17 | } 18 | 19 | retrun null; 20 | } 21 | 22 | var xhr = createXHR(); 23 | xhr.onreadystatechange = function () { 24 | if (xhr.readyState == 4 && xhr.status == 200) { 25 | console.log(xhr.responseText); 26 | } 27 | } 28 | xhr.open('get', '//getServerTime.do', true); 29 | xhr.send(); 30 | -------------------------------------------------------------------------------- /03 Async & callback/demo/02_jQuery_ajax.js: -------------------------------------------------------------------------------- 1 | $.ajax({ 2 | method: 'post', 3 | url: '//getServerTimeApi.do', 4 | data: { 5 | name: 'xxx', 6 | timeZone: '+0800' 7 | }, 8 | success: function(ret){}, 9 | error: function(err){} 10 | }); 11 | -------------------------------------------------------------------------------- /03 Async & callback/demo/03_jQuery_ajax2.js: -------------------------------------------------------------------------------- 1 | var doneHanlder = function(ret){ 2 | console.log(ret); 3 | }; 4 | 5 | var failHandler = function (err){ 6 | console.log(err); 7 | }; 8 | 9 | var alwaysHandler = function(ret){ 10 | console.log(ret); 11 | } 12 | 13 | $.ajax({ 14 | url: '//getServerTimeApi.do' 15 | }).done(doneHanlder) 16 | .fail(failHandler) 17 | .always(alwaysHandler); 18 | -------------------------------------------------------------------------------- /03 Async & callback/demo/04_deferred.js: -------------------------------------------------------------------------------- 1 | function getTime(){ 2 | var dtd = $.Deferred(); 3 | 4 | setTimeout(function(){ 5 | var now = Date.now(); 6 | 7 | if(now % 2 === 0){ 8 | dtd.resolve(now); 9 | }else{ 10 | dtd.reject(now); 11 | } 12 | }, 1000); 13 | 14 | return dtd.promise(); 15 | } 16 | 17 | getTime().done(function(time){ 18 | console.log(`OK: ${time}`); 19 | }).fail(function(time){ 20 | console.log(`Error: ${time}`); 21 | }).always(function(time){ 22 | console.log(time); 23 | }); 24 | -------------------------------------------------------------------------------- /03 Async & callback/demo/05_Promise.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function getTime(){ 4 | var promise = new Promise((resolve, reject) => { 5 | setTimeout(() => { 6 | var now = Date.now(); 7 | 8 | if(now % 2 === 0){ 9 | resolve(now); 10 | }else{ 11 | reject(now); 12 | } 13 | }, 500); 14 | }); 15 | 16 | return promise; 17 | } 18 | 19 | // getTime().then((n) => { 20 | // console.log(`OK: ${n}`); 21 | // }, (n) => { 22 | // console.log(`Error: ${n}`); 23 | // }); 24 | 25 | getTime().then(n => { 26 | console.log(`OK: ${n}`); 27 | }).catch(n => { 28 | console.log(`Error: ${n}`); 29 | }); 30 | 31 | function log(n){ 32 | var promise = new Promise((resolve, reject) => { 33 | setTimeout(() => { 34 | console.log(n) 35 | resolve(); 36 | }, 200); 37 | }); 38 | 39 | return promise; 40 | } 41 | 42 | getTime().then(log) 43 | .then(() => { 44 | console.log('done'); 45 | }) 46 | .catch(err => { 47 | console.error(err + ' is odd!'); 48 | }); 49 | -------------------------------------------------------------------------------- /03 Async & callback/demo/06 async/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["stage-3"] 3 | } 4 | -------------------------------------------------------------------------------- /03 Async & callback/demo/06 async/source.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function getTime(){ 4 | var promise = new Promise((resolve, reject) => { 5 | setTimeout(() => { 6 | var now = Date.now(); 7 | 8 | if(now % 2 === 0){ 9 | resolve(now); 10 | }else{ 11 | reject(now); 12 | } 13 | }, 500); 14 | }); 15 | 16 | return promise; 17 | } 18 | 19 | async function print(){ 20 | console.log(Date.now()); 21 | 22 | var t = await getTime().catch(function(err){ 23 | console.log(`Error: ${err}`); 24 | return false; 25 | }); 26 | 27 | console.log(`Done: ${t}`); 28 | } 29 | 30 | print(); 31 | -------------------------------------------------------------------------------- /03 Async & callback/demo/06 async/starter.js: -------------------------------------------------------------------------------- 1 | require("babel-core/register"); 2 | require('./source.js'); 3 | -------------------------------------------------------------------------------- /03 Async & callback/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "01 ajax.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "babel-core": "~6.7.2", 13 | "babel-preset-stage-3": "~6.3.13" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/01_browser_inherits.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function inherits(subType, superType){ 4 | var _prototype = Object.create(superType.prototype); 5 | _prototype.constructor = subType; 6 | subType.prototype = _prototype; 7 | } 8 | 9 | 10 | function Shape(x, y) { 11 | this.x = x; 12 | this.y = y; 13 | } 14 | 15 | Shape.prototype.move = function(x, y) { 16 | this.x += x; 17 | this.y += y; 18 | console.info("Shape moved."); 19 | }; 20 | 21 | function Rectangle(x, y, w, h) { 22 | Shape.call(this); 23 | this.w = w; 24 | this.h = h; 25 | } 26 | 27 | inherits(Rectangle, Shape); 28 | 29 | Rectangle.prototype.area = function(){ 30 | return this.w * this.h; 31 | }; 32 | 33 | var rect = new Rectangle(10, 20, 200, 100); 34 | 35 | console.log(rect instanceof Rectangle); 36 | console.log(rect instanceof Shape); 37 | 38 | rect.move(20, 20); 39 | console.log(rect.area()); 40 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/02_nodejs_inherits.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var inherits = require('util').inherits; 4 | 5 | function Shape(x, y) { 6 | this.x = x; 7 | this.y = y; 8 | } 9 | 10 | Shape.prototype.move = function(x, y) { 11 | this.x += x; 12 | this.y += y; 13 | 14 | console.log(`(${x},${y})`); 15 | }; 16 | 17 | function Rectangle(x, y, w, h) { 18 | Shape.call(this); // 借用构造函数 19 | this.w = w; 20 | this.h = h; 21 | } 22 | 23 | inherits(Rectangle, Shape); 24 | 25 | Rectangle.prototype.area = function(){ 26 | return this.w * this.h; 27 | }; 28 | 29 | var rect = new Rectangle(10, 20, 200, 100); 30 | 31 | console.log(rect instanceof Rectangle); 32 | console.log(rect instanceof Shape); 33 | 34 | rect.move(20, 20); 35 | console.log(rect.area()); 36 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/03_inherits.js: -------------------------------------------------------------------------------- 1 | exports.inherits = function(ctor, superCtor) { 2 | ctor.super_ = superCtor; 3 | ctor.prototype = Object.create(superCtor.prototype, { 4 | constructor: { 5 | value: ctor, 6 | enumerable: false, 7 | writable: true, 8 | configurable: true 9 | } 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/04_events.js: -------------------------------------------------------------------------------- 1 | const util = require('util'); 2 | const EventEmitter = require('events'); 3 | 4 | function MyStream() { 5 | EventEmitter.call(this); 6 | } 7 | 8 | util.inherits(MyStream, EventEmitter); 9 | 10 | MyStream.prototype.write = function(content) { 11 | this.emit('data', content); 12 | }; 13 | 14 | var stream = new MyStream(); 15 | 16 | console.log(stream instanceof EventEmitter); // true 17 | console.log(MyStream.super_ === EventEmitter); // true 18 | 19 | stream.on('data', (content) => { 20 | console.log(`Received data: "${content}"`); 21 | }); 22 | 23 | stream.write('It works!'); // Received data: "It works!" 24 | stream.write('It works!'); // Received data: "It works!" 25 | stream.write('It works!'); // Received data: "It works!" 26 | stream.write('It works!'); // Received data: "It works!" 27 | stream.write('It works!'); // Received data: "It works!" 28 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/05_extends.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const EventEmitter = require('events'); 3 | 4 | class MyEmitter extends EventEmitter {} 5 | 6 | const myEmitter = new MyEmitter(); 7 | 8 | myEmitter.on('data', () => { 9 | console.log('an event occurred!'); 10 | }); 11 | 12 | myEmitter.emit('data'); 13 | myEmitter.emit('data'); 14 | myEmitter.emit('data'); 15 | myEmitter.emit('data'); 16 | myEmitter.emit('data'); 17 | myEmitter.emit('data'); 18 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/06_event_params.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const EventEmitter = require('events'); 3 | class MyEmitter extends EventEmitter {} 4 | 5 | const myEmitter = new MyEmitter(); 6 | myEmitter.on('event', (a, b) => { 7 | console.log(a, b); 8 | }); 9 | myEmitter.emit('event', '1', '2'); 10 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/07_envet_once.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const EventEmitter = require('events'); 3 | class MyEmitter extends EventEmitter {} 4 | 5 | const myEmitter = new MyEmitter(); 6 | var m = 0; 7 | 8 | myEmitter.on('event', () => { 9 | console.log(++m); 10 | }); 11 | myEmitter.once('event2', () => { 12 | console.log(`Once: ${++m}`); 13 | }); 14 | 15 | myEmitter.emit('event'); 16 | myEmitter.emit('event'); 17 | myEmitter.emit('event2'); 18 | myEmitter.emit('event2'); 19 | -------------------------------------------------------------------------------- /04 Inherits & Events/demo/08_remove_listeners.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const EventEmitter = require('events'); 3 | class MyEmitter extends EventEmitter {} 4 | const myEmitter = new MyEmitter(); 5 | 6 | function handler(n){ 7 | console.log(n); 8 | } 9 | 10 | function handler2(n){ 11 | console.log(n * n); 12 | } 13 | 14 | myEmitter.on('event1', handler); 15 | myEmitter.on('event2', handler); 16 | myEmitter.on('event2', handler2); 17 | 18 | myEmitter.on('removeListener', (name, hander) => { 19 | debugger; 20 | console.log(name); 21 | }); 22 | 23 | myEmitter.emit('event1', 1); 24 | myEmitter.emit('event2', 2); 25 | 26 | myEmitter.removeListener('event1', handler); 27 | 28 | myEmitter.removeAllListeners('event2'); 29 | 30 | myEmitter.emit('event1', 1); 31 | myEmitter.emit('event2', 2); 32 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/1. Buffer.md: -------------------------------------------------------------------------------- 1 | # Buffer 2 | 3 | JavaScript对字符串操作十分友好,无论是单字节字符串还是宽字节字符串都被认为是一个字符串 4 | 5 | '0123456789'.length; // 10 6 | '零壹贰叁肆伍陆柒捌玖'.length; // 10 7 | 8 | 在Node应用需要处理网络协议、数据库、图片、文本文件等大量二进制数据,JavaScript自带的字符串不能满足这些场景,`Buffer`应运而生 9 | 10 | >Prior to the introduction of TypedArray in ECMAScript 2015 (ES6), the JavaScript language had no mechanism for reading or manipulating streams of binary data. The Buffer class was introduced as part of the Node.js API to make it possible to interact with octet streams in the context of things like TCP streams and file system operations. 11 | 12 | Buffer是一个类数组对象,主要用于操作字节。性能相关的由C++实现,非性能相关部分JavaScript实现。Buffer所占用的内存不是通过V8分配的,属于堆外内存。 13 | 14 | NodeJS在启用的时候就将Buffer加载到了全局对象(global),使用的时候不用require 15 | 16 | ## 实例化 17 | 18 | const buf1 = new Buffer(10); 19 | // creates a buffer of length 10 20 | 21 | const buf2 = new Buffer([1,2,3]); 22 | // creates a buffer containing [01, 02, 03] 23 | 24 | const buf3 = new Buffer('test'); 25 | // creates a buffer containing ASCII bytes [74, 65, 73, 74] 26 | 27 | const buf4 = new Buffer('tést', 'utf8'); 28 | // creates a buffer containing UTF8 bytes [74, c3, a9, 73, 74] 29 | 30 | const buf1 = new Buffer('buffer'); 31 | const buf2 = new Buffer(buf1); 32 | 33 | buf1[0] = 0x61; 34 | console.log(buf1.toString()); 35 | // 'auffer' 36 | console.log(buf2.toString()); 37 | // 'buffer' (copy is not changed) 38 | 39 | ## encoding 40 | 41 | * 'ascii' - for 7-bit ASCII data only. This encoding method is very fast and will strip the high bit if set. 42 | 43 | * 'utf8' - Multibyte encoded Unicode characters. Many web pages and other document formats use UTF-8. 44 | 45 | * 'utf16le' - 2 or 4 bytes, little-endian encoded Unicode characters. Surrogate pairs (U+10000 to U+10FFFF) are supported. 46 | 47 | * 'ucs2' - Alias of 'utf16le'. 48 | 49 | * 'base64' - Base64 string encoding. When creating a buffer from a string, this encoding will also correctly accept "URL and Filename Safe Alphabet" as specified in RFC 4648, Section 5. 50 | 51 | * 'binary' - A way of encoding the buffer into a one-byte (latin-1) encoded string. The string 'latin-1' is not supported. Instead, pass 'binary' to use 'latin-1' encoding. 52 | 53 | * 'hex' - Encode each byte as two hexadecimal characters. 54 | 55 |   56 | 57 | const buf = new Buffer('hello world', 'ascii'); 58 | 59 | console.log(buf.toString('hex')); 60 | // prints: 68656c6c6f20776f726c64 61 | 62 | console.log(buf.toString('base64')); 63 | // prints: aGVsbG8gd29ybGQ= 64 | 65 | ## byteLength & length 66 | 67 | 获取字符串实际占用字节长度 `Buffer.byteLength(string[, encoding])` 68 | 69 | const str = '\u00bd + \u00bc = \u00be'; 70 | 71 | console.log(`${str}: ${str.length} characters, ` + 72 | `${Buffer.byteLength(str, 'utf8')} bytes`); 73 | 74 | // ½ + ¼ = ¾: 9 characters, 12 bytes 75 | 76 | length 获取Buffer对象占用空间 77 | 78 | const buf = new Buffer(1234); 79 | 80 | console.log(buf.length); 81 | // Prints: 1234 82 | 83 | buf.write('some string', 0, 'ascii'); 84 | console.log(buf.length); 85 | // Prints: 1234 86 | 87 | length属性可变 88 | 89 | var buf = new Buffer(10); 90 | buf.write('abcdefghj', 0, 'ascii'); 91 | console.log(buf.length); 92 | // Prints: 10 93 | buf = buf.slice(0,5); 94 | console.log(buf.length); 95 | // Prints: 5 96 | 97 | ## Buffer.concat(list[, totalLength]) 98 | 99 | 拼接多个Buffer,第一个参数是Buffer对象列表,第二个是总长度,添加后可以提升性能 100 | 101 | const buf1 = new Buffer(10).fill(0); 102 | const buf2 = new Buffer(14).fill(0); 103 | const buf3 = new Buffer(18).fill(0); 104 | const totalLength = buf1.length + buf2.length + buf3.length; 105 | 106 | console.log(totalLength); 107 | const bufA = Buffer.concat([buf1, buf2, buf3], totalLength); 108 | console.log(bufA); 109 | console.log(bufA.length); 110 | 111 | // 42 112 | // 113 | // 42 114 | 115 | ## buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]]) 116 | 117 | 复制Buffer到另一个Buffer对象,可以指定开始、结束位置 118 | 119 | const buf1 = new Buffer(26); 120 | const buf2 = new Buffer(26).fill('!'); 121 | 122 | for (var i = 0 ; i < 26 ; i++) { 123 | buf1[i] = i + 97; // 97 is ASCII a 124 | } 125 | 126 | buf1.copy(buf2, 8, 16, 20); 127 | console.log(buf2.toString('ascii', 0, 25)); 128 | // Prints: !!!!!!!!qrst!!!!!!!!!!!!! 129 | 130 | ## buf.equals(otherBuffer) 131 | 132 | 比较两个Buffer对象内容是否一致 133 | 134 | const buf1 = new Buffer('ABC'); 135 | const buf2 = new Buffer('414243', 'hex'); 136 | const buf3 = new Buffer('ABCD'); 137 | 138 | console.log(buf1.equals(buf2)); 139 | // Prints: true 140 | console.log(buf1.equals(buf3)); 141 | // Prints: false 142 | 143 | ## buf.fill(value[, offset[, end]][, encoding]) 144 | 145 | 为Buffer对象填充内容 146 | 147 | const b = new Buffer(50).fill('h'); 148 | console.log(b.toString()); 149 | // Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 150 | 151 | ## buf.indexOf(value[, byteOffset][, encoding]) 152 | 153 | const buf = new Buffer('this is a buffer'); 154 | 155 | buf.indexOf('this'); 156 | // returns 0 157 | buf.indexOf('is'); 158 | // returns 2 159 | buf.indexOf(new Buffer('a buffer')); 160 | // returns 8 161 | buf.indexOf(97); // ascii for 'a' 162 | // returns 8 163 | buf.indexOf(new Buffer('a buffer example')); 164 | // returns -1 165 | buf.indexOf(new Buffer('a buffer example').slice(0,8)); 166 | // returns 8 167 | 168 | const utf16Buffer = new Buffer('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2'); 169 | 170 | utf16Buffer.indexOf('\u03a3', 0, 'ucs2'); 171 | // returns 4 172 | 173 | ## buf.slice([start[, end]]) 174 | 175 | 返回一个和原Buffer共享内存的Buffer,可以通过后两个参数改变offset和长度 176 | 177 | const buf1 = new Buffer(26); 178 | 179 | for (var i = 0 ; i < 26 ; i++) { 180 | buf1[i] = i + 97; // 97 is ASCII a 181 | } 182 | 183 | const buf2 = buf1.slice(0, 3); 184 | buf2.toString('ascii', 0, buf2.length); 185 | // Returns: 'abc' 186 | buf1[0] = 33; 187 | buf2.toString('ascii', 0, buf2.length); 188 | // Returns : '!bc' 189 | 190 | ## buf.toString([encoding[, start[, end]]]) 191 | 192 | const buf = new Buffer(26); 193 | for (var i = 0 ; i < 26 ; i++) { 194 | buf[i] = i + 97; // 97 is ASCII a 195 | } 196 | buf.toString('ascii'); 197 | // Returns: 'abcdefghijklmnopqrstuvwxyz' 198 | buf.toString('ascii',0,5); 199 | // Returns: 'abcde' 200 | buf.toString('utf8',0,5); 201 | // Returns: 'abcde' 202 | buf.toString(undefined,0,5); 203 | // Returns: 'abcde', encoding defaults to 'utf8' 204 | 205 | ## buf.write(string[, offset[, length]][, encoding]) 206 | 207 | 向Buffer内写数据 208 | 209 | const buf = new Buffer(256); 210 | const len = buf.write('\u00bd + \u00bc = \u00be', 0); 211 | console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`); 212 | // Prints: 12 bytes: ½ + ¼ = ¾ 213 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/2. FileSystem.md: -------------------------------------------------------------------------------- 1 | # File System 2 | 3 | NodeJS把常见的文件操作封装到了`fs`模块中,方法默认都是异步的,部分方法提供了同步版本 4 | 5 | const fs = require('fs'); 6 | 7 | fs.unlink('/tmp/hello', (err) => { 8 | if (err) throw err; 9 | console.log('successfully deleted /tmp/hello'); 10 | }); 11 | 12 | fs.unlinkSync('/tmp/hello'); 13 | console.log('successfully deleted /tmp/hello'); 14 | 15 | ## fs.Stats 16 | 17 | * stats.isFile() 18 | * stats.isDirectory() 19 | * stats.isBlockDevice() 20 | * stats.isCharacterDevice() 21 | * stats.isSymbolicLink() 22 | * stats.isFIFO() 23 | * stats.isSocket() 24 | 25 | ## fs.appendFile(file, data[, options], callback)# 26 | 27 | fs.appendFile('message.txt', 'data to append', (err) => { 28 | if (err) throw err; 29 | console.log('The "data to append" was appended to file!'); 30 | }); 31 | 32 | ## fs.mkdir(path[, mode], callback) 33 | 34 | ## fs.open(path, flags[, mode], callback) 35 | 36 | ## fs.close(fd, callback) 37 | 38 | ## fs.read(fd, buffer, offset, length, position, callback) 39 | 40 | ## fs.write(fd, buffer, offset, length[, position], callback) 41 | 42 | ## fs.readdir(path, callback) 43 | 44 | ## fs.readFile(file[, options], callback) 45 | 46 | fs.readFile('/etc/passwd', (err, data) => { 47 | if (err) throw err; 48 | console.log(data); 49 | }); 50 | 51 | ## fs.writeFile(file, data[, options], callback) 52 | 53 | fs.writeFile('message.txt', 'Hello Node.js', (err) => { 54 | if (err) throw err; 55 | console.log('It\'s saved!'); 56 | }); 57 | 58 | ## fs.rename(oldPath, newPath, callback) 59 | 60 | ## fs.rmdir(path, callback) 61 | 62 | ## fs.watchFile(filename[, options], listener) 63 | 64 | fs.watchFile('message.text', (curr, prev) => { 65 | console.log(`the current mtime is: ${curr.mtime}`); 66 | console.log(`the previous mtime was: ${prev.mtime}`); 67 | }); 68 | 69 | 70 | http://javascript.ruanyifeng.com/nodejs/fs.html 71 | 72 | http://www.cnblogs.com/rubylouvre/archive/2011/11/28/2264717.html 73 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/0. buffer.js: -------------------------------------------------------------------------------- 1 | const buf = new Buffer(26); 2 | for (var i = 0 ; i < 26 ; i++) { 3 | buf[i] = i + 97; // 97 is ASCII a 4 | } 5 | console.log(buf.toString('ascii')); 6 | // Returns: 'abcdefghijklmnopqrstuvwxyz' 7 | console.log(buf.toString('ascii',0,5)); 8 | // Returns: 'abcde' 9 | console.log(buf.toString('base64',0,5)); 10 | // Returns: 'abcde' 11 | console.log(buf.toString(undefined,0,5)); 12 | // Returns: 'abcde', encoding defaults to 'utf8' 13 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/1. badchar.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var rs = fs.createReadStream('test.md', {highWaterMark: 5}); 4 | rs.setEncoding('utf8'); // data事件传递的不再是Buffer,而是编码后的字符串 5 | 6 | var content = ''; 7 | rs.on('data', function(chunk){ 8 | content += chunk; 9 | }); 10 | 11 | rs.on('end', function(){ 12 | console.log(content); 13 | }); 14 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/2. string_decoder.js: -------------------------------------------------------------------------------- 1 | var StringDecoder = require('string_decoder').StringDecoder; 2 | var decoder = new StringDecoder('utf8'); 3 | 4 | console.log(new Buffer('这是个测试。')); 5 | // 6 | 7 | var buf1 = new Buffer([0xe8, 0xbf, 0x99, 0xe6, 0x98]); 8 | console.log(decoder.write(buf1)); 9 | 10 | var buf2 = new Buffer([0xaf, 0xe4, 0xb8, 0xaa, 0xe6, 0xb5, 0x8b, 0xe8, 0xaf, 0x95, 0xe3, 0x80, 0x82]); 11 | console.log(decoder.write(buf2)); 12 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/3. buffer_concat.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var StringDecoder = require('string_decoder').StringDecoder; 3 | var decoder = new StringDecoder('utf8'); 4 | 5 | var rs = fs.createReadStream('test.md'); 6 | 7 | var content = [], 8 | size = 0; 9 | rs.on('data', function(chunk){ 10 | content.push(chunk); // Buffer 11 | size += chunk.length; 12 | }); 13 | 14 | rs.on('end', function(){ 15 | var buf = Buffer.concat(content, size); 16 | console.log(decoder.write(buf)); 17 | }); 18 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/4. file_exist.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | fs.access('./test.md', function(err){ 4 | console.log(err); 5 | }); 6 | 7 | fs.access('./test2.md', function(err){ 8 | console.log(err); 9 | }); 10 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/5. file.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | fs.readFile('./test.md', function(err, data){ 4 | debugger; 5 | if(err){ 6 | console.log(err); 7 | return false; 8 | } 9 | 10 | console.log(`async:\n${data}`); 11 | }); 12 | 13 | var text = fs.readFileSync('./test.md', 'utf8'); 14 | console.log(`sync:\n${text}`); 15 | 16 | fs.writeFileSync('./test3.txt', '我是中国人。', 'utf8'); 17 | fs.writeFile('./test3.txt', '我是中国人!'); 18 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/6. file2.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | fs.readdir('./', function(err, files){ 4 | if(err){ 5 | console.log(err); 6 | return false; 7 | } 8 | 9 | files.forEach(function(file, index){ 10 | //console.log(file); 11 | fs.stat(file, function (err, info) { 12 | debugger; 13 | console.log(info); 14 | }) 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/7. watchFile.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | fs.watchFile('./test3.txt', function (curr, prev) { 4 | debugger; 5 | console.log('the current mtime is: ' + curr.mtime); 6 | console.log('the previous mtime was: ' + prev.mtime); 7 | }); 8 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/test.md: -------------------------------------------------------------------------------- 1 | # test 2 | 3 | This is a test. 4 | 5 | This is a test. 6 | 7 | 这是一个测试。 8 | 9 | 这是一个测试。 10 | 11 | This is a test. 12 | 13 | This is a test. 14 | -------------------------------------------------------------------------------- /05 Buffer & FileSystem/demo/test3.txt: -------------------------------------------------------------------------------- 1 | 我是中国人! 2 | aaabbb 3 | -------------------------------------------------------------------------------- /06 Stream/cus_stream/du1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Duplex = require('stream').Duplex; 4 | 5 | class Du extends Duplex { 6 | 7 | constructor(_readNum) { 8 | super(); 9 | this._readNum = 0; 10 | this.container = []; 11 | } 12 | 13 | _read() { 14 | if (this._readNum > this.container.length) { 15 | this.push(null); 16 | } else { 17 | this.push(this.container[this._readNum++]); 18 | } 19 | } 20 | 21 | _write(buf, enc, next) { 22 | //process.stdout.write(buf.toString() + '\n'); 23 | this.container.push(buf); 24 | next(); 25 | } 26 | 27 | } 28 | 29 | module.exports = Du; 30 | -------------------------------------------------------------------------------- /06 Stream/cus_stream/du2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/06 Stream/cus_stream/du2.js -------------------------------------------------------------------------------- /06 Stream/cus_stream/du_test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Du1 = require('./du1'); 4 | 5 | let du = new Du1(); 6 | 7 | du.on('finish', () => { 8 | console.log('done!'); 9 | }); 10 | 11 | du.write('a'); 12 | du.write('b'); 13 | du.write('c'); 14 | 15 | du.end(); 16 | 17 | du.on('data', data => { 18 | console.log(`ondata: ${data.toString()}`); 19 | }); 20 | -------------------------------------------------------------------------------- /06 Stream/cus_stream/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transform_stream", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "tr1.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "through2": "^2.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /06 Stream/cus_stream/read1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Readable = require('stream').Readable; 4 | 5 | class ToReadable extends Readable{ 6 | 7 | constructor(iterable){ 8 | super(); 9 | this.iterable = iterable || 0; 10 | 11 | // this.iterator = new function *() { 12 | // yield * iterable; 13 | // }; 14 | } 15 | 16 | _read(){ 17 | //const res = this.iterator.next(); 18 | 19 | // if(res.done){ 20 | // this.push(null); 21 | // }else { 22 | // this.push(res.value + '\n'); 23 | // } 24 | 25 | if(this.iterable > 100){ 26 | this.push(null); 27 | }else { 28 | this.push(this.iterable++ + '\n'); 29 | } 30 | 31 | } 32 | 33 | } 34 | 35 | module.exports = ToReadable; -------------------------------------------------------------------------------- /06 Stream/cus_stream/read2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Readable = require('stream').Readable 4 | 5 | // 底层数据 6 | const dataSource = ['a', 'b', 'c'] 7 | 8 | const readable = Readable() 9 | 10 | let n = 0; 11 | 12 | readable._read = function () { 13 | 14 | if (dataSource.length) { 15 | console.log(`read: ${n++}`); 16 | this.push(dataSource.shift()) 17 | } else { 18 | this.push(null) 19 | } 20 | } 21 | 22 | // 进入暂停模式 23 | readable.pause() 24 | readable.on('data', data => console.log('data: ' + data)) 25 | 26 | var data = readable.read() 27 | while (data !== null) { 28 | //console.log('read: ' + data) 29 | data = readable.read() 30 | } -------------------------------------------------------------------------------- /06 Stream/cus_stream/read3.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Readable = require('stream').Readable 4 | 5 | // 底层数据 6 | const dataSource = ['aaa', 'b', 'c'] 7 | 8 | const readable = Readable() 9 | 10 | let n = 0; 11 | 12 | readable._read = function () { 13 | setTimeout(function () { 14 | if (dataSource.length) { 15 | this.push(dataSource.shift()) 16 | } else { 17 | this.push(null) 18 | } 19 | }.bind(this), 1000) 20 | } 21 | 22 | // 进入暂停模式 23 | readable.pause() 24 | readable.on('data', data => console.log('data: ' + data)) 25 | 26 | readable.on('readable', function () { 27 | readable.read() 28 | }) -------------------------------------------------------------------------------- /06 Stream/cus_stream/read_test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const ToReadable = require('./read1.js'); 4 | 5 | const iterable = function *(limit) { 6 | while(limit--){ 7 | yield Math.random(); 8 | } 9 | }(100); 10 | 11 | //const readable = new ToReadable(iterable); 12 | 13 | const readable = new ToReadable(5); 14 | 15 | readable.on('data', data => { 16 | process.stdout.write(data); 17 | }); 18 | 19 | readable.on('end', () => { 20 | process.stdout.write('done\n'); 21 | }); -------------------------------------------------------------------------------- /06 Stream/cus_stream/ret.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/06 Stream/cus_stream/ret.js -------------------------------------------------------------------------------- /06 Stream/cus_stream/tr1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Transform = require('stream').Transform; 4 | 5 | class Rotate extends Transform { 6 | 7 | constructor(n) { 8 | super(); 9 | this.offset = n || 32; 10 | } 11 | 12 | _transform(buf, enc, next) { 13 | let res = buf.toString().split('').map(c => { 14 | 15 | let code = c.charCodeAt(0); // 'abc'.charCodeAt(1); //98 16 | 17 | if (c >= 'a' && c <= 'z') { 18 | code -= this.offset; 19 | } else if (c >= 'A' && c <= 'Z') { 20 | code += this.offset; 21 | } 22 | 23 | return String.fromCharCode(code); 24 | }).join(''); 25 | 26 | this.push(res); 27 | 28 | next(); 29 | } 30 | 31 | } 32 | 33 | module.exports = Rotate; -------------------------------------------------------------------------------- /06 Stream/cus_stream/tr2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Transform = require('stream').Transform; 4 | 5 | class Tr extends Transform{ 6 | 7 | constructor(opt){ 8 | super(opt); 9 | } 10 | 11 | } 12 | 13 | function through(construct) { 14 | return function (options, _transform, _flush) { 15 | if (typeof options === 'function') { 16 | _flush = _transform; 17 | _transform = options; 18 | options = {}; 19 | } 20 | 21 | if (typeof _flush !== 'function') { 22 | _flush = null; 23 | } 24 | 25 | return construct(options, _transform, _flush); 26 | }; 27 | } 28 | 29 | module.exports = through(function (options, _transform, _flush) { 30 | let tr = new Tr(options); 31 | 32 | tr._transform = _transform; 33 | if(_flush){ 34 | tr._flush = _flush; 35 | } 36 | 37 | return tr; 38 | }); -------------------------------------------------------------------------------- /06 Stream/cus_stream/tr_ret1.js: -------------------------------------------------------------------------------- 1 | "trd rsqhbs"; 2 | 3 | bnmrs Uq`mrenql = qdpthqd('rsqd`l').Uq`mrenql; 4 | 5 | bk`rr Sns`sd dwsdmcr Uq`mrenql { 6 | 7 | bnmrsqtbsnq(m) { 8 | rtodq(); 9 | sghr.neerds = m || 32; 10 | } 11 | 12 | _sq`mrenql(ate, dmb, mdws) { 13 | kds qdr = ate.snTsqhmf().rokhs('').l`o(b => { 14 | 15 | kds bncd = b.bg`qDncdBs(0); // '`ab'.bg`qDncdBs(1); //98 16 | 17 | he (b >= '`' && b <= 'y') { 18 | bncd -= sghr.neerds; 19 | } dkrd he (b >= 'B' && b <= '[') { 20 | bncd += sghr.neerds; 21 | } 22 | 23 | qdstqm Tsqhmf.eqnlDg`qDncd(bncd); 24 | }).inhm(''); 25 | 26 | sghr.otrg(qdr); 27 | 28 | mdws(); 29 | } 30 | 31 | } 32 | 33 | lnctkd.dwonqsr = Sns`sd; -------------------------------------------------------------------------------- /06 Stream/cus_stream/tr_ret2.js: -------------------------------------------------------------------------------- 1 | "USE STRICT"; 2 | 3 | CONST tRANSFORM = REQUIRE('STREAM').tRANSFORM; 4 | 5 | CLASS rOTATE EXTENDS tRANSFORM { 6 | 7 | CONSTRUCTOR(N) { 8 | SUPER(); 9 | THIS.OFFSET = N || 32; 10 | } 11 | 12 | _TRANSFORM(BUF, ENC, NEXT) { 13 | LET RES = BUF.TOsTRING().SPLIT('').MAP(C => { 14 | 15 | LET CODE = C.CHARcODEaT(0); // 'ABC'.CHARcODEaT(1); //98 16 | 17 | IF (C >= 'A' && C <= 'Z') { 18 | CODE -= THIS.OFFSET; 19 | } ELSE IF (C >= 'a' && C <= 'z') { 20 | CODE += THIS.OFFSET; 21 | } 22 | 23 | RETURN sTRING.FROMcHARcODE(CODE); 24 | }).JOIN(''); 25 | 26 | THIS.PUSH(RES); 27 | 28 | NEXT(); 29 | } 30 | 31 | } 32 | 33 | MODULE.EXPORTS = rOTATE; -------------------------------------------------------------------------------- /06 Stream/cus_stream/tr_test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require('fs'); 4 | const Tr = require('./tr1.js'); 5 | const Tr2 = require('./tr2.js'); 6 | 7 | var rotate = new Tr(); 8 | 9 | fs.createReadStream('./tr1.js') 10 | .pipe(rotate) 11 | .pipe(fs.createWriteStream('tr_ret1.js')); 12 | 13 | 14 | fs.createReadStream('./tr1.js') 15 | .pipe(new Tr2(function (buf, enc, next) { 16 | let res = buf.toString().split('').map(c => { 17 | 18 | let code = c.charCodeAt(0); 19 | 20 | if (c >= 'a' && c <= 'z') { 21 | code -= 32; 22 | } else if (c >= 'A' && c <= 'Z') { 23 | code += 32; 24 | } 25 | 26 | return String.fromCharCode(code); 27 | }).join(''); 28 | 29 | this.push(res); 30 | 31 | next(); 32 | })) 33 | .pipe(fs.createWriteStream('./tr_ret2.js')); -------------------------------------------------------------------------------- /06 Stream/cus_stream/write1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Writable = require('stream').Writable 4 | 5 | const writable = Writable() 6 | // 实现`_write`方法 7 | // 这是将数据写入底层的逻辑 8 | writable._write = function (data, enc, next) { 9 | // 将流中的数据写入底层 10 | process.stdout.write(data.toString().toUpperCase()) 11 | // 写入完成时,调用`next()`方法通知流传入下一个数据 12 | process.nextTick(next) 13 | } 14 | 15 | // 所有数据均已写入底层 16 | writable.on('finish', () => process.stdout.write('DONE\n')) 17 | 18 | // 将一个数据写入流中 19 | writable.write('a' + '\n') 20 | writable.write('b' + '\n') 21 | writable.write('c' + '\n') 22 | 23 | // 再无数据写入流时,需要调用`end`方法 24 | writable.end() 25 | 26 | a.pipe(b); 27 | -------------------------------------------------------------------------------- /06 Stream/demo/duplex.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/06 Stream/demo/duplex.js -------------------------------------------------------------------------------- /06 Stream/demo/files/message.txt: -------------------------------------------------------------------------------- 1 | beep boop 2 | -------------------------------------------------------------------------------- /06 Stream/demo/files/transform.js: -------------------------------------------------------------------------------- 1 | CONST TR = REQUIRE('THROUGH2'); 2 | CONST FS = REQUIRE('FS'); 3 | CONST SPLIT = REQUIRE('SPLIT'); 4 | FS.CREATEREADSTREAM('TRANSFORM1.JS') 5 | .PIPE(SPLIT()) 6 | .PIPE(TR(FUNCTION(BUF, _, NEXT){ 7 | IF(BUF.TOSTRING().LENGTH > 15){ 8 | CONSOLE.LOG(BUF.TOSTRING().LENGTH); 9 | THIS.PUSH(BUF.TOSTRING().TOUPPERCASE()); 10 | THIS.PUSH('\N'); 11 | .PIPE(FS.CREATEWRITESTREAM('FILES/TRANSFORM.JS')); 12 | -------------------------------------------------------------------------------- /06 Stream/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "readable.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "publishConfig": { 13 | "registry": "http://registry.npm.alibaba-inc.com" 14 | }, 15 | "dependencies": { 16 | "split": "~1.0.0", 17 | "through2": "~2.0.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /06 Stream/demo/readable.js: -------------------------------------------------------------------------------- 1 | var Readable = require('stream').Readable; 2 | 3 | var rs = new Readable(); 4 | rs.push(new Buffer('Hello\n')); 5 | rs.push(null); 6 | 7 | rs.pipe(process.stdout); 8 | console.log(1); 9 | -------------------------------------------------------------------------------- /06 Stream/demo/readable2.js: -------------------------------------------------------------------------------- 1 | var Readable = require('stream').Readable; 2 | 3 | var rs = new Readable(); 4 | var c = 97; 5 | 6 | rs._read = function(){ 7 | rs.push(String.fromCharCode(c++)); 8 | if(c > 'z'.charCodeAt(0)){ 9 | rs.push(null); 10 | } 11 | }; 12 | 13 | rs.pipe(process.stdout); 14 | -------------------------------------------------------------------------------- /06 Stream/demo/readable3.js: -------------------------------------------------------------------------------- 1 | var Readable = require('stream').Readable; 2 | var rs = new Readable(); 3 | 4 | var c = 97 - 1; 5 | 6 | rs._read = function () { 7 | if(c > 'z'.charCodeAt(0)){ 8 | return rs.push(null); 9 | } 10 | 11 | setTimeout(function(){ 12 | rs.push(String.fromCharCode(++c)); 13 | }, 100); 14 | } 15 | 16 | rs.pipe(process.stdout); 17 | 18 | process.on('exit', function () { 19 | console.error('\n_read() called ' + (c - 97) + ' times'); 20 | }); 21 | process.stdout.on('error', process.exit); 22 | -------------------------------------------------------------------------------- /06 Stream/demo/readable4.js: -------------------------------------------------------------------------------- 1 | process.stdin.on('readable', function () { 2 | var buf = process.stdin.read(3); 3 | console.log(buf); 4 | process.stdin.read(0); 5 | }); 6 | -------------------------------------------------------------------------------- /06 Stream/demo/rw_stream.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var fs = require('fs'); 3 | 4 | var fcopy = function(){ 5 | console.log(1,Date.now()); 6 | var source = fs.readFileSync('./copy.js', {encoding: 'utf-8'}); 7 | console.log(2,Date.now()); 8 | fs.writeFileSync('./files/copy2.js', source); 9 | console.log(3,Date.now()); 10 | }; 11 | 12 | var scopy = function(){ 13 | var rs = fs.createReadStream('./source.mp4'), 14 | ws = fs.createWriteStream('./files/xxx.mp4'), 15 | counter = 0; 16 | 17 | rs.on('data', function(chunk){ 18 | ws.write(chunk); 19 | }); 20 | 21 | rs.on('end', function(){ 22 | ws.end(); 23 | }); 24 | }; 25 | 26 | 27 | var scopy2 = function(){ 28 | var rs = fs.createReadStream('./source.mp4'), 29 | ws = fs.createWriteStream('./files/xxx.mp4'); 30 | 31 | rs.on('data', function(chunk){ 32 | if(ws.write(chunk) === false){ 33 | rs.pause(); 34 | } 35 | }); 36 | 37 | ws.on('drain', function(){ 38 | rs.resume(); 39 | }); 40 | 41 | rs.on('end', function(){ 42 | ws.end(); 43 | }); 44 | }; 45 | 46 | var pipe = function(){ 47 | fs.createReadStream('./source.mp4') 48 | .pipe(fs.createWriteStream('./files/xxx.mp4')); 49 | } 50 | 51 | var pcopy = function(){ 52 | var out = process.stdout, 53 | rs = fs.createReadStream('./source.mp4'), 54 | ws = fs.createWriteStream('./files/source.mp4'), 55 | stat = fs.statSync('./source.mp4'), 56 | total = stat.size, 57 | length = 0, 58 | last = 0, 59 | start = Date.now(); 60 | 61 | rs.on('data', function(chunk){ 62 | length += chunk.length; 63 | 64 | if(ws.write(chunk) === false){ 65 | rs.pause(); 66 | } 67 | }); 68 | 69 | ws.on('drain', function() { 70 | rs.resume(); 71 | }); 72 | 73 | rs.on('end', function () { 74 | ws.end(); 75 | }); 76 | 77 | setTimeout(function display(){ 78 | var percent = ((length / total) * 100).toFixed(2), 79 | speed = ((length - last) * 10 / 1000000).toFixed(2); 80 | 81 | last = length; 82 | 83 | out.clearLine(); 84 | out.cursorTo(0); 85 | out.write(`${length}KB\t/ ${total}KB\t ${percent}%\t ${speed}MB/s`); 86 | 87 | if(length < total){ //未完成 88 | setTimeout(display, 100); 89 | }else{ 90 | var end = Date.now(); 91 | console.log(`\n共用时: ${(end - start)/1000}秒`); 92 | } 93 | }, 500); 94 | }; 95 | 96 | pcopy(); 97 | -------------------------------------------------------------------------------- /06 Stream/demo/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var fs = require('fs'); 3 | 4 | var server = http.createServer(function(req, res){ 5 | 6 | //res.writeHead(200, {'Content-Type': 'text/html'}); 7 | 8 | var source = fs.createReadStream('./source.mp4'); 9 | source.pipe(res); 10 | 11 | }); 12 | 13 | server.listen(process.argv[2]); 14 | -------------------------------------------------------------------------------- /06 Stream/demo/transform1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const tr = require('through2'); 3 | const fs = require('fs'); 4 | const split = require('split'); 5 | 6 | fs.createReadStream('transform1.js') 7 | .pipe(split()) 8 | .pipe(tr(function(buf, _, next){ 9 | if(buf.toString().length > 15){ 10 | console.log(buf.toString().length); 11 | this.push(buf.toString().toUpperCase()); 12 | this.push('\n'); 13 | } 14 | next(); 15 | })) 16 | .pipe(fs.createWriteStream('files/transform.js')); 17 | -------------------------------------------------------------------------------- /06 Stream/demo/writeable1.js: -------------------------------------------------------------------------------- 1 | var Writable = require('stream').Writable; 2 | var ws = Writable(); 3 | ws._write = function (chunk, enc, next) { 4 | console.log(chunk); 5 | next(); 6 | }; 7 | 8 | process.stdin.pipe(ws); 9 | -------------------------------------------------------------------------------- /06 Stream/demo/writeable2.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var ws = fs.createWriteStream('files/message.txt'); 3 | 4 | ws.write('beep '); 5 | 6 | setTimeout(function () { 7 | ws.end('boop\n'); 8 | }, 1000); 9 | -------------------------------------------------------------------------------- /06 Stream/function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/06 Stream/function.png -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/dist/a.js: -------------------------------------------------------------------------------- 1 | test 2 | // a.js begin 3 | 4 | alert('a'); 5 | 6 | // a.js end -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/dist/b.js: -------------------------------------------------------------------------------- 1 | test 2 | // a.js begin 3 | 4 | alert('b'); 5 | 6 | // a.js end -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/gulpfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const gulp = require('gulp'); 4 | const plugin1 = require('./plugin1'); 5 | const plugin2 = require('./plugin2'); 6 | 7 | gulp.task('default', () => { 8 | gulp.src('src/*.js') 9 | .pipe(plugin1()) 10 | .pipe(gulp.dest('./dist')); 11 | }); 12 | 13 | gulp.task('plugin2', () => { 14 | gulp.src('src/*.js') 15 | .pipe(plugin2('test\n')) 16 | .pipe(gulp.dest('./dist')); 17 | }); -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp_plugin", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "gulpfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "gulp": "^3.9.1", 13 | "gulp-util": "^3.0.7", 14 | "through-gulp": "^0.5.0", 15 | "through2": "^2.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/plugin1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const through = require('through-gulp'); 4 | 5 | module.exports = () => { 6 | let stream = through(function (file, encoding, callback) { 7 | if (file.isNull()) { 8 | } 9 | 10 | if (file.isBuffer()) { 11 | let contents = file.contents.toString('utf-8').toUpperCase(); 12 | file.contents = new Buffer(contents, encoding); 13 | } 14 | 15 | if (file.isStream()) { 16 | console.log('stream'); 17 | } 18 | 19 | // just pipe data next, or just do nothing to process file later in flushFunction 20 | // never forget callback to indicate that the file has been processed. 21 | this.push(file); 22 | callback(); 23 | 24 | }, function (callback) { 25 | // just pipe data next, just callback to indicate that the stream's over 26 | this.push(null); 27 | callback(); 28 | }); 29 | 30 | return stream; 31 | }; -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/plugin2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const through = require('through2'); 4 | const gutil = require('gulp-util'); 5 | const PluginError = gutil.PluginError; 6 | 7 | const PLUGIN_NAME = 'gulp-prefixer'; 8 | 9 | function gulpPrefixer(prefixText) { 10 | if (!prefixText) { 11 | throw new PluginError(PLUGIN_NAME, 'Missing prefix text!'); 12 | } 13 | 14 | prefixText = new Buffer(prefixText); 15 | 16 | let stream = through.obj(function (file, enc, cb) { 17 | if (file.isStream()) { 18 | this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!')); 19 | return cb(); 20 | } 21 | 22 | if (file.isBuffer()) { 23 | file.contents = Buffer.concat([prefixText, file.contents]); 24 | } 25 | 26 | // 确保文件进入下一个 gulp 插件 27 | this.push(file); 28 | 29 | // 告诉 stream 引擎,我们已经处理完了这个文件 30 | cb(); 31 | }); 32 | 33 | return stream; 34 | }; 35 | 36 | module.exports = gulpPrefixer; -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/plugin3.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/06 Stream/gulp_plugin/plugin3.js -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/src/a.js: -------------------------------------------------------------------------------- 1 | // a.js begin 2 | 3 | alert('a'); 4 | 5 | // a.js end -------------------------------------------------------------------------------- /06 Stream/gulp_plugin/src/b.js: -------------------------------------------------------------------------------- 1 | // a.js begin 2 | 3 | alert('b'); 4 | 5 | // a.js end -------------------------------------------------------------------------------- /06 Stream/processing.svg: -------------------------------------------------------------------------------- 1 | Without streamingProcessRenderFetchWith streaming -------------------------------------------------------------------------------- /07 HTTP Server/cache-control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/07 HTTP Server/cache-control.png -------------------------------------------------------------------------------- /07 HTTP Server/connect/app1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http =require('http'); 4 | const connect = require('connect'); 5 | 6 | let app = connect(); 7 | 8 | app.use((req, res, next) => { 9 | console.log(req.url); 10 | next(); 11 | }); 12 | 13 | app.use((req, res) => { 14 | res.end('Hello from connect!'); 15 | }); 16 | 17 | http.createServer(app).listen(3000); 18 | 19 | // http.createServer((req, res) => { 20 | // res.end('Hello World!'); 21 | // }).listen(3001) -------------------------------------------------------------------------------- /07 HTTP Server/connect/app2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http =require('http'); 4 | const connect = require('connect'); 5 | const fs = require('fs'); 6 | const url = require('url'); 7 | const path = require('path'); 8 | const public_folder = path.join(__dirname, 'public'); 9 | 10 | 11 | let app = connect(), 12 | filePath = '', 13 | stats = null; 14 | 15 | app.use((req, res, next) => { 16 | let pathName = url.parse(req.url).pathname; 17 | filePath = path.join(public_folder, path.normalize(pathName.replace(/\.\./g, ''))); 18 | next(); 19 | }); 20 | 21 | app.use((req, res, next) => { 22 | try{ 23 | stats = fs.statSync(filePath); 24 | next(); 25 | }catch(ex){ 26 | res.writeHead(404, { 27 | 'Content-Type': 'text/html' 28 | }); 29 | res.end('404'); 30 | } 31 | }); 32 | 33 | app.use((req, res, next) => { 34 | if(stats.isDirectory()){ 35 | let files = fs.readdirSync(filePath); 36 | 37 | res.writeHead(200, { 38 | 'Content-Type': 'text/html' 39 | }); 40 | res.end(files.join('
')); 41 | }else{ 42 | next(); 43 | } 44 | }); 45 | 46 | app.use((req, res) => { 47 | res.writeHead(200, { 48 | 'Content-Type': 'text/html' 49 | }); 50 | fs.createReadStream(filePath).pipe(res); 51 | }); 52 | 53 | http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /07 HTTP Server/connect/app3.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http =require('http'); 4 | const connect = require('connect'); 5 | const fs = require('fs'); 6 | const url = require('url'); 7 | const path = require('path'); 8 | const public_folder = path.join(__dirname, 'public'); 9 | 10 | 11 | let app = connect(), 12 | filePath = '', 13 | stats = null; 14 | 15 | app.use((req, res, next) => { 16 | let pathName = url.parse(req.url).pathname; 17 | filePath = path.join(public_folder, path.normalize(pathName.replace(/\.\./g, ''))); 18 | next(); 19 | }); 20 | 21 | app.use((req, res, next) => { 22 | try{ 23 | stats = fs.statSync(filePath); 24 | next(); 25 | }catch(ex){ 26 | res.writeHead(404, { 27 | 'Content-Type': 'text/html' 28 | }); 29 | res.end('404'); 30 | } 31 | }); 32 | 33 | app.use((req, res, next) => { 34 | if(stats.isDirectory()){ 35 | res.writeHead(200, { 36 | 'Content-Type': 'text/html' 37 | }); 38 | let files = fs.readdirSync(filePath); 39 | res.end(file.jion('
')); 40 | } else{ 41 | next(); 42 | } 43 | }); 44 | 45 | app.use((req, res) => { 46 | res.writeHead(200, { 47 | 'Content-Type': 'text/html' 48 | }); 49 | fs.createReadStream(filePath).pipe(res); 50 | }); 51 | 52 | http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /07 HTTP Server/connect/app4.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http =require('http'); 4 | const connect = require('connect'); 5 | const fs = require('fs'); 6 | const url = require('url'); 7 | const path = require('path'); 8 | const serveIndex = require('serve-index'); 9 | const public_folder = path.join(__dirname, 'public'); 10 | 11 | 12 | let app = connect(), 13 | filePath = '', 14 | stats = null; 15 | 16 | app.use((req, res, next) => { 17 | let pathName = url.parse(req.url).pathname; 18 | filePath = path.join(public_folder, path.normalize(pathName.replace(/\.\./g, ''))); 19 | next(); 20 | }); 21 | 22 | app.use((req, res, next) => { 23 | try{ 24 | stats = fs.statSync(filePath); 25 | next(); 26 | }catch(ex){ 27 | res.writeHead(404, { 28 | 'Content-Type': 'text/html' 29 | }); 30 | res.end('404'); 31 | } 32 | }); 33 | 34 | app.use(serveIndex(public_folder, {'icons': true})); 35 | 36 | app.use((req, res) => { 37 | res.writeHead(200, { 38 | 'Content-Type': 'text/html' 39 | }); 40 | fs.createReadStream(filePath).pipe(res); 41 | }); 42 | 43 | http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /07 HTTP Server/connect/app5.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http =require('http'); 4 | const connect = require('connect'); 5 | const fs = require('fs'); 6 | const url = require('url'); 7 | const path = require('path'); 8 | const serveIndex = require('serve-index'); 9 | const serveStatic = require('serve-static'); 10 | 11 | const public_folder = path.join(__dirname, 'public'); 12 | 13 | 14 | let app = connect(), 15 | filePath = '', 16 | stats = null; 17 | 18 | app.use((req, res, next) => { 19 | let pathName = url.parse(req.url).pathname; 20 | filePath = path.join(public_folder, path.normalize(pathName.replace(/\.\./g, ''))); 21 | next(); 22 | }); 23 | 24 | app.use((req, res, next) => { 25 | try{ 26 | stats = fs.statSync(filePath); 27 | next(); 28 | }catch(ex){ 29 | res.writeHead(404, { 30 | 'Content-Type': 'text/html' 31 | }); 32 | res.end('404'); 33 | } 34 | }); 35 | 36 | app.use(serveIndex(public_folder, {'icons': true})); 37 | 38 | app.use(serveStatic(public_folder)); 39 | 40 | http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /07 HTTP Server/connect/app6.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http =require('http'); 4 | const connect = require('connect'); 5 | const fs = require('fs'); 6 | const url = require('url'); 7 | const path = require('path'); 8 | const serveIndex = require('serve-index'); 9 | const serveStatic = require('serve-static'); 10 | const mid404 = require('./mid404.js'); 11 | 12 | const public_folder = path.join(__dirname, 'public'); 13 | 14 | let app = connect(), 15 | filePath = '', 16 | stats = null; 17 | debugger; 18 | app.use(mid404); 19 | 20 | app.use((req, res, next) => { 21 | let pathName = url.parse(req.url).pathname; 22 | filePath = path.join(public_folder, path.normalize(pathName.replace(/\.\./g, ''))); 23 | next(); 24 | }); 25 | 26 | app.use((req, res, next) => { 27 | try{ 28 | stats = fs.statSync(filePath); 29 | next(); 30 | }catch(ex){ 31 | res.writeHead(404, { 32 | 'Content-Type': 'text/html' 33 | }); 34 | res.end('404'); 35 | } 36 | }); 37 | 38 | app.use(serveIndex(public_folder, {'icons': true})); 39 | 40 | app.use(serveStatic(public_folder)); 41 | 42 | http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /07 HTTP Server/connect/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const debug =require('degub')('connect:dispatcher'); 4 | const EventEmitter = require('events').EventEmitter; 5 | const finalhandler = require('finalhandler'); 6 | const http = require('http'); 7 | const merge = require('util-merge'); 8 | const parseUrl = require('parseurl'); 9 | 10 | module.exports = createServer; 11 | 12 | const env = process.env.NODE_ENV || 'development'; 13 | 14 | const proto = {}; 15 | 16 | function createServer() { 17 | function app(req, res, next){ 18 | app.handle(req, res, next); 19 | } 20 | 21 | merge(app, proto); 22 | merge(app, EventEmitter.prototype); 23 | 24 | app.route = '/'; 25 | app.stack = []; 26 | return app; 27 | } 28 | 29 | proto.use = function use(route, fn) { 30 | let handle = fn, 31 | path = route; 32 | 33 | if(typeof route !== 'string'){ 34 | handle = route; 35 | path = '/'; 36 | } 37 | 38 | if(typeof handle.handle === 'function'){ 39 | let server = handle; 40 | server.route = path; 41 | handle = function (req, res, next) { 42 | server.handle(req, res, next); 43 | }; 44 | } 45 | 46 | if(handle instanceof http.server){ 47 | handle = handle.listeners('request')[0]; 48 | } 49 | 50 | if(path[path.length - 1] === '/'){ 51 | path = path.slice(0, -1); 52 | } 53 | 54 | 55 | }; -------------------------------------------------------------------------------- /07 HTTP Server/connect/mid404.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = (req, res, next) => { 4 | console.log(new Date().toUTCString()); 5 | next(); 6 | }; -------------------------------------------------------------------------------- /07 HTTP Server/connect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "static_server", 3 | "version": "1.0.0", 4 | "description": "NodeJS static Server", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "NodeJS", 11 | "http", 12 | "static", 13 | "server" 14 | ], 15 | "author": "sunluyong@gmail.com", 16 | "license": "MIT", 17 | "dependencies": { 18 | "body-parser": "~1.15.0", 19 | "compression": "~1.6.1", 20 | "connect": "~3.4.1", 21 | "cookie-session": "~1.2.0", 22 | "serve-index": "~1.7.3", 23 | "serve-static": "~1.10.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /07 HTTP Server/connect/public/a.js: -------------------------------------------------------------------------------- 1 | //a -------------------------------------------------------------------------------- /07 HTTP Server/connect/public/a/t.txt: -------------------------------------------------------------------------------- 1 | xxx -------------------------------------------------------------------------------- /07 HTTP Server/connect/public/b.js: -------------------------------------------------------------------------------- 1 | //b -------------------------------------------------------------------------------- /07 HTTP Server/connect/public/c.css: -------------------------------------------------------------------------------- 1 | c.css -------------------------------------------------------------------------------- /07 HTTP Server/connect/public/d.html: -------------------------------------------------------------------------------- 1 | html -------------------------------------------------------------------------------- /07 HTTP Server/connect/serve-index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http =require('http'); 4 | const connect = require('connect'); 5 | const serveIndex = require('serve-index'); 6 | const path = require('path'); 7 | 8 | let app = connect(); 9 | 10 | app.use(serveIndex(path.join(__dirname, 'public'), {'icons': true})); 11 | 12 | app.use((req, res) => { 13 | res.end('Hello from connect!'); 14 | }); 15 | 16 | http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /07 HTTP Server/demo/01_base_http.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | 5 | let server = http.createServer(function(req, res){ 6 | debugger; 7 | res.write('Hello World!'); 8 | res.end(); 9 | }); 10 | 11 | server.listen(8033); 12 | 13 | // 报文 14 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/02_argv.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | 5 | let server = http.createServer(function(req, res){ 6 | res.end('Hello World!'); 7 | }); 8 | 9 | server.listen(process.argv[2] || 9000); 10 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/03_readfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | * assert root path is __dirname 5 | */ 6 | 7 | const http = require('http'); 8 | const fs = require('fs'); 9 | const url = require('url'); 10 | const path = require('path'); 11 | 12 | let server = http.createServer(function(req, res){ 13 | 14 | let pathName = url.parse(req.url).pathname; // /package.json 15 | 16 | // __dirname: ./Users/Samaritan/Desktop/book/07 HTTP Server/demo 17 | // pathName: /package.json 18 | let fileDiskPath = path.join(__dirname, pathName); 19 | 20 | let body = fs.createReadStream(fileDiskPath); 21 | 22 | body.pipe(res); 23 | 24 | }); 25 | 26 | server.listen(process.argv[2] || 9000); 27 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/04_directory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | const path = require('path'); 7 | const handlebars = require('handlebars'); 8 | 9 | let server = http.createServer(function(req, res){ 10 | let pathName = url.parse(req.url).pathname, 11 | realPath = path.join(__dirname, pathName); 12 | 13 | fs.stat(realPath, (err, stats) => { 14 | if(err){ // file or forder do not exists 15 | res.writeHead(404, { 16 | 'content-type':'text/html' 17 | }); 18 | let source = fs.readFileSync('./template/404.tmpl'), 19 | template = handlebars.compile(source.toString()), 20 | data = { 21 | path: url.parse(req.url).pathname 22 | }; 23 | 24 | res.end(template(data)); 25 | // res.write(template(data)); 26 | // res.end(); 27 | 28 | // let path = url.parse(req.url).pathname; 29 | // 30 | // res.end(` 31 | // 32 | // 33 | // 34 | // 404 35 | // 46 | // 47 | // 48 | // file ${path} do not exists; 49 | // 50 | // `); 51 | }else{ 52 | if(stats.isDirectory()){ 53 | let source = fs.readFileSync('./template/directory.tmpl'), 54 | template = handlebars.compile(source.toString()), 55 | data = { 56 | title: url.parse(req.url).name, 57 | path: path.join(pathName, '/'), 58 | files: [] 59 | }; 60 | 61 | data.files = fs.readdirSync(realPath); 62 | res.end(template(data)); 63 | 64 | // fs.readdir(realPath, (err, files) => { 65 | // data.files = files; 66 | // res.end(template(data)); 67 | // }); 68 | }else{ 69 | fs.createReadStream(realPath).pipe(res); 70 | } 71 | } 72 | }); 73 | 74 | }); 75 | 76 | server.listen(process.argv[2] || 9000); 77 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/05_mime.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | const path = require('path'); 7 | const mime = require('../ss/mime.json'); 8 | const handlebars = require('handlebars'); 9 | 10 | let server = http.createServer(function(req, res){ 11 | let pathName = url.parse(req.url).pathname, 12 | realPath = path.join(__dirname, pathName); 13 | 14 | fs.stat(realPath, (err, stats) => { 15 | if(err){ // file do not exists 16 | let source = fs.readFileSync('./template/404.tmpl'), 17 | template = handlebars.compile(source.toString()), 18 | data = { 19 | path: url.parse(req.url).name 20 | }; 21 | res.setHeader('Content-Type', 'text/html'); 22 | res.end(template(data)); 23 | }else{ 24 | if(stats.isDirectory()){ 25 | let source = fs.readFileSync('./template/directory.tmpl'), 26 | template = handlebars.compile(source.toString()), 27 | data = { 28 | title: url.parse(req.url).name, 29 | path: path.join(pathName, '/'), 30 | files: [] 31 | }; 32 | 33 | data.files = fs.readdirSync(realPath); 34 | 35 | res.setHeader('Content-Type', 'text/html'); 36 | res.end(template(data)); 37 | }else{ 38 | let extension = path.extname(pathName).replace('.', ''), 39 | fileType = mime[extension] || 'text/plain'; 40 | 41 | res.setHeader('Content-Type', fileType); 42 | fs.createReadStream(realPath).pipe(res); 43 | } 44 | } 45 | }); 46 | }); 47 | 48 | server.listen(process.argv[2] || 9000); 49 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/06_status_code.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | const path = require('path'); 7 | const mime = require('../ss/mime.json'); 8 | const handlebars = require('handlebars'); 9 | 10 | let server = http.createServer(function(req, res){ 11 | let pathName = url.parse(req.url).pathname, 12 | realPath = path.join(__dirname, pathName); 13 | 14 | fs.stat(realPath, (err, stats) => { 15 | if(err){ // file do not exists 16 | let source = fs.readFileSync('./template/404.tmpl'), 17 | template = handlebars.compile(source.toString()), 18 | data = { 19 | path: url.parse(req.url).name 20 | }; 21 | 22 | res.writeHead(404, { 23 | 'Content-Type': 'text/html' 24 | }); 25 | res.end(template(data)); 26 | }else{ 27 | if(stats.isDirectory()){ 28 | let source = fs.readFileSync('./template/directory.tmpl'), 29 | template = handlebars.compile(source.toString()), 30 | data = { 31 | title: url.parse(req.url).name, 32 | path: path.join(pathName, '/'), 33 | files: [] 34 | }; 35 | 36 | data.files = fs.readdirSync(realPath); 37 | 38 | res.writeHead(200, { 39 | 'Content-Type': 'text/html' 40 | }); 41 | res.end(template(data)); 42 | }else{ 43 | let extension = path.extname(pathName).replace('.', ''), 44 | fileType = mime[extension] || 'text/plain'; 45 | 46 | res.writeHead(200, { 47 | 'Content-Type': fileType 48 | }); 49 | fs.createReadStream(realPath).pipe(res); 50 | } 51 | } 52 | }); 53 | }); 54 | 55 | server.listen(process.argv[2] || 9000); 56 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/07_public.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | const path = require('path'); 7 | const mime = require('../ss/mime.json'); 8 | const handlebars = require('handlebars'); 9 | const public_folder = path.join(__dirname, 'node_modules'); 10 | 11 | let server = http.createServer(function(req, res){ 12 | let pathName = url.parse(req.url).pathname, 13 | realPath = path.join(public_folder, pathName); 14 | 15 | fs.stat(realPath, (err, stats) => { 16 | if(err){ // file do not exists 17 | let source = fs.readFileSync('./template/404.tmpl'), 18 | template = handlebars.compile(source.toString()), 19 | data = { 20 | path: path.basename(url.parse(req.url).pathname) 21 | }; 22 | 23 | res.writeHead(404, { 24 | 'Content-Type': 'text/html' 25 | }); 26 | res.end(template(data)); 27 | }else{ 28 | if(stats.isDirectory()){ 29 | let source = fs.readFileSync('./template/directory.tmpl'), 30 | template = handlebars.compile(source.toString()), 31 | data = { 32 | title: url.parse(req.url).name, 33 | path: path.join(pathName, '/'), 34 | files: [] 35 | }; 36 | 37 | data.files = fs.readdirSync(realPath); 38 | 39 | res.writeHead(200, { 40 | 'Content-Type': 'text/html' 41 | }); 42 | res.end(template(data)); 43 | }else{ 44 | let extension = path.extname(pathName).replace('.', ''), 45 | fileType = mime[extension] || 'text/plain'; 46 | 47 | res.writeHead(200, { 48 | 'Content-Type': fileType 49 | }); 50 | fs.createReadStream(realPath).pipe(res); 51 | } 52 | } 53 | }); 54 | }); 55 | 56 | server.listen(process.argv[2] || 9000); 57 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/08_compress.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | const path = require('path'); 7 | const mime = require('../ss/mime.json'); 8 | const handlebars = require('handlebars'); 9 | var zlib = require("zlib"); 10 | const public_folder = path.join(__dirname, 'node_modules'); 11 | 12 | let server = http.createServer(function(req, res){ 13 | let pathName = url.parse(req.url).pathname, 14 | realPath = path.join(public_folder, pathName); 15 | 16 | fs.stat(realPath, (err, stats) => { 17 | if(err){ // file do not exists 18 | let source = fs.readFileSync('./template/404.tmpl'), 19 | template = handlebars.compile(source.toString()), 20 | data = { 21 | path: path.basename(url.parse(req.url).pathname) 22 | }; 23 | 24 | res.writeHead(404, { 25 | 'Content-Type': 'text/html' 26 | }); 27 | res.end(template(data)); 28 | }else{ 29 | if(stats.isDirectory()){ 30 | let source = fs.readFileSync('./template/directory.tmpl'), 31 | template = handlebars.compile(source.toString()), 32 | data = { 33 | title: url.parse(req.url).name, 34 | path: path.join(pathName, '/'), 35 | files: [] 36 | }; 37 | 38 | data.files = fs.readdirSync(realPath); 39 | 40 | res.writeHead(200, { 41 | 'Content-Type': 'text/html' 42 | }); 43 | res.end(template(data)); 44 | }else{ 45 | let extension = path.extname(pathName).replace('.', ''), 46 | fileType = mime[extension] || 'text/plain'; 47 | 48 | let acceptEncoding = req.headers['accept-encoding'] || '', 49 | compressable = extension.match(/css|js|html|json|xml|txt|md/ig); 50 | 51 | res.statusCode = 200; 52 | res.setHeader('Content-Type', fileType); 53 | 54 | if(compressable && acceptEncoding.match(/\bgzip\b/)){ 55 | res.setHeader('Content-Encoding', 'gzip'); 56 | fs.createReadStream(realPath).pipe(zlib.createGzip()).pipe(res); 57 | 58 | }else if(compressable && acceptEncoding.match(/\bdeflate\b/)){ 59 | res.setHeader('Content-Encoding', 'defalte'); 60 | fs.createReadStream(realPath).pipe(zlib.createDeflate()).pipe(res); 61 | 62 | }else{ 63 | fs.createReadStream(realPath).pipe(res); 64 | } 65 | 66 | } 67 | } 68 | }); 69 | }); 70 | 71 | server.listen(process.argv[2] || 9000); 72 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/09_secure.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | const path = require('path'); 7 | const mime = require('../ss/mime.json'); 8 | const handlebars = require('handlebars'); 9 | var zlib = require("zlib"); 10 | const public_folder = path.join(__dirname, 'node_modules'); 11 | 12 | let server = http.createServer(function(req, res){ 13 | let pathName = url.parse(req.url).pathname, 14 | realPath = path.join(public_folder, path.normalize(pathName.replace(/\.\./g, ''))); 15 | 16 | fs.stat(realPath, (err, stats) => { 17 | if(err){ // file do not exists 18 | let source = fs.readFileSync('./template/404.tmpl'), 19 | template = handlebars.compile(source.toString()), 20 | data = { 21 | path: path.basename(url.parse(req.url).pathname) 22 | }; 23 | 24 | res.writeHead(404, { 25 | 'Content-Type': 'text/html' 26 | }); 27 | res.end(template(data)); 28 | }else{ 29 | if(stats.isDirectory()){ 30 | let source = fs.readFileSync('./template/directory.tmpl'), 31 | template = handlebars.compile(source.toString()), 32 | data = { 33 | title: url.parse(req.url).name, 34 | path: path.join(pathName, '/'), 35 | files: [] 36 | }; 37 | 38 | data.files = fs.readdirSync(realPath); 39 | 40 | res.writeHead(200, { 41 | 'Content-Type': 'text/html' 42 | }); 43 | res.end(template(data)); 44 | }else{ 45 | let extension = path.extname(pathName).replace('.', ''), 46 | fileType = mime[extension] || 'text/plain'; 47 | 48 | let acceptEncoding = req.headers['accept-encoding'] || '', 49 | compressable = extension.match(/css|js|html|json|xml|txt|md/ig); 50 | 51 | res.statusCode = 200; 52 | res.setHeader('Content-Type', fileType); 53 | 54 | if(compressable && acceptEncoding.match(/\bgzip\b/)){ 55 | res.setHeader('Content-Encoding', 'gzip'); 56 | fs.createReadStream(realPath).pipe(zlib.createGzip()).pipe(res); 57 | 58 | }else if(compressable && acceptEncoding.match(/\bdeflate\b/)){ 59 | res.setHeader('Content-Encoding', 'defalte'); 60 | fs.createReadStream(realPath).pipe(zlib.createDeflate()).pipe(res); 61 | 62 | }else{ 63 | fs.createReadStream(realPath).pipe(res); 64 | } 65 | 66 | } 67 | } 68 | }); 69 | }); 70 | 71 | server.listen(process.argv[2] || 9000); 72 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/10_chche.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | const path = require('path'); 7 | const mime = require('../ss/mime.json'); 8 | const handlebars = require('handlebars'); 9 | const zlib = require("zlib"); 10 | const public_folder = path.join(__dirname, 'node_modules'); 11 | 12 | let server = http.createServer(function(req, res){ 13 | let pathName = url.parse(req.url).pathname, 14 | realPath = path.join(public_folder, path.normalize(pathName.replace(/\.\./g, ''))); 15 | 16 | fs.stat(realPath, (err, stats) => { 17 | if(err){ // file do not exists 18 | let source = fs.readFileSync('./template/404.tmpl'), 19 | template = handlebars.compile(source.toString()), 20 | data = { 21 | path: path.basename(url.parse(req.url).pathname) 22 | }; 23 | 24 | res.writeHead(404, { 25 | 'Content-Type': 'text/html' 26 | }); 27 | res.end(template(data)); 28 | }else{ 29 | if(stats.isDirectory()){ 30 | let source = fs.readFileSync('./template/directory.tmpl'), 31 | template = handlebars.compile(source.toString()), 32 | data = { 33 | title: url.parse(req.url).name, 34 | path: path.join(pathName, '/'), 35 | files: [] 36 | }; 37 | 38 | data.files = fs.readdirSync(realPath); 39 | 40 | res.writeHead(200, { 41 | 'Content-Type': 'text/html' 42 | }); 43 | res.end(template(data)); 44 | }else{ 45 | let extension = path.extname(pathName).replace('.', ''), 46 | fileType = mime[extension] || 'text/plain'; 47 | 48 | let acceptEncoding = req.headers['accept-encoding'] || '', 49 | compressable = extension.match(/css|js|html|json|xml|txt|md/ig), 50 | cacheable = extension.match(/^(gif|png|jpg|css|js)$/ig); 51 | 52 | res.statusCode = 200; 53 | res.setHeader('Content-Type', fileType); 54 | res.setHeader("Date", (new Date()).toUTCString()); 55 | 56 | if(cacheable){ 57 | let expires = new Date(); 58 | expires.setTime(expires.getTime() + 60 * 60 * 24 * 365 * 1000); //一年后失效 59 | res.setHeader("Expires", expires.toUTCString()); 60 | res.setHeader("Cache-Control", "max-age=" + 60 * 60 * 24 * 365 * 1000); 61 | 62 | let lastModified = stats.mtime.toUTCString(); 63 | res.setHeader("Last-Modified", lastModified); 64 | 65 | let isExsits = req.headers['if-modified-since'], 66 | isEqual = lastModified === req.headers['if-modified-since']; 67 | 68 | if(isExsits && isEqual){ 69 | res.statusCode = 304; 70 | res.end(); 71 | } 72 | } 73 | 74 | if(compressable && acceptEncoding.match(/\bgzip\b/)){ 75 | res.setHeader('Content-Encoding', 'gzip'); 76 | fs.createReadStream(realPath).pipe(zlib.createGzip()).pipe(res); 77 | 78 | }else if(compressable && acceptEncoding.match(/\bdeflate\b/)){ 79 | res.setHeader('Content-Encoding', 'defalte'); 80 | fs.createReadStream(realPath).pipe(zlib.createDeflate()).pipe(res); 81 | 82 | }else{ 83 | fs.createReadStream(realPath).pipe(res); 84 | } 85 | 86 | } 87 | } 88 | }); 89 | }); 90 | 91 | server.listen(process.argv[2] || 9000); 92 | 93 | // curl --header "If-Modified-Since: Tue, 09 Jun 2015 03:32:13 GMT" -i http://localhost:9000/etag/index.js 94 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/11_argv2.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const os = require('os'); 4 | const http = require('http'); 5 | const exec = require('child_process').exec; 6 | const spawn = require('child_process').spawn; 7 | 8 | let argv = require("minimist")(process.argv.slice(2), { 9 | "alias": { 10 | "silent": "s", 11 | "port": "p", 12 | "hostname": "h", 13 | "dir": "d" 14 | }, 15 | "string": ["port", "hostname"], 16 | "boolean": "silent", 17 | "default": { 18 | "port": 9527, 19 | "dir": process.cwd() 20 | } 21 | }); 22 | 23 | if (argv.help) { 24 | console.log("Usage:"); 25 | console.log(" ss --help // print help information"); 26 | console.log(" ss // 9527 as default port, current folder as root"); 27 | console.log(" ss 8888 // 8888 as port"); 28 | console.log(" ss -p 8989 // 8989 as port"); 29 | console.log(" ss -s // don't open browser"); 30 | console.log(" ss -h localhost // localhost as hostname"); 31 | console.log(" ss -d /home // /home as root"); 32 | process.exit(0); 33 | } 34 | 35 | let openURL = url => { 36 | switch (process.platform) { 37 | case 'darwin': 38 | exec('open ' + url); 39 | break; 40 | case 'win32': 41 | exec('start ' + url); 42 | break; 43 | default: 44 | spawn('xdg-open', [url]); 45 | } 46 | }; 47 | 48 | let getIPAddress = () => { 49 | let ifaces = os.networkInterfaces(); 50 | let ip = ''; 51 | for (let dev in ifaces) { 52 | ifaces[dev].forEach(details => { 53 | if (ip === '' && details.family === 'IPv4' && !details.internal) { 54 | ip = details.address; 55 | return; 56 | } 57 | }); 58 | } 59 | return ip || '127.0.0.1'; 60 | }; 61 | 62 | let port = argv._[0] || argv.port; 63 | let hostname = argv.hostname || getIPAddress(); 64 | 65 | let server = http.createServer((req, res) => { 66 | res.end('test argv'); 67 | }); 68 | 69 | server.listen(port, () => { 70 | port = (port != '80' ? ':' + port : ''); 71 | var url = "http://" + hostname + port + '/'; 72 | console.log("Running at " + url); 73 | if (!argv.silent) { 74 | openURL(url); 75 | } 76 | }); 77 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http_server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "01_base_http.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "publishConfig": { 12 | "registry": "http://registry.npm.alibaba-inc.com" 13 | }, 14 | "dependencies": { 15 | "anywhere": "~1.2.0", 16 | "etag": "~1.7.0", 17 | "express": "~4.13.4", 18 | "handlebars": "~4.0.5", 19 | "minimist": "~1.2.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/template/404.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 6 | 17 | 18 | 19 | file {{path}} do not exists; 20 | 21 | 22 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/template/directory.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{title}} 6 | 17 | 18 | 19 | {{#each files}} 20 | {{this}} 21 | {{/each}} 22 | 23 | 24 | -------------------------------------------------------------------------------- /07 HTTP Server/demo/template/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/07 HTTP Server/demo/template/logo.png -------------------------------------------------------------------------------- /07 HTTP Server/exp/01_start.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const express = require('express'); 3 | 4 | let app = express(); 5 | 6 | app.get('/', (req, res) => { 7 | res.send('Hello world!'); 8 | }); 9 | 10 | app.listen(3000, () => { 11 | console.log('Example app listening on port 3000!'); 12 | }); 13 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/02_routing1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | let app = express(); 6 | 7 | app.get('/', (req, res) => { 8 | res.send('Hello World!'); 9 | }); 10 | 11 | // error: post vs put => update vs add 12 | // error: post vs put => add vs update 13 | 14 | app.post('/', (req, res) => { 15 | res.send('Got a POST request'); 16 | }); 17 | 18 | app.put('/user', (req, res) => { 19 | res.send('Got a PUT request at /user'); 20 | }); 21 | 22 | app.delete('/user', (req, res) => { 23 | res.send('Got a DELETE request at /user'); 24 | }); 25 | 26 | app.listen(3000, () => { 27 | console.log('Example app listening on port 3000!'); 28 | }); 29 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/03_static.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | let app = express(); 6 | 7 | app.use(express.static('public')); 8 | app.use(express.static('files')); 9 | 10 | app.listen(3000, () => { 11 | console.log('Example app listening on port 3000!'); 12 | }); 13 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/04_static2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | let app = express(); 6 | 7 | app.use('/static', express.static('public')); 8 | 9 | app.listen(3000, () => { 10 | console.log('Example app listening on port 3000!'); 11 | }); 12 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/05_routing2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | let app = express(); 6 | 7 | // GET method route 8 | app.get('/', function (req, res) { 9 | res.send('GET request to the homepage'); 10 | }); 11 | 12 | // POST method route 13 | app.post('/', function (req, res) { 14 | res.send('POST request to the homepage'); 15 | }); 16 | 17 | app.all('/secret', function (req, res, next) { 18 | console.log('Accessing the secret section ...'); 19 | next(); // pass control to the next handler 20 | }); 21 | 22 | app.get('/ab?cd', function(req, res) { 23 | res.send('ab?cd'); 24 | }); 25 | 26 | app.get('/ab+cd', function(req, res) { 27 | res.send('ab+cd'); 28 | }); 29 | 30 | app.get('/ab*cd', function(req, res) { 31 | res.send('ab*cd'); 32 | }); 33 | 34 | app.get('/ab(cd)?e', function(req, res) { 35 | res.send('ab(cd)?e'); 36 | }); 37 | 38 | app.get(/xx/, function(req, res) { 39 | res.send('/xx/'); 40 | }); 41 | 42 | app.get('/example/b', function (req, res, next) { 43 | console.log('the response will be sent by the next function ...'); 44 | next(); 45 | }, function (req, res) { 46 | res.send('Hello from B!'); 47 | }); 48 | 49 | 50 | var cb0 = function (req, res, next) { 51 | console.log('CB0'); 52 | next(); 53 | } 54 | 55 | var cb1 = function (req, res, next) { 56 | console.log('CB1'); 57 | next(); 58 | } 59 | 60 | var cb2 = function (req, res) { 61 | res.send('Hello from C!'); 62 | } 63 | 64 | app.get('/example/c', [cb0, cb1, cb2]); 65 | 66 | 67 | app.get('/example/d', [cb0, cb1], function (req, res, next) { 68 | console.log('the response will be sent by the next function ...'); 69 | next(); 70 | }, function (req, res) { 71 | res.send('Hello from D!'); 72 | }); 73 | 74 | app.listen(3000, () => { 75 | console.log('Example app listening on port 3000!'); 76 | }); 77 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/06_sendFile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | let app = express(); 6 | 7 | app.get('/file/:name', (req, res, next) => { 8 | let options = { 9 | root: __dirname + '/files/', 10 | dotfiles: 'deny', 11 | headers: { 12 | 'x-timestamp': Date.now(), 13 | 'x-sent': true 14 | } 15 | }; 16 | 17 | let fileName = req.params.name; 18 | 19 | res.sendFile(fileName, options, (err) => { 20 | if(err){ 21 | console.log(err); 22 | res.sendStatus(err.status).end(); 23 | }else{ 24 | console.log('sent', fileName); 25 | } 26 | }); 27 | }); 28 | 29 | app.listen(3000, () => { 30 | console.log('Example app listening on port 3000!'); 31 | }); 32 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/07_route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | let app = express(); 6 | 7 | app.route('/book') 8 | .get((req, res) => { 9 | res.send('Get a random book'); 10 | }) 11 | .post((req, res) => { 12 | res.send('Add a book'); 13 | }) 14 | .put((req, res) => { 15 | res.send('Update the book'); 16 | }); 17 | 18 | app.listen(3000, () => { 19 | console.log('Example app listening on port 3000!'); 20 | }); 21 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/08_router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | let router = express.Router(); 6 | 7 | router.use(function timeLog(req, res, next) { 8 | console.log('Time: ', Date.now()); 9 | next(); 10 | }); 11 | 12 | router.get('/', function(req, res) { 13 | res.send('Birds home page'); 14 | }); 15 | 16 | router.get('/about', function(req, res) { 17 | res.send('About birds'); 18 | }); 19 | 20 | let app = express(), 21 | router2 = require('./userRouter.js'); 22 | 23 | app.use('/birds', router); 24 | app.use('/user', router2); 25 | 26 | app.listen(3000, () => { 27 | console.log('Example app listening on port 3000!'); 28 | }); 29 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/files/1.js: -------------------------------------------------------------------------------- 1 | // files 2 | 3 | alert(2); 4 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exp", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "~4.13.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/public/1.js: -------------------------------------------------------------------------------- 1 | //public 2 | 3 | alert(1); 4 | -------------------------------------------------------------------------------- /07 HTTP Server/exp/userRouter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const express = require('express'); 3 | let router2 = express.Router(); 4 | 5 | router2.use(function timeLog(req, res, next) { 6 | console.log('Time: ', Date.now()); 7 | next(); 8 | }); 9 | 10 | router2.get('/', function(req, res) { 11 | res.send('user home page'); 12 | }); 13 | 14 | router2.get('/about', function(req, res) { 15 | res.send('About user'); 16 | }); 17 | 18 | module.exports = router2; 19 | -------------------------------------------------------------------------------- /07 HTTP Server/http2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/07 HTTP Server/http2.gif -------------------------------------------------------------------------------- /07 HTTP Server/https.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/07 HTTP Server/https.jpg -------------------------------------------------------------------------------- /07 HTTP Server/midleware.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/07 HTTP Server/midleware.gif -------------------------------------------------------------------------------- /07 HTTP Server/ss/conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ss", 3 | "version": "0.0.1", 4 | "env": "development", 5 | "port": 8888, 6 | "compress": ["css", "js", "html", "txt", "md", "json"], 7 | "cache": ["js", "css", "gif", "png", "jpg", "webp"] 8 | } -------------------------------------------------------------------------------- /07 HTTP Server/ss/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http = require('http'); 4 | const connect = require('connect'); 5 | const conf = require('conf.json'); 6 | 7 | var app = connect(); 8 | 9 | // app.use(); 10 | 11 | let port = process.argv[2] || conf.port; 12 | 13 | http.createServer(app).listen(port); -------------------------------------------------------------------------------- /07 HTTP Server/ss/mime.json: -------------------------------------------------------------------------------- 1 | { 2 | "css": "text/css", 3 | "gif": "image/gif", 4 | "html": "text/html", 5 | "ico": "image/x-icon", 6 | "jpeg": "image/jpeg", 7 | "jpg": "image/jpeg", 8 | "js": "text/javascript", 9 | "json": "application/json", 10 | "pdf": "application/pdf", 11 | "png": "image/png", 12 | "svg": "image/svg+xml", 13 | "swf": "application/x-shockwave-flash", 14 | "tiff": "image/tiff", 15 | "txt": "text/plain", 16 | "wav": "audio/x-wav", 17 | "wma": "audio/x-ms-wma", 18 | "wmv": "video/x-ms-wmv", 19 | "xml": "text/xml" 20 | } 21 | -------------------------------------------------------------------------------- /07 HTTP Server/缓存.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/07 HTTP Server/缓存.png -------------------------------------------------------------------------------- /08 Build/1_gulp/dest/css/index.min.css: -------------------------------------------------------------------------------- 1 | p{margin:0}img{max-width:200px}.button{width:200px} -------------------------------------------------------------------------------- /08 Build/1_gulp/dest/css/lib/main.css: -------------------------------------------------------------------------------- 1 | html{margin:0;padding:0}html section{color:#333} -------------------------------------------------------------------------------- /08 Build/1_gulp/dest/image/head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/08 Build/1_gulp/dest/image/head.jpg -------------------------------------------------------------------------------- /08 Build/1_gulp/dest/image/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/08 Build/1_gulp/dest/image/search.png -------------------------------------------------------------------------------- /08 Build/1_gulp/dest/index.html: -------------------------------------------------------------------------------- 1 | Document
Hello World!

Hello World!

-------------------------------------------------------------------------------- /08 Build/1_gulp/dest/js/index.min.js: -------------------------------------------------------------------------------- 1 | function index(){alert("index")}"use strict";function main(){alert("main")} -------------------------------------------------------------------------------- /08 Build/1_gulp/dest/js/lib/store.js: -------------------------------------------------------------------------------- 1 | "use strict";function store(){alert("store")} -------------------------------------------------------------------------------- /08 Build/1_gulp/fs_through2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const through = require('through2'); 5 | 6 | fs.createReadStream('./package.json') 7 | .pipe(through.obj((chunk, enc, done)=> { 8 | if (enc === 'buffer') { 9 | chunk = chunk.toString('utf-8'); 10 | enc = 'utf-8'; 11 | } 12 | done(null, chunk, enc); 13 | })) 14 | .pipe(through.obj((chunk, enc, done)=> { 15 | done(null, chunk.toUpperCase(), enc); 16 | })) 17 | .pipe(through.obj((chunk, enc, done)=> { 18 | chunk = chunk.split('').reverse().join(''); 19 | done(null, chunk, enc); 20 | })) 21 | .pipe(fs.createWriteStream('./out.txt')); -------------------------------------------------------------------------------- /08 Build/1_gulp/gulp1.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const gulp = require('gulp'); 3 | 4 | gulp.task('sync', ()=> { 5 | console.log('sync'); 6 | }); 7 | 8 | gulp.task('async', (done)=> { 9 | setTimeout(()=> { 10 | console.log('async'); 11 | done(); 12 | }, 500); 13 | }); 14 | 15 | gulp.task('default', ()=> { 16 | console.log('default'); 17 | }); -------------------------------------------------------------------------------- /08 Build/1_gulp/gulp2.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const gulp = require('gulp'); 3 | 4 | gulp.task('sync1', ()=> { 5 | console.log('我是第一个同步任务'); 6 | }); 7 | 8 | gulp.task('sync2', ()=> { 9 | console.log('我是第二个同步任务'); 10 | }); 11 | 12 | gulp.task('sync3', ()=> { 13 | console.log('我是第三个同步任务'); 14 | }); 15 | 16 | gulp.task('async', (done)=> { 17 | console.log('老大喊我去搬砖'); 18 | setTimeout(()=> { 19 | console.log('我是一个异步任务'); 20 | done(); 21 | }, 500); 22 | }); 23 | 24 | gulp.task('default', ['async', 'sync1', 'sync2', 'sync3'], ()=> { 25 | console.log('砖搬完了!'); 26 | }); -------------------------------------------------------------------------------- /08 Build/1_gulp/gulp3.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const gulp = require('gulp'); 4 | 5 | gulp.task('src-dist', ()=> { 6 | gulp.src('./*.js') 7 | .pipe(gulp.dest('./js')); 8 | }); 9 | 10 | gulp.task('default', ['src-dist']); -------------------------------------------------------------------------------- /08 Build/1_gulp/gulp4.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const gulp = require('gulp'); 4 | const concat = require('gulp-concat'); 5 | const through = require('through2'); 6 | 7 | gulp.task('src-dist', ()=> { 8 | gulp.src('./**/*.md') 9 | .pipe(gulp.dest('./md')); 10 | }); 11 | 12 | gulp.task('concat', ()=> { 13 | gulp.src('./**/package.json') 14 | .pipe(concat('all.txt')) 15 | .pipe(gulp.dest('./')); 16 | }); 17 | -------------------------------------------------------------------------------- /08 Build/1_gulp/gulp5.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const gulp = require('gulp'); 4 | const through = require('through2'); 5 | const HTMLMinifier = require('html-minifier').minify; 6 | 7 | gulp.task('default', ()=> { 8 | gulp.src('src/index.html') 9 | .pipe(through.obj((file, enc, done)=> { 10 | 11 | let contents = file.contents.toString(enc); 12 | 13 | let minified = HTMLMinifier(contents, { 14 | minifyCSS: true, 15 | minifyJS: true, 16 | collapseWhitespace: true, 17 | removeAttributeQuotes: false 18 | }); 19 | 20 | file.contents = new Buffer(minified, enc); 21 | done(null, file, enc); 22 | })) 23 | .pipe(gulp.dest('dest')); 24 | }); 25 | -------------------------------------------------------------------------------- /08 Build/1_gulp/gulp6.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const gulp = require('gulp'); 3 | const throuth = require('through2'); 4 | const fs = require('fs'); 5 | const CleanCSS = require('clean-css'); 6 | const UglifyJS = require('uglify-js'); 7 | const less = require('gulp-less'); 8 | const cheerio = require('cheerio'); 9 | const HTMLMinifier = require('html-minifier').minify; 10 | const path = require('path'); 11 | 12 | function minifyAndComboCSS(name, enc, files) { 13 | 14 | let content = ''; 15 | 16 | files.forEach(css=> { 17 | let contents = fs.readFileSync(css, enc), 18 | minified = new CleanCSS().minify(contents).styles; 19 | content += minified; 20 | }); 21 | 22 | if (content) { 23 | let combo = 'src/css/' + name; 24 | fs.writeFileSync(combo, content); 25 | gulp.src(combo) 26 | .pipe(gulp.dest('dest/css')); 27 | } 28 | 29 | } 30 | 31 | function minifyAndComboJS(name, enc, files) { 32 | 33 | let content = ''; 34 | 35 | files.forEach(js=> { 36 | let minified = UglifyJS.minify(js).code; 37 | content += minified; 38 | }); 39 | 40 | if (content) { 41 | let combo = 'src/js/' + name; 42 | fs.writeFileSync(combo, content); 43 | gulp.src(combo) 44 | .pipe(gulp.dest('dest/js')); 45 | } 46 | 47 | } 48 | 49 | gulp.task('build-js-lib', ()=> { 50 | return gulp.src('src/js/lib/**/*.js') 51 | .pipe(throuth.obj((file, enc, done)=> { 52 | let contents = file.contents.toString(enc), 53 | minified = UglifyJS.minify(contents, { 54 | fromString: true 55 | }).code; 56 | 57 | file.contents = new Buffer(minified, enc); 58 | done(null, file, enc); 59 | })) 60 | .pipe(gulp.dest('dest/js/lib')); 61 | }); 62 | 63 | gulp.task('less', ()=> { 64 | return gulp.src('src/less/**/*.less') 65 | .pipe(less()) 66 | .pipe(gulp.dest('src/css')); 67 | }); 68 | 69 | gulp.task('build-css-lib', ['less'], ()=> { 70 | return gulp.src('src/css/lib/**/*.css') 71 | .pipe(throuth.obj((file, enc, done)=> { 72 | let contents = file.contents.toString(enc), 73 | minified = new CleanCSS().minify(contents).styles; 74 | 75 | file.contents = new Buffer(minified, enc); 76 | done(null, file, enc); 77 | })) 78 | .pipe(gulp.dest('dest/css/lib')); 79 | }); 80 | 81 | gulp.task('image', ()=> { 82 | gulp.src('src/image/**/*') 83 | .pipe(gulp.dest('dest/image')); 84 | }); 85 | 86 | gulp.task('default', ['build-js-lib', 'build-css-lib', 'image'], ()=> { 87 | gulp.src('src/index.html') 88 | .pipe(throuth.obj((file, enc, done)=> { 89 | let contents = file.contents.toString(enc), 90 | $ = cheerio.load(contents, {decodeEntities: false}); 91 | 92 | let links = $('link'), 93 | cssToCombo = []; 94 | 95 | for (let i = 0, len = links.length; i < len; i++) { 96 | let link = $(links[i]); 97 | 98 | if (link.attr('rel') === 'stylesheet') { 99 | let href = link.attr('href'); 100 | if (/css\/(?!lib)/.test(href)) { 101 | cssToCombo.push('src/' + href); 102 | if (cssToCombo.length === 1) { 103 | link.attr('href', 'css/index.min.css'); 104 | } else { 105 | link.remove(); 106 | } 107 | } 108 | } 109 | } 110 | minifyAndComboCSS('index.min.css', enc, cssToCombo); 111 | //////////////////////////////////////////////////// 112 | 113 | let scripts = $('script'), 114 | jsToCombo = []; 115 | 116 | for (let i = 0, len = scripts.length; i < len; i++) { 117 | let script = $(scripts[i]); 118 | 119 | if (script.attr('type') == null || script.attr('type') === 'text/javascript') { 120 | let src = script.attr('src'); 121 | if (src) { 122 | if (/js\/(?!lib)/.test(src)) { 123 | jsToCombo.push('src/' + src); 124 | if (jsToCombo.length == 1) { 125 | script.attr('src', 'js/index.min.js'); 126 | } else { 127 | script.remove(); 128 | } 129 | } 130 | } 131 | } 132 | } 133 | minifyAndComboJS('index.min.js', enc, jsToCombo); 134 | //////////////////////////////////////////////////// 135 | 136 | let imgs = $('img'); 137 | for (let i = 0, len = imgs.length; i < len; i++) { 138 | let img = $(imgs[i]), 139 | src = 'src/' + img.attr('src'); 140 | if(/image\//.test(src)){ 141 | let stat = fs.statSync(src), 142 | ext = path.parse(src).ext; 143 | 144 | if(stat.size < 1024 * 5){ 145 | let head = ext === '.png'? 146 | 'data:image/png;base64' : 'data:image/jpeg;base64'; 147 | let dataurl = fs.readFileSync(src).toString('base64'); 148 | 149 | img.attr('src', head + ',' + dataurl); 150 | } 151 | } 152 | 153 | } 154 | //////////////////////////////////////////////////// 155 | 156 | contents = $.html(); 157 | 158 | let minified = HTMLMinifier(contents, { 159 | minifyCSS: true, 160 | minifyJS: true, 161 | collapseWhitespace: true, 162 | removeAttributeQuotes: false 163 | }); 164 | 165 | file.contents = new Buffer(minified, enc); 166 | 167 | //file.contents = new Buffer(contents, enc); 168 | 169 | done(null, file, enc); 170 | })) 171 | .pipe(gulp.dest('dest')); 172 | }); -------------------------------------------------------------------------------- /08 Build/1_gulp/gulpfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | require('./gulp6'); -------------------------------------------------------------------------------- /08 Build/1_gulp/out.txt: -------------------------------------------------------------------------------- 1 | 2 | } 3 | } 4 | "2.6.2~" :"SJ-YFILGU" 5 | ,"1.0.2~" :"2HGUORHT" 6 | ,"0.5.1~" :"REIFINIM-LMTH" 7 | ,"5.0.3~" :"SSEL-PLUG" 8 | ,"1.9.3~" :"PLUG" 9 | ,"21.4.3~" :"SSC-NAELC" 10 | ,"0.02.0~" :"OIREEHC" 11 | { :"SEICNEDNEPED" 12 | ,"TIM" :"ESNECIL" 13 | ,"MOC.LIAMG@GNOYULNUS" :"ROHTUA" 14 | ,] 15 | "PLUG" 16 | [ :"SDROWYEK" 17 | ,} 18 | "PLUG" :"TSET" 19 | { :"STPIRCS" 20 | ,"SJ.ELIFPLUG" :"NIAM" 21 | ,"OMED PLUG" :"NOITPIRCSED" 22 | ,"0.0.1" :"NOISREV" 23 | ,"PLUG_1" :"EMAN" 24 | { -------------------------------------------------------------------------------- /08 Build/1_gulp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "1_gulp", 3 | "version": "1.0.0", 4 | "description": "gulp demo", 5 | "main": "gulpfile.js", 6 | "scripts": { 7 | "test": "gulp" 8 | }, 9 | "keywords": [ 10 | "gulp" 11 | ], 12 | "author": "sunluyong@gmail.com", 13 | "license": "MIT", 14 | "dependencies": { 15 | "cheerio": "~0.20.0", 16 | "clean-css": "~3.4.12", 17 | "gulp": "~3.9.1", 18 | "gulp-concat": "^2.6.0", 19 | "gulp-less": "~3.0.5", 20 | "html-minifier": "~1.5.0", 21 | "through2": "~2.0.1", 22 | "uglify-js": "~2.6.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /08 Build/1_gulp/src/css/button.css: -------------------------------------------------------------------------------- 1 | .button{ 2 | width: 200px; 3 | } -------------------------------------------------------------------------------- /08 Build/1_gulp/src/css/index.css: -------------------------------------------------------------------------------- 1 | p{ 2 | margin: 0; 3 | } 4 | 5 | img{ 6 | max-width: 200px; 7 | } -------------------------------------------------------------------------------- /08 Build/1_gulp/src/css/index.min.css: -------------------------------------------------------------------------------- 1 | p{margin:0}img{max-width:200px}.button{width:200px} -------------------------------------------------------------------------------- /08 Build/1_gulp/src/css/lib/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | html section { 6 | color: #333; 7 | } 8 | -------------------------------------------------------------------------------- /08 Build/1_gulp/src/image/head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/08 Build/1_gulp/src/image/head.jpg -------------------------------------------------------------------------------- /08 Build/1_gulp/src/image/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunluyong/lesson/6f1b53d8f1452acd3e717e171fc63854b1e59ca9/08 Build/1_gulp/src/image/search.png -------------------------------------------------------------------------------- /08 Build/1_gulp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 23 | 24 | 25 | 26 |
27 | Hello World! 28 |
29 | 30 |

31 | Hello World! 32 |

33 | 34 | 35 | 36 | 37 | 38 | 39 | 46 | 47 | -------------------------------------------------------------------------------- /08 Build/1_gulp/src/js/index.js: -------------------------------------------------------------------------------- 1 | function index() { 2 | alert('index'); 3 | } -------------------------------------------------------------------------------- /08 Build/1_gulp/src/js/index.min.js: -------------------------------------------------------------------------------- 1 | function index(){alert("index")}"use strict";function main(){alert("main")} -------------------------------------------------------------------------------- /08 Build/1_gulp/src/js/lib/store.js: -------------------------------------------------------------------------------- 1 | // store.js 2 | "use strict"; 3 | 4 | function store(){ 5 | alert('store'); 6 | } -------------------------------------------------------------------------------- /08 Build/1_gulp/src/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function main(){ 4 | alert('main'); 5 | } -------------------------------------------------------------------------------- /08 Build/1_gulp/src/less/lib/main.less: -------------------------------------------------------------------------------- 1 | @fc: #333; 2 | 3 | html{ 4 | margin: 0; 5 | padding: 0; 6 | 7 | section{ 8 | color: @fc; 9 | } 10 | } -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/bin/app: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | console.log('start'); -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/bin/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | console.log('build'); -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/bin/pre: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | console.log('pre start'); -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/dist/css/test.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 12px; } 3 | html section { 4 | color: red; 5 | box-shadow: 3px 3px 3px #0000ed; 6 | -webkit-transition: width 2s; 7 | transition: width 2s; } 8 | 9 | @-webkit-keyframes myfirst { 10 | from { 11 | background: red; } 12 | to { 13 | background: yellow; } } 14 | 15 | @keyframes myfirst { 16 | from { 17 | background: red; } 18 | to { 19 | background: yellow; } } 20 | -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "2_npm_scripts", 3 | "version": "1.0.0", 4 | "description": "npm scripts demo", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "", 8 | "preinstall": "echo install...", 9 | "scss": "node-sass --output-style cpmpressed -o dist/css src/scss", 10 | "prefix": "postcss -u autoprefixer --autoprefixer.browser '> 5%, ie 9' -r dist/css/*", 11 | "lint": "jslint --edition=latest src/js/*.js", 12 | "build": "bin/build", 13 | "prestart": "bin/pre", 14 | "start": "bin/app" 15 | }, 16 | "author": "sunluyong@gmail.com", 17 | "license": "MIT", 18 | "devDependencies": { 19 | "autoprefixer": "~6.3.6", 20 | "jslint": "~0.9.6", 21 | "node-sass": "~3.4.2", 22 | "postcss-cli": "~2.5.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/src/js/test.js: -------------------------------------------------------------------------------- 1 | function test(){ 2 | var a = 2 3 | 4 | for (i = 0; i < 2; i++) { 5 | console.log(i); 6 | } 7 | } -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/src/js/test2.js: -------------------------------------------------------------------------------- 1 | function print() { 2 | console.log(1); 3 | } -------------------------------------------------------------------------------- /08 Build/2_npm_scripts/src/scss/test.scss: -------------------------------------------------------------------------------- 1 | $size: 12px; 2 | $color: red; 3 | 4 | html{ 5 | font-size: $size; 6 | 7 | section{ 8 | color: $color; 9 | box-shadow: 3px 3px 3px #0000ed; 10 | transition: width 2s; 11 | } 12 | } 13 | 14 | @keyframes myfirst { 15 | from {background: red;} 16 | to {background: yellow;} 17 | } 18 | 19 | -------------------------------------------------------------------------------- /08 Build/3_webpack/01/bundle.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports) { 46 | 47 | document.write("It works."); 48 | 49 | 50 | /***/ } 51 | /******/ ]); -------------------------------------------------------------------------------- /08 Build/3_webpack/01/entry.js: -------------------------------------------------------------------------------- 1 | document.write("It works."); 2 | -------------------------------------------------------------------------------- /08 Build/3_webpack/01/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /08 Build/3_webpack/02/bundle.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports, __webpack_require__) { 46 | 47 | "use strict"; 48 | 49 | let text = __webpack_require__(1); 50 | document.write(text); 51 | 52 | /***/ }, 53 | /* 1 */ 54 | /***/ function(module, exports) { 55 | 56 | module.exports = "It works from content.js."; 57 | 58 | 59 | /***/ } 60 | /******/ ]); -------------------------------------------------------------------------------- /08 Build/3_webpack/02/content.js: -------------------------------------------------------------------------------- 1 | module.exports = "It works from content.js."; 2 | -------------------------------------------------------------------------------- /08 Build/3_webpack/02/entry.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let text = require("./content.js"); 4 | document.write(text); -------------------------------------------------------------------------------- /08 Build/3_webpack/02/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /08 Build/3_webpack/03/bundle.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports, __webpack_require__) { 46 | 47 | "use strict"; 48 | 49 | __webpack_require__(1); 50 | 51 | let text = __webpack_require__(5); 52 | document.write(text); 53 | 54 | /***/ }, 55 | /* 1 */ 56 | /***/ function(module, exports, __webpack_require__) { 57 | 58 | // style-loader: Adds some css to the DOM by adding a