學習資料:CommonJS規範 javascript
Node應用由模塊組成,採用的就是CommonJS規範css
規範指明,每一個文件就是一個模塊,有本身的做用域。在一個文件裏面,類、函數、方法都是私有的,其餘文件不可見html
// example.js var x = 5; var addX = function (value) { return value + x; };
上面代碼中x變量和addx方法,就是當前文件私有,其餘不可見。前端
CommonJS規定,每一個模塊內部,module 變量表明當前模塊。這個變量是一個對象,他的 exports 屬性是對外的接口。java
加載某個模塊,實際上是加載該模塊的 module.exports 屬性。node
var x = 5; var addX = function (value) { return value + x; }; module.exports.x = x; module.exports.addX = addX;
經過module.exports輸出變量x和函數addx。webpack
require 方法用於加載模塊git
var example = require('./example.js'); console.log(example.x); // 5 console.log(example.addX(1)); // 6
CommonJS模塊的特色以下:github
Node內部提供一個Module構造函數,全部模塊都是Module的實例。web
每一個內部都有一個 module 對象,表明當前模塊,幷包含如下屬性
module.id
模塊的識別符,一般是帶有絕對路徑的模塊文件名。module.filename
模塊的文件名,帶有絕對路徑。module.loaded
返回一個布爾值,表示模塊是否已經完成加載。module.parent
返回一個對象,表示調用該模塊的模塊。module.children
返回一個數組,表示該模塊要用到的其餘模塊。module.exports
表示模塊對外輸出的值。console.log(module) 會輸出當前module對象的全部信息。使用module.parent,能夠判斷是不是入口文件。
module.exports屬性表示當前模塊對外輸出的接口,其餘文件加載該模塊,實際上讀取module.exports變量。
爲了方便,NodeJS爲每一個模塊提供一個exports變量,指向module.exports。這等同在每一個模塊頭部,有這段命令
var exports = module.exports;
能夠直接給這個變量添加對象。但不能將這個變量直接賦值。
若是一個模塊的對外接口,就是一個單一的值,則不能使用exports變量。須要module.exports = function(){}
CommonJS規範是同步進行的,也就是說只有加載完成纔會執行後面的操做。
AMD規範是非同步加載模塊,容許指定回掉函數。。
NodeJS主要用於服務端編程,模塊文件通常都已經存在於本地硬盤,因此加載速度會比較快。
若是是瀏覽器環境,要從服務器加載模塊,就必須採用非同步模式,所以通常瀏覽器使用AMD模式。
CommonJS模塊規範,內置的require命令用於加載模塊
require命令會讀取並執行一個Javascript文件,而後返回該文件模塊的exports對象。若是沒有會報錯
require命令用於加載文件,後綴名默認爲*.js
var foo = require('foo'); // 等同於 var foo = require('foo.js');
根據參數不一樣,require命令會去不一樣路徑查找文件
一般咱們會把相關的文件放在一個目錄裏面,便於組織。
此時最好爲該目錄設置一個入口文件,讓require方法能夠經過這個入口文件,加載整個目錄
目錄中防止要給 package.json,可使用 npm init 直接建立一份package.json
{ "name": "Cxy", "version": "1.0.0", "description": "描述", "main": "index.js", //入口文件 "scripts": { "test": "null" }, "repository": { "type": "git", "url": "https://git.coding.net/chenxygx/CodeSave.git" }, "author": "", "license": "MIT" }
require發現參數字符串指向一個目錄後,就會自動查找該目錄的 package.json,而後加載main的入口文件
若是沒有,則默認加載index.js 或 index.node
第一次加載模塊,Node會緩存該模塊。之後再加載該模塊,就直接從緩存中取出該模塊的module.exports屬性
全部模塊都緩存在require.cache之中。若是想刪除模塊的緩存,能夠以下寫法
// 刪除指定模塊的緩存 delete require.cache[moduleName]; // 刪除全部模塊的緩存 Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; })
Node執行一個腳本會先查看環境變量Node_path。他是一組以冒號分隔的絕對路徑,在其餘位置找不到指定模塊時,Node會去此路徑查找
有兩種方式能夠解決
1.將文件添加到node_modules目錄
2.修改NODE_PATH環境變量,package.json採用以下寫法
{ "name": "node_path", "main": "index.js", "scripts": { "start": "NODE_PATH=lib node index.js" } }
NODE_PATH是歷史遺留的解決方案,儘可能不要採用此方法,採用node_modules會更好
require方法有一個main屬性,能夠用來判斷模塊是直接執行仍是被調用執行
直接執行的時候(node module.js) require.main屬性指向自己
require.main === module // true
CommonJS模塊的加載機制是,輸入的是被輸出的值的拷貝,也就是一旦輸出一個值,內部變化就不會影響
require命令是CommonJS規範中,用來加載其餘模塊的命令。他指向當前模塊的module.require命令,而後調用Node命令Module._load
Module._load 會執行下面操做
Module._load = function(request, parent, isMain) { // 1. 檢查 Module._cache,是否緩存之中有指定模塊 // 2. 若是緩存之中沒有,就建立一個新的Module實例 // 3. 將它保存到緩存 // 4. 使用 module.load() 加載指定的模塊文件, // 讀取文件內容以後,使用 module.compile() 執行文件代碼 // 5. 若是加載/解析過程報錯,就從緩存刪除該模塊 // 6. 返回該模塊的 module.exports }; //第四步module.compile Module.prototype._compile = function(content, filename) { // 1. 生成一個require函數,指向module.require // 2. 加載其餘輔助方法到require // 3. 將文件內容放到一個函數之中,該函數可調用 require // 4. 執行該函數 };
主要使用到的函數和輔助方法以下:
require()
: 加載外部模塊require.resolve()
:將模塊名解析到一個絕對路徑require.main
:指向主模塊require.cache
:指向全部緩存的模塊require.extensions
:根據文件的後綴名,調用不一樣的執行函數一旦requrire函數準備完畢,整個所要加載的腳本內容,就會被放到一個新的函數之中,就能夠避免全局污染
新的函數包含,require\module\exports,
Module._compile是同步的,Module._load要等它執行完成,纔會向用戶返回module.exports的值
學習資料:
webpack2官網 CoffeeScript ES2015 ES2015核心內容
Webpack是一個現代的Javascript應用程序的模塊打包器 (module bundler)。有很是高的可配置性。
Webpack是一個前端模塊管理器,會把一堆文件中的每一個做爲一個模塊,找出他們之間的依賴關係
並將它們捆綁到準備部署的靜態文件上。
舉一個簡單的例子,加入咱們有一堆CommonJS模塊,他們不能直接在瀏覽器中運行。
咱們須要將他們綁定到一個<script>標籤包含的文件裏。webpack能夠跟隨require() 調用的依賴關係,爲咱們作這些事
Webpack能作更多的事情,經過 "loaders" 咱們能讓Webpack按照咱們想要的方式打包輸出。例如:
webpack將建立全部應用程序的依賴關係圖表,圖表的起點稱之爲入口起點。入口起點告訴webpack從哪裏開始
並遵循着依賴關係表知道要打包什麼。能夠理解爲入口就是根上下文或者app第一個執行的文件。
在webpack中,咱們使用 entry 屬性來定義入口
module.exports = { entry: './path/to/my/entry/file.js' };
將全部的資源歸攏在一塊兒之後,還需告訴webpack打包在哪裏。webpack的output屬性描述瞭如何處理歸攏在一塊兒的代碼(bundled code)
上面例子中,咱們經過output.filename 和 output.path 屬性,來告訴webpack bundled的名稱,以及咱們想要生成的路徑
__dirname變量指向爲根目錄
const path = require('path'); module.exports = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' } };
webpack把每一個文件(css,html,scss,jpg,etc)都做爲模塊處理。
然而webpack只理解javascript。會把這些文件轉換爲模塊,而轉換後的文件會被添加到依賴圖表中
webpack的配置有兩個目標
1. 識別出identify 應該被對應的loader 進行轉換(transform)的那些文件
2. 因爲進行過文件轉換,因此可以將被轉換的文件添加到依賴圖表中
const path = require('path'); const config = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' }, module: { rules: [ {test: /\.(js|jsx)$/, use: 'babel-loader'} ] } }; module.exports = config;
以上配置中,對一個單獨的module 對象定義了 rules 屬性,裏面包含兩個必須屬性:test 和 use
當requrie() 或 import 語句中被解析爲 .js 或 .jsx的路徑時,在你把他們添加並打包以前,要先使用 babel-loader 去轉換
因爲loader 僅在每一個文件的基礎上執行轉換,而插件 最經常使用於在打包模塊的 compilation 和 chunk生命週期執行操做和自定義功能
webpack 的插件系統極其強大,而且可定製化強。
想要使用一個插件,只須要require(),而後放到plugins數組中。多數插件能夠經過選項option自定義。
也能夠在一個配置中,因不一樣的目的屢次使用同一個插件。只須要new一下便可
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm const webpack = require('webpack'); //to access built-in plugins const path = require('path'); const config = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' }, module: { rules: [ {test: /\.(js|jsx)$/, use: 'babel-loader'} ] }, plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
首先須要安裝,最新版NodeJS。
而後
$ npm install webpack -g
最後啓動打包
$ webpack // 最基本的啓動webpack方法 $ webpack -w // 提供watch方法,實時進行打包更新 $ webpack -p // 對打包後的文件進行壓縮,提供production $ webpack -d // 提供source map,方便調試。
學習資料:中文官網
每一個項目的根目錄下,通常都有一個package.json文件,定義了這個項目所須要的各類模塊,以及項目的配置信息(名稱、版本、許可等)
npm install 命令會根據這個配置文件,自動下載所需的模塊,也就是配置項目所需的運行和開發環境。
npm install -g cnpm --registry=https://registry.npm.taobao.org
使用cnpm能夠設置爲淘寶鏡像的npm,而後下載使用cnpm下載便可
package.json文件就是一個json對象,對象的每個成員就是當前項目的一項設置。能夠經過npm init來生成package.json
看一個完整的package.json,而後挨個解答一下對應的意思。
{ "name": "Hello World", "version": "0.0.1", "author": "張三", "contributors": "ai wo bie zou", "description": "第一個node.js程序", "Homepage": "www.baidu.com", "main": "index.js", "Files":"", "keywords": [ "node.js", "javascript" ], "repository": { "type": "git", "url": "https://path/to/url" }, "license": "MIT", "engines": { "node": "0.10.x" }, "bugs": { "url": "http://path/to/bug", "email": "bug@example.com" }, "contributors": [ { "name": "李四", "email": "lisi@example.com" } ], "bin": { "someTool": "./bin/someTool.js" }, "scripts": { "start": "node index.js && someTool build", "test": "tap test/*.js" }, "dependencies": { "express": "latest", "mongoose": "~3.8.3", "handlebars-runtime": "~1.0.12", "express3-handlebars": "~0.5.0", "MD5": "~1.2.0" }, "devDependencies": { "bower": "~1.2.8", "grunt": "~0.4.1", "grunt-contrib-concat": "~0.3.0", "grunt-contrib-jshint": "~0.7.2", "grunt-contrib-uglify": "~0.2.7", "grunt-contrib-clean": "~0.5.0", "browserify": "2.36.1", "grunt-browserify": "~1.3.0" }, "peerDependencies": { "chai": "1.x" } }
name:項目名稱,不能包含js、node字樣,不能以點或下劃線開頭
version:項目版本
author:做者
contributors:做者團隊
description:描述
keywords:關鍵字,會在搜索的時候使用
repository:指示代碼存放位置。
license:版權
Homepage:主頁,不用填寫協議
Files:項目包含的一組文件
engines:指定node版本
bugs:問題追蹤系統的URL或郵箱地址
scripts
指定運行腳本命令的npm命令和縮寫,好比start指定了運行npm run start時,所要執行的命令
上文中,指定了npm run start和npm run test,所要執行的命令。
dependencies
指定了項目運行時所依賴的模塊,該對象的各個成員,分別由模塊名和對應版本要求組成。
使用npm install能夠安裝全部模塊。
npm install --production只安裝dependencies
npm install express --save 將模塊寫入dependencies屬性
對應的版本限定,主要有如下幾種
1.2.2
,遵循「大版本.次要版本.小版本」的格式規定,安裝時只安裝指定版本。~1.2.2
,表示安裝1.2.x的最新版本(不低於1.2.2),可是不安裝1.3.x,也就是說安裝時不改變大版本號和次要版本號。devDependencies
指定了項目開發時所須要的模塊
npm install express --dev 將模塊寫入devDependencies屬性。
npm install express --save-dev 兩個都寫入
peerDependencies
供插件指定其所須要的主工具的版本。
上面代碼指,安裝Hello World須要主程序chai一塊兒安裝。並且版本必須是1.x。若是依賴是2.0就會報錯。
bin
用來指定各個內部命令對應的可執行文件的位置。
someTool命令對應的可執行文件爲bin子目錄下的someTool.js。
npm會尋找這個文件,在node_modules/.bin/目錄下創建符號連接。上面例子中
someTool.js會創建符號連接npm_module/.bin/someTool。
因爲node_modules/.bin/目錄會在運行時加入系統path變量,所以在運行Npm時,就能夠不帶路徑。
全部node_module/.bin/目錄下的命令,均可以用npm run [命令]的格式運行
main
指定加載的入口文件,require('moduleName')會加載這個文件。默認值是根目錄下的index.js
$