学习资料: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
$