• Posts tagged "npm"

Blog Archives

Angular2新的体验

AngularJS体验式编程系列文章,将介绍如何用angularjs构建一个强大的web前端系统。angularjs是由Google团队开发的一款非常优秀web前端框架。在当前如此多的web框架下,angularjs能脱颖而出,从架构设计上就高人一等,双向数据绑定,依赖注入,指令,MVC,模板。Angular.js创新地把后台技术融入前端开发,扫去jQuery一度的光芒。用angularjs就像写后台代码,更规范,更结构化,更可控。

从 Angular 2.x 开始新的体验。

关于作者

  • 张丹(Conan), 程序员R,Java,Nodejs
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/angular2-init/

前言

随着Angular2的升级,从1.x升级2.x,但我却迟迟没有动手。原因了2.x对1.x完全不兼容,而且从原生Javascript变成了Typescript,增加很多的生成模块,依赖的类库一下子变得很多。变化实在太大了,确实让人难以接受。我特别对于Typescript的不解,喜欢javascript的灵活,而静态化意味代码量的增加。

前几天,看到Angular2的release,想来想去还是要试试。从官方文档中,看到对中文支持的非常好,开发团队真是用心了。开发团队用心的改变,作为使用者来说是切身可以感受的,带着敬意和信心,决定把Angular2学起来。

目录

  1. Angular2介绍
  2. Anguar2的快速启动
  3. 从命令行构建Anguar2

1. Angular2介绍

Angular是由Google开发的一套前端应用开发框架,可以快速帮你构建复杂的大型前端单页应用(Single Page Application)。我非常喜欢Angular 1.x 给我带来的前端开发体验,当前花了2周时间时间学习,几百行代码就实现了,超乎想象的应用效果。我放下了所有原来对于前端Javascript的认知,直接转向了Angular。

官方网站:https://angular.cn/

Angular2的新特性包括:

  • 渐进式Web应用:借助现代化Web平台的力量,交付app式体验。高性能、离线化、零安装。
  • 原生:借助来自Ionic、NativeScript和React Native中的技术与思想,构建原生移动应用。
  • 桌面:借助你已经在Web开发中学过的能力,结合访问原生操作系统API的能力,创造能在桌面环境下安装的应用,横跨Mac、Windows和Linux平台。
  • 代码生成:Angular会把你的模板转换成代码,针对现代JavaScript虚拟机进行高度优化,轻松获得框架提供的高生产率,同时又能保留所有手写代码的优点。
  • 统一:在服务端渲染应用的首屏,像只有HTML和CSS的页面那样几乎瞬间展现,支持node.js、.NET、PHP,以及其它服务器,为通过SEO来优化站点铺平了道路。
  • 代码拆分:Angular应用通过新的组件路由(Component Router)模块实现快速加载,提供了自动拆分代码的功能,为用户单独加载它们请求的视图中需要的那部分代码。
  • 模板:通过简单而强大的模板语法,快速创建UI视图。
  • Angular命令行工具:命令行工具:快速进入构建环节、添加组件和测试,然后立即部署。
  • 各种IDE:在常用IDE和编辑器中获得智能代码补全、实时错误反馈及其它反馈等特性。
  • 测试:使用Karma进行单元测试,让你在每次存盘时都能立即知道是否弄坏了什么。Protractor则让你的场景测试运行得又快又稳定。
  • 动画:通过Angular中直观简便的API创建高性能复杂编排和动画时间线 —— 只要非常少的代码。
  • 可访问性:通过支持ARIA的组件、开发者指南和内置的一体化测试基础设施,创建具有完备可访问性的应用。

接下来,就让我们来体验Angular2的新颖之处的。

2. Anguar2的快速启动

阅读官方文档,我们可以跟着文档进行项目的快速启动,快速启动项目quickstart,是基于github,node,npm的,我们按照文档执行就可以了。关于Node的介绍,可以参考系列文章从零开始nodejs系列文章

系统环境:

  • Win10 64bit
  • node v6.9.4
  • npm 3.10.10
  • git version 2.7.0.windows.1

2.1 构建项目

进入开发目录,下载quickstart项目。


~ cd D:\\workspace\js
~ git clone https://github.com/angular/quickstart.git quickstart
~ cd quickstart
~ npm install   # 执行npm安装和配置
~ npm start     # 启动项目

通过npm start命令,就直接启动了angular2的程序,默认会自动打开浏览器,就可以看到效果了。如果浏览没有自动打开,自己手动在浏览器打开localhost:3000,也可以打开。

2.2 目录结构

接下来,我们查看项目目录结构。

由于这个quickstart的模板项目,包含了太多的文件。一下子看到这么多东西,肯定要晕一会的。图中用红色部分标记的几个文件,是我们应该要知道的,其他的文件对于首次执行来说并不是太重要。

文件说明

  • app/app.components.ts, 一个自定义组件,Typescript代码。
  • app/app.module.ts, 模块文件,用于组合管理组件,Typescript代码。
  • app/main.ts, 项目启动的入口,加载ts文件,Typescript代码。
  • app/app.components.spec.ts, 单测试文件
  • .gitignore, git的配置文件
  • index.html, 单页应用的html入口文件
  • package.json, Node项目的工程配置文件
  • tsconfig.json, Typescript语言的配置文件

2.3 4个核心文件

把几个核心的文件中的代码,进行解释。

app/app.components.ts文件


import { Component } from '@angular/core';        //引用系统类库

@Component({                                      //定义组件
  selector: 'my-app',                             //对应该index.html的<my-app>标签
  template: `<h1>Hello {{name}}</h1>`,            //替换<my-app>标签的内容
})
export class AppComponent  { name = 'Angular'; }  //输出自定义组件 

app/app.module.ts文件


import { NgModule }      from '@angular/core';                  //引用系统类库
import { BrowserModule } from '@angular/platform-browser';      //引用系统类库
import { AppComponent }  from './app.component';                //引用app.components.ts文件,定义的AppComponent组件
 
@NgModule({                                                     //定义模块
  imports:      [ BrowserModule ],                              //引用浏览器模块
  declarations: [ AppComponent ],                               //声明组件
  bootstrap:    [ AppComponent ]                                //启动组件
})
export class AppModule { }                                      //输出自定义模块 

app/main.ts文件


import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';  //引用系统类库

import { AppModule } from './app.module';                                    //引用app.module.ts文件的AppModule 

platformBrowserDynamic().bootstrapModule(AppModule);                         //启动程序,加载模块

index.html文件


<!DOCTYPE html>
<html>
  <head>
    <title>Angular QuickStart</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- Polyfill(s) for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>

    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>

  <body>
    <my-app>Loading AppComponent content here ...</my-app>
  </body>
</html>

index.html中$lt;my-app&gtl的标签,是会被app.components.ts文件定义的selector发现并处理。

这4个文件,其实就是程序源代码的核心文件。那么项目中的其他文件,都是各种工具的配置文件。比如,我要编译Typescript文件到Javascript文件,就是需要在tsconfig.json进行配置;对类库做动态加载就要用到systemjs;执行单元测试需要用到karma;上传到github需要用到.gitignore;对node项目的管理用package.json配置。

2.4 扩展工具

当然,还有一些扩展工具。

单独编译Typescrip到Javascript。


~ D:\workspace\js\quickstart>npm run tsc

单独编译Typescrip,并监控文件状态,发现文件变化重新变异。


~ D:\workspace\js\quickstart>npm run tsc:w

启动Server,在浏览器中查看效果。


~ D:\workspace\js\quickstart>npm run lite 

单元测试


~ D:\workspace\js\quickstart>npm test

E2E测试End-to-end


~ D:\workspace\js\quickstart>npm run e2e 

除了从github上面下载quickstart模板,还是另外一种初始构建项目的方式,就是用Anguar2的命令行工具。

3. 从命令行构建Anguar2

从上文的Angular2的特性中,就有一项是命令工具,用这种方式构建一个新项目,更符合开发人员“脚手架”的思路。首先,我们需要安装这个命令工具anguar-cli。请大家务必升级Nodejs到v6.x以上,我之前用v4.4,花了大量时间调试都没有通过。

3.1 安装anguar-cli


~ D:\workspace\js>npm install -g angular-cli

安装好后,我们可以通过help命令查看命令行有哪个功能。


D:\workspace\js>ng help
ember build 
  Builds your app and places it into the output path (dist/ by default).
  aliases: b
  --target (String) (Default: development)
    aliases: -t , -dev (--target=development), -prod (--target=production)
  --environment (String) (Default: )
    aliases: -e 
  --output-path (Path) (Default: null)
    aliases: -o 
  --watch (Boolean) (Default: false)
    aliases: -w
  --watcher (String)
  --suppress-sizes (Boolean) (Default: false)
  --base-href (String) (Default: null)
    aliases: -bh 
  --aot (Boolean) (Default: false)
  --sourcemap (Boolean) (Default: true)
    aliases: -sm
  --vendor-chunk (Boolean) (Default: true)
  --verbose (Boolean) (Default: false)
  --progress (Boolean) (Default: true)
  --i18n-file (String) (Default: null)
  --i18n-format (String) (Default: null)
  --locale (String) (Default: null)

  // 省略....

查看ng工具的版本


~ D:\workspace\js>ng version
                             _                           _  _
  __ _  _ __    __ _  _   _ | |  __ _  _ __         ___ | |(_)
 / _` || '_ \  / _` || | | || | / _` || '__|_____  / __|| || |
| (_| || | | || (_| || |_| || || (_| || |  |_____|| (__ | || |
 \__,_||_| |_| \__, | \__,_||_| \__,_||_|          \___||_||_|
               |___/

angular-cli: 1.0.0-beta.26
node: 6.9.4
os: win32 x64

当然,我们最需要的就是构建项目,启动服务,生成组件,指令,服务等功能。

3.2 新建项目

新建一个项目


~ D:\workspace\js>ng new conan1      // 新建项目
installing ng2
  create .editorconfig
  create README.md
  create src\app\app.component.css
  create src\app\app.component.html
  create src\app\app.component.spec.ts
  create src\app\app.component.ts
  create src\app\app.module.ts
  create src\assets\.gitkeep
  create src\environments\environment.prod.ts
  create src\environments\environment.ts
  create src\favicon.ico
  create src\index.html
  create src\main.ts
  create src\polyfills.ts
  create src\styles.css
  create src\test.ts
  create src\tsconfig.json
  create angular-cli.json
  create e2e\app.e2e-spec.ts
  create e2e\app.po.ts
  create e2e\tsconfig.json
  create .gitignore
  create karma.conf.js
  create package.json
  create protractor.conf.js
  create tslint.json
Successfully initialized git.
Installing packages for tooling via npm.
Installed packages for tooling via npm.
Project 'conan1' successfully created.

等了大概有10分钟,下载了有200mb的文件,希望大家有耐心。进入安装目录。


~ D:\workspace\js\conan1>cd conan1      // 进入项目目录
~ D:\workspace\js\conan1>ng serve       // 启动项目

打开浏览器,查看Web网页。

如果你想修改启动端口为4201,可以用下面的命令。


ng serve --host 0.0.0.0 --port 4201 --live-reload-port 49153

用命令工具构建的项目目录。

目录结构有一个变化,就是嵌套了一层src目录,然后才是app目录。另外,多了angular-cli.json的配置文件。

3.3 模块生成器

接下来,我们可以用命令工具,进行项目模块和组件的开发了。

命令使用说明
组件Componentng generate component my-new-component
指令Directiveng generate directive my-new-directive
服务Serviceng generate pipe my-new-service
管道Pipeng generate pipe my-new-pipe
类Classng generate class my-new-class
接口Interfaceng generate interface my-new-interface
枚举对象Enumng generate enum my-new-enum
模块Moduleng generate module my-module

3.4 生成一个新组件

用命令生成一个hello的新组件,文件生成如下。


~ D:\workspace\js\conan1>ng generate component hello
installing component
  create src\app\hello\hello.component.css
  create src\app\hello\hello.component.html
  create src\app\hello\hello.component.spec.ts
  create src\app\hello\hello.component.ts
  update src\app\app.module.ts

在app目录下生成了一个hello的子目录,包括了4个组件的文件,同时在app.module.ts模块文件中,注册了这个新组件。

我们要修改2个地方,让这个新生成的hello组件可以运行。

1. 修改index.html文件,增加<app-hello>标签。


<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Conan1</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
  
  <app-hello>Loading...</app-hello>
</body>
</html>

2. 修改app.module.ts文件,在@NgModule.bootstrap中,增加HelloComponent的启动项。


import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello/hello.component';

@NgModule({
  declarations: [
    AppComponent,
    HelloComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent,HelloComponent]
})
export class AppModule { }

查看浏览器,我们可以看到hello works!显示到界面上。

3.5 生成一个新指令

属性型指令用于改变一个 DOM 元素的外观或行为。用命令生成一个link的新指令,操作如下。


~ D:\workspace\js\conan1>ng generate directive link
installing directive
  create src\app\link.directive.spec.ts
  create src\app\link.directive.ts
  update src\app\app.module.ts

主要生成了新文件link.directive.ts。


import { Directive } from '@angular/core';
@Directive({
  selector: '[appLink]'
})
export class LinkDirective {
  constructor() { }
}

接下来,用appLink指令来做一个样式的修饰,需要修改2个文件。

1. 修改hello.component.html文件,增加一段span的HTML标签,并配置appLink属性。


<p>hello works!</p>

<span appLink>Directive me!</span>

2. 修改link.directive.ts文件,在LinkDirective类的构造器constructor函数中,增加样式的修改属性。同时,通过@HostListener,监听鼠标动作。


import { Directive, ElementRef, HostListener, Renderer } from '@angular/core';
@Directive({
  selector: '[appLink]'
})
export class LinkDirective {
    constructor(el: ElementRef, renderer: Renderer) {
       renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
    }

    @HostListener('mouseenter') onMouseEnter() {
      this.highlight('blue');
    }
    @HostListener('mouseleave') onMouseLeave() {
      this.highlight('yellow');
    }
    
    private highlight(color: string) {
      this.renderer.setElementStyle(this.el.nativeElement, 'backgroundColor', color);
    }
}

修改后,我们在浏览器中查看运行的效果。

3.6 生成一个新服务

服务,可以封装代码,比如我们可以对数据访问代码单独隔离,封装到一个独立的服务中。用命令生成一个meta的新服务,操作如下。


~ D:\workspace\js\conan1>ng generate service meta
installing service
  create src\app\meta.service.spec.ts
  create src\app\meta.service.ts
  WARNING Service is generated but not provided, it must be provided to be used

生成了2个service的文件,同时提供了Service必须被provided,才可以被应用。我们如果想要启用meta的这个服务,需要在3个文件中进行修改。

1. 修改meta.service.ts文件,增加getNames()函数,用于提供数据访问。


import { Injectable } from '@angular/core';
@Injectable()
export class MetaService {
  constructor() { }
  getNames():any[]{
    return [
        {id: 1, name: 'AAA'},
        {id: 2, name: 'BBB'},
        {id: 3, name: 'CCC'},
        {id: 4, name: 'DDD'}
      ];
  }
}

2. 修改hello.component.ts文件,把MetaService注入到HelloComponent中,通过providers进行依赖注入的体现,同时调用MetaService 类的getNames()函数获取数据。


import { Component, OnInit } from '@angular/core';
import { MetaService } from '../meta.service';
@Component({
  selector: 'app-hello',
  templateUrl: './hello.component.html',
  styleUrls: ['./hello.component.css'],
  providers: [MetaService]
})
export class HelloComponent implements OnInit {
  meta = [];
  constructor(private metaService: MetaService) { }
  ngOnInit() {
    this.meta = this.metaService.getNames();
  }
}

3. 修改hello.component.html文件,用于数据的html输出,以列表形式输出。


<p>hello works!</p>

<span appLink>Directive me!</span>

<ul>
  <li *ngFor="let m of meta">
    {{m.id}}, {{m.name}}
  </li>
</ul>

修改后,我们在浏览器中查看运行的效果。

3.7 生成一个新管道

管道,可以用于数据的连续处理操作,比如可以把日期在界面端进行格式化,把20170101格式转型2017-01-01格式。用命令生成一个datef的新管道,操作如下。


~ D:\workspace\js\conan1>ng generate pipe datef
installing pipe
  create src\app\datef.pipe.spec.ts
  create src\app\datef.pipe.ts
  update src\app\app.module.ts

生成了2个pipe的文件。如果我们想使用这个功能,需要在2个文件中进行修改。

1. 修改datef.pipe.ts文件,对日期进行格式化,把20161222转化为2016-12-22。


import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
  name: 'datef'
})
export class DatefPipe implements PipeTransform {
  transform(value: string) {
    var dat1 = value.toString();
    return dat1.substring(0,4)+ "-"+ parseInt(dat1.substring(4,6)) +  "-"+dat1.substring(6,8);
  }
}

2. 修改hello.component.html文件,进行HTML的输出。


<p>hello works!</p>

<span appLink>Directive me!</span>

<ul>
  <li *ngFor="let m of meta">
    {{m.id}}, {{m.name}}
  </li>
</ul>

<p>{{day}} ==> {{ day | datef}}</p>

修改后,我们在浏览器中查看运行的效果。

其他的命令,我们在后文再继续说明。本文只是一篇对Angular2的新体验介绍,由于Angular2整个框架还是变化挺大的,同时我对Typescript也不熟悉,对webapck也需要花时间学习。整个过程花了不少时间,也走了不少的弯路。

目前,网上Angular2框架介绍的文章本来就不多,虽然官网文档比较详细,但是上手来说,还是有一定的难度的,希望本文对于新手来说有一些帮助,也希望Angualr2尽快成熟,我准备正在项目中用起来!!

转载请注明出处:
http://blog.fens.me/angularjs-yeoman-project/

打赏作者

CNPM搭建私有的NPM服务

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-cnpm-npm/

nodejs-cnpm-npm

前言

随着Nodejs开发的项目越来越多,Node项目管理就成了一个需要思考的问题了。如果所有项目都开源统一用 NPM 进行管理也没什么问题,但总有一些是我们不希望的完全开放的代码,作为企业是核心秘密保留在公司内部,这个时候就需要在公司内网也搭建一套 NPM 依赖管理系统。

CNPM正好就提供了这个功能。从Github上CNPM的主页看,CNPM由国内Alibaba团队开发维护。

目录

  1. CNPM是什么?
  2. 搭建CNPM的服务器
  3. 设置私有注册库的三种方法
  4. CNPM的客户端使用

1. CNPM是什么?

CNPM 是一个Nodejs的库,致力于打造私有的 NPM 注册服务。当然,除了私有库功能以外,CNPM官网 (http://cnpmjs.org/) 还提供了NPM同步的服务。

CNPM官方发布的架构图:
cnpm-architect

从CNPM的架构图中,我们可以看出CNPM是对NPM做的镜像服务,CNPM会定期同步NPM的资源库,同时CNPM支持发布私有的库,这样就非常方便地集成了公有库和私有库,对于公司内部的开发者来说,基本感觉不到两种库的区别。

另外,我们使用NPM下载依赖包时,经常性地会遇到一些包下载失败的情况,主要原因了NPM的注册服务器在国外,国内的网络环境访问国外的IP并不是太好。所以,直接配置到国内的NPM镜像,可以减少NPM下载出错机会。

比如,最近发生的NPM下载时的“No compatible version found”错误,如果不想升级NPM的环境,那么你还选择用CNPM去进行依赖管理,关于错误的详细介绍,请参考文章 NPM下载出错 No compatible version found

2. 搭建CNPM的服务器

从官方文档中,我们看到CNPM服务器环境,只需要Node(0.11.12) + MySQL(>= 0.5.0),另外我们还需要Linux的环境,接下来就让我们动手自己搭建一个私有NPM的服务器。

我的系统环境:

  • Linux: Ubuntu 12.04.2 64bit Server
  • Node: v0.11.2
  • Npm: 1.2.21
  • MySQL: 5.6.11 MySQL Community Server (GPL)
  • IP: 192.168.1.20

通过github下载项目源代码


# 下载项目,进入目录
~ git clone https://github.com/cnpm/cnpmjs.org.git
~ cd cnpmjs.org

在我们开始安装依赖包之前,先要升级NPM的版本,不然会出现“No compatible version found”的错误。


~ sudo npm install npm -g
/usr/local/bin/npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js
npm@2.0.0-beta.0 /usr/local/lib/node_modules/npm

安装项目依赖


~ sudo npm install 
npm WARN engine koa-generic-session@1.1.3: wanted: {"node":">= 0.11.9"} (current: {"node":"0.11.2","np               m":"2.0.0-beta.0"})
npm WARN engine koa-redis@0.1.1: wanted: {"node":">= 0.11.9"} (current: {"node":"0.11.2","npm":"2.0.0-               beta.0"})
npm WARN engine koa-resource-router@0.3.3: wanted: {"node":"> 0.11.4"} (current: {"node":"0.11.2","npm               ":"2.0.0-beta.0"})
npm WARN engine koa-rt@0.0.2: wanted: {"node":">= 0.11.9"} (current: {"node":"0.11.2","npm":"2.0.0-bet               a.0"})
npm WARN engine koa-router@3.2.3: wanted: {"node":"> 0.11.4"} (current: {"node":"0.11.2","npm":"2.0.0-               beta.0"})
npm WARN engine koa-static-cache@1.1.0: wanted: {"node":"> 0.11.4"} (current: {"node":"0.11.2","npm":"               2.0.0-beta.0"})
npm WARN deprecated lingo@0.0.5: This project is abandoned
co-read@0.1.0 node_modules/co-read

error-formater@1.0.3 node_modules/error-formater
└── utility@0.1.16 (address@0.0.3)

multiline@1.0.0 node_modules/multiline
└── strip-indent@1.0.0 (get-stdin@1.0.0)

jshint@2.5.5 node_modules/jshint
├── strip-json-comments@0.1.3
├── underscore@1.6.0
├── exit@0.1.2
├── shelljs@0.3.0
├── minimatch@0.4.0 (sigmund@1.0.0, lru-cache@2.5.0)
├── console-browserify@1.1.0 (date-now@0.1.4)
├── cli@0.6.4 (glob@3.2.11)
└── htmlparser2@3.7.3 (domelementtype@1.1.1, domutils@1.5.0, entities@1.0.0, domhandler@2.2.0, readabl               e-stream@1.1.13)

koa-middlewares@1.2.0 node_modules/koa-middlewares
├── koa-conditional-get@1.0.2
├── koa-rt@0.0.2
├── koa-session@2.0.0
├── koa-etag@1.3.1 (buffer-crc32@0.2.3)
├── koa-logger@1.2.2 (passthrough-counter@0.0.1)
├── koa-compress@1.0.7 (statuses@1.0.4, koa-is-json@1.0.0, compressible@1.1.1)
├── koa-safe-jsonp@0.2.0 (jsonp-body@0.1.0)
├── koa-rewrite@1.1.0 (path-to-regexp@0.0.2)
├── koa-static-cache@1.1.0 (fs-readdir-recursive@0.0.2, compressible@1.1.1, mime-types@1.0.2)
├── koa-redis@0.1.1 (redis@0.10.3)
├── koa-router@3.2.3 (koa-compose@2.3.0, methods@1.1.0, path-to-regexp@0.2.1)
├── koa-bodyparser@1.0.1 (co-body@1.0.0)
├── koa-favicon@1.1.0 (co-fs@1.2.0)
├── koa-resource-router@0.3.3 (koa-compose@2.2.0, path-to-regexp@0.0.2, debug@0.7.4, lingo@0.0.5, defa               ults@1.0.0)
├── koa-generic-session@1.1.3 (buffer-crc32@0.2.3, uid-safe@1.0.1)
├── koa-csrf@2.1.3 (csrf@2.0.1)
├── koa-ejs@1.0.1 (ejs@1.0.0, co-fs@1.2.0, is-type-of@0.2.1)
└── koa-onerror@1.0.3 (swig@1.4.2)

创建MySQL数据库,我本地的MySQL用户名为root,密码是mysql,可以通过下面语句创建。


~ mysql -uroot -pmysql -e 'DROP DATABASE IF EXISTS cnpmjs_test;' &&\
mysql -uroot -pmysql -e 'CREATE DATABASE cnpmjs_test;' &&\
mysql -uroot -pmysql 'cnpmjs_test' < docs/db.sql &&\
mysql -uroot -pmysql 'cnpmjs_test' -e 'show tables;'
+-----------------------+
| Tables_in_cnpmjs_test |
+-----------------------+
| dist_dir              |
| dist_file             |
| download_total        |
| module                |
| module_deps           |
| module_keyword        |
| module_log            |
| module_maintainer     |
| module_star           |
| module_unpublished    |
| tag                   |
| total                 |
| user                  |
+-----------------------+

接下来,我们需要在项目的./config/index.js文件中,修改MySQL数据库的用户名和密码。


~ vi ./config/index.js

108   /**
109    * mysql config
110    */
111
112   mysqlServers: [
113     {
114       host: '127.0.0.1',
115       port: 3306,
116       user: 'root',
117       password: 'mysql'
118     }
119   ],
120   mysqlDatabase: 'cnpmjs_test',
121   mysqlMaxConnections: 4,
122   mysqlQueryTimeout: 5000,
123

启动CNPM服务器,默认会打开两个端口,7001用于NPM的注册服务,7002用于Web访问。


~  node --harmony_generators dispatch.js
[Tue Sep 02 2014 15:17:54 GMT+0800 (CST)] [worker:25211:common/redis.js] Redis config can not found
[Tue Sep 02 2014 15:17:54 GMT+0800 (CST)] [worker:25211] Server started, registry server listen at 127.0.0.1:7001, web listen at 127.0.0.1:7002, cluster: false
[Tue Sep 02 2014 15:17:54 GMT+0800 (CST)] [worker:25211] mysql ready, got 13 tables

从日志中看到,这两个端口服务都绑定在127.0.0.1的本地网络中,我们需要修改配置文件 ./config/index.js文件,注释bindingHost一行,对外网开放。


~ vi ./config/index.js

 39   /*
 40    * server configure
 41    */
 42   registryPort: 7001,
 43   webPort: 7002,
 44   //bindingHost: '127.0.0.1', // only binding on 127.0.0.1 for local access

第二次,启动CNPM服务器


~ node --harmony_generators dispatch.js
[Tue Sep 02 2014 15:22:46 GMT+0800 (CST)] [worker:25259:common/redis.js] Redis config can not found
[Tue Sep 02 2014 15:22:46 GMT+0800 (CST)] [worker:25259] Server started, registry server listen at undefined:7001, web listen at undefined:7002, cluster: false
[Tue Sep 02 2014 15:22:46 GMT+0800 (CST)] [worker:25259] mysql ready, got 13 tables

通过浏览器访问:http://192.168.1.20:7002,没想到的情况,应用又崩溃了,这个坑深入了!!


[Tue Sep 02 2014 15:29:00 GMT+0800 (CST)] [worker:25404] Server started, registry server listen at undefined:7001, web listen at undefined:7002, cluster: false
[Tue Sep 02 2014 15:29:00 GMT+0800 (CST)] [worker:25404] mysql ready, got 13 tables

==== JS stack trace =========================================

    2: arguments adaptor frame: 0->1
Security context: 0x185dd4b5e291 <JS Object>#0#
    4: /* anonymous */ [/home/conan/nodejs/cnpmjs.org/node_modules/co/index.js:40] (this=0x2a1e646d07e1 <an Object>#1#,done=0x2d36f5fcdd31 <JS Function>#2#)
    5: /* anonymous */ [/home/conan/nodejs/cnpmjs.org/node_modules/koa/lib/application.js:125] (this=0x2d36f5fab301 <a Server>#3#,req=0x2d36f5fcacc1 <an IncomingMessage>#4#,res=0x2d36f5fcc3f9 <a ServerResponse>#5#)
    6: emit [events.js:100] (this=0x2d36f5fab301 <a Server>#3#,type=0x8305a126379 <String[7]: request>)
    7: arguments adaptor frame: 3->1
    8: onIncoming [_http_server.js:450] (this=0x2d36f5fc8029 <an HTTPParser>#6#,req=0x2d36f5fcacc1 <an IncomingMessage>#4#,shouldKeepAlive=0x185dd4b04161 <true>)
    
//省略日志

经过检查发现,是Node版本的问题。重新下载编译安装Node,详细操作请参考文章准备Nodejs开发环境Ubuntu,升级后的版本为

  • Node v0.13.0-pre
  • NPM 1.4.21

第三次,启动CNPM服务器。


~ node --harmony_generators dispatch.js
[Tue Sep 02 2014 16:00:25 GMT+0800 (CST)] [worker:14842:common/redis.js] Redis config can not found
[Tue Sep 02 2014 16:00:25 GMT+0800 (CST)] [worker:14842] Server started, registry server listen at undefined:7001, web listen at undefined:7002, cluster: false
[Tue Sep 02 2014 16:00:25 GMT+0800 (CST)] [worker:14842] mysql ready, got 13 tables

通过浏览器访问,CNPM服务:http://192.168.1.20:7002

cnpm-local

终于正常了,这样就成功搭建了私有的NPM注册服务。

搜索一下,我之前在NPM发布的自己的包ape-algorithm,发现没有结果,根据界面提示CNPM应用会自动去NPM上同步。

cnpm-ape-algorithm

第一次同步操作,会下载很多的包,大家要耐心等待啊。页面不能切换!

3. 设置私有注册库的三种方法

我们自己搭建的私有服务怎么用呢?

我们先建一个项目目录


~ /home/conan/nodejs
~ mkdir nodejs-cnpm && cd nodejs-cnpm

3.1 下载指定私有库

一种简单的方式就是,下载的时候指定我们自己的私有库,这样就会从我们自己的私有库中下载。如果私有库没有对应的库,CNPM会自动同步到NPM 找到我们要下载的库和版本,先在CNPM中存一份,然后再传给客户端一份,运行原理和Maven的原理一样。

执行下载的操作


~ npm install ape-algorithm --registry=http://192.168.1.20:7001
ape-algorithm@0.0.8 node_modules/ape-algorithm
└── linklist@0.0.3

# 查看下载的库
~ ls -l
drwxrwxr-x 3 conan conan 4096  9月  2 16:36 node_modules

3.2 给项目设置私有库

如果这个项目所有依赖库都从公司内网下载,那么我们可以给整个项目设置私有库,就不需要每次下载的时候单独指定了。

首先,我们查看项目的默设置,通过npm config list命令。


~ npm config list

; cli configs
registry = "https://registry.npmjs.org/"
user-agent = "npm/1.4.21 node/v0.13.0-pre linux x64"

; node bin location = /usr/local/bin/node
; cwd = /home/conan/nodejs/nodejs-cnpm
; HOME = /home/conan
; 'npm config ls -l' to show all defaults.

registry属性是指向NPM的官司位置https://registry.npmjs.org/,我们可以通过npm config set registry命令来修改这个配置。


~ npm config set registry http://192.168.1.20:7001

# 再次查看项目设置
~ npm config list
; cli configs
registry = "http://192.168.1.20:7001/"
user-agent = "npm/1.4.21 node/v0.13.0-pre linux x64"

; userconfig /home/conan/.npmrc
registry = "http://192.168.1.20:7001/"

; node bin location = /usr/local/bin/node
; cwd = /home/conan/nodejs/nodejs-cnpm
; HOME = /home/conan

这个项目再下载新包时,就会通过我们私有库去下载。

3.3 给用户设置私有库

如果我们的开发环境在内网,不允许访问外网,那么我们可以设置全局的NPM库。

在当前用户所在的根目录,找到.npmrc文件,配置NPM私有库。


~  vi ~/.npmrc

registry=http://192.168.1.20:7001

设置成功后,当前用户的所有NPM下载都会通过私有库来完成。

3.4 设置淘宝的开放库

我们除了使用自己的私有库,还可以使用淘宝的NPM库,这样可以有效地避免国内访问国外NPM库,网络不通的问题。

按照上面的方法,把registry配置为https://registry.npm.taobao.org 就行了。


registry = "https://registry.npm.taobao.org/"

4. CNPM的客户端使用

CNPM 不仅提供服务端的功能,还提供了客户端的访问功能,就像NPM一样。通过全局安装cnpm包,可以完全取代了npm的命令操作了。

安装cnpm客户端


~ sudo npm install -g cnpm

/usr/local/bin/cnpm -> /usr/local/lib/node_modules/cnpm/bin/cnpm
/usr/local/bin/cnpm-sync -> /usr/local/lib/node_modules/cnpm/bin/cnpm-sync
/usr/local/bin/cnpm-check -> /usr/local/lib/node_modules/cnpm/bin/cnpm-check
/usr/local/bin/cnpm-web -> /usr/local/lib/node_modules/cnpm/bin/cnpm-web
/usr/local/bin/cnpm-user -> /usr/local/lib/node_modules/cnpm/bin/cnpm-user
/usr/local/bin/cnpm-doc -> /usr/local/lib/node_modules/cnpm/bin/cnpm-doc
/usr/local/bin/cnpm-search -> /usr/local/lib/node_modules/cnpm/bin/cnpm-search
cnpm@1.0.0 /usr/local/lib/node_modules/cnpm
├── commander@2.3.0
├── auto-correct@1.0.0
├── giturl@0.0.3
├── cross-spawn@0.1.7
├── colors@0.6.2
├── bagpipe@0.3.5
├── open@0.0.5
├── debug@1.0.4 (ms@0.6.2)
├── npm-request@0.0.4 (urllib@0.5.11)
├── npm@2.0.0-beta.2
└── urllib@0.5.17 (default-user-agent@0.0.1, debug@0.8.1, digest-header@0.0.1)

测试一下,通过cnpm安装gulp包。


~ cnpm install gulp

> node-v8-clone@0.6.2 install /home/conan/nodejs/nodejs-cnpm/node_modules/gulp/node_modules/gulp-util/node_modules/vinyl/node_modules/node-v8-clone
> node-gyp rebuild

gulp@3.8.7 node_modules/gulp
├── tildify@0.2.0
├── interpret@0.3.2
├── pretty-hrtime@0.2.0
├── deprecated@0.0.1
├── archy@0.0.2
├── minimist@0.2.0
├── semver@3.0.1
├── chalk@0.5.0 (escape-string-regexp@1.0.1, ansi-styles@1.1.0, supports-color@0.2.0, has-ansi@0.1.0, strip-ansi@0.3.0)
├── orchestrator@0.3.0 (sequencify@0.0.7, events@1.0.2, execify@0.0.3)
├── liftoff@0.12.0 (extend@1.2.1, minimist@0.1.0, resolve@0.7.4, findup-sync@0.1.3)
├── gulp-util@3.0.1 (lodash._reinterpolate@2.4.1, dateformat@1.0.8-1.2.3, minimist@1.1.0, multipipe@0.1.0, lodash.template@2.4.1, through2@0.6.1, lodash@2.4.1, vinyl@0.4.0)
└── vinyl-fs@0.3.0 (map-stream@0.1.0, graceful-fs@3.0.2, lodash.defaults@2.4.1, mkdirp@0.5.0, through2@0.5.1, strip-bom@0.3.0, through2-map@1.4.0, glob-watcher@0.0.6, glob-stream@3.1.15, vinyl@0.2.0)

效果同NPM一样,gulp包被成功安装。

当我们要发布包到NPM的时候,由于CNPM默认同步时间差是30分钟,如果想马上同步,需要手动输入同步的命令。

同步gulp包。


~ cnpm sync gulp

Start sync ["gulp"].
sync gulp, PUT http://r.cnpmjs.org/gulp/sync?publish=false&nodeps=false
logurl: http://cnpmjs.org/sync/gulp#logid=10798
[2014-09-02 05:18:09] user: anonymous, sync gulp worker start, 1 concurrency, nodeps: false, publish: false
[2014-09-02 05:18:09] [c#0] [gulp] pkg status: 200, start...
[2014-09-02 05:18:09]   [gulp] found 15 missing star users
[2014-09-02 05:18:09]   [gulp] all versions are exists
[2014-09-02 05:18:09]   [gulp] no versions need to deleted
[2014-09-02 05:18:09]   [gulp] saving 15 star users
[2014-09-02 05:18:09]   [gulp] saving 3/187 missing npm users: ["mittya","160mph","vivainio"]
[2014-09-02 05:18:09] [c#0] [gulp] synced success, 0 versions:
[2014-09-02 05:18:09] [c#0] setImmediate after, gulp done, start next...
[2014-09-02 05:18:09] [done] Sync gulp module finished, 1 success, 0 fail
Success: [ gulp ]
Fail: [  ]
sync gulp, PUT https://registry.npm.taobao.org/gulp/sync?publish=false&nodeps=false
logurl: https://npm.taobao.org/sync/gulp#logid=8354
[2014-09-02 17:18:13] user: anonymous, sync gulp worker start, 1 concurrency, nodeps: false, publish: false
[2014-09-02 17:18:14] [c#0] [gulp] pkg status: 200, start...
[2014-09-02 17:18:14]   [gulp] found 15 missing star users
[2014-09-02 17:18:14]   [gulp] all versions are exists
[2014-09-02 17:18:14]   [gulp] saving 15 star users
[2014-09-02 17:18:14]   [gulp] no versions need to deleted
[2014-09-02 17:18:15]   [gulp] saving 3/188 missing npm users: ["mittya","160mph","vivainio"]
[2014-09-02 17:18:15] [c#0] setImmediate after, gulp done, start next...
[2014-09-02 17:18:15] [c#0] [gulp] synced success, 0 versions:
[2014-09-02 17:18:15] [done] Sync gulp module finished, 1 success, 0 fail
Success: [ gulp ]
Fail: [  ]
Sync all packages done, successed: ["gulp"], failed: []

这样我们就完全地把CNPM私有库在公司内部用起来了。把包管理的问题解决了,让程序员可以踏踏实实地写代码才是最重要的!!

转载请注明出处:
http://blog.fens.me/nodejs-cnpm-npm/

打赏作者

NPM下载出错 No compatible version found

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-npm-no-compatible-version

nodejs-npm

前言

NPM大家都熟,天天都在用。最近,NPM不断出现的下载出错 “npm ERR! Error: No compatible version found” ,已经影响到正常的开发工作,到了不得不解决的地步了。网上到处都是这个错误的问题,但解决问题的文章很难找到。我有必要来写一下。

目录

  1. NPM下载出错 No compatible version found
  2. 官方解决方案
  3. 其他解决方案

1. NPM下载出错 No compatible version found

最近,NPM不断出现的下载出错 “npm ERR! Error: No compatible version found” ,已经影响到了正常的开发工作,到了不得不解决的地步了。

我的系统环境

  • Win7 64bit
  • Node v0.10.5
  • NPM 1.2.19

NPM的下载出错


npm ERR! Error: No compatible version found: gulp-rename@'^1.2.0'
npm ERR! Valid install targets:
npm ERR! ["0.1.0","0.2.1","0.2.2","1.0.0","1.1.0","1.2.0"]
npm ERR!     at installTargetsError (D:\toolkit\nodejs\node_modules\npm\lib\cache.js:689:10)
npm ERR!     at D:\toolkit\nodejs\node_modules\npm\lib\cache.js:611:10
npm ERR!     at saved (D:\toolkit\nodejs\node_modules\npm\node_modules\npm-registry-client\lib\get.js:138:7)
npm ERR!     at Object.oncomplete (fs.js:107:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     
npm ERR! or email it to:
npm ERR!     

像这种类库管理本来不用动脑子的事情,一下子就会变得很麻烦了,小白程序员肯定是各种抓狂,网上所有的文章都解决不了自己的问题,对Nodejs瞬间失去信心….

我的项目中,只是要配置gulp包及相关插件的依赖下载,项目配置文件为 package.json。


{
  "name": "nodejs-cnpm",
  "version": "0.0.1",
  "description": "cnpm",
  "keywords": [
    "cnpm"
  ],
  "author": "Conan Zhang ",
  "main": "cnpm",
  "dependencies": {},
  "devDependencies": {
    "gulp": "^3.8.7",
    "gulp-changed": "^1.0.0",
    "gulp-concat": "^2.3.4",
    "gulp-jshint": "^1.8.4",
    "gulp-minify-css": "^0.3.7",
    "gulp-ngmin": "^0.3.0",
    "gulp-rename": "^1.2.0",
    "gulp-uglify": "^1.0.0",
    "gulp-util": "^3.0.1"
  }
}

无论怎么运行都是No compatible version found的错误。


~ npm install
npm WARN package.json nodejs-cnpm@0.0.1 No readme data!
npm http GET https://registry.npmjs.org/gulp-changed
npm http GET https://registry.npmjs.org/gulp-concat
npm http GET https://registry.npmjs.org/gulp-ngmin
npm http GET https://registry.npmjs.org/gulp-uglify
npm http GET https://registry.npmjs.org/gulp-util
npm http GET https://registry.npmjs.org/gulp
npm http GET https://registry.npmjs.org/gulp-jshint
npm http GET https://registry.npmjs.org/gulp-minify-css
npm http GET https://registry.npmjs.org/gulp-rename
npm http 304 https://registry.npmjs.org/gulp-uglify
npm http 304 https://registry.npmjs.org/gulp-ngmin
npm ERR! Error: No compatible version found: gulp-uglify@'^1.0.0'
npm ERR! Valid install targets:
npm ERR! ["0.0.1","0.0.3","0.0.4","0.1.0","0.2.0","0.2.1","0.3.0","0.3.1","0.3.2","1.0.0-0","1.0.0"]
npm ERR!     at installTargetsError (D:\toolkit\nodejs\node_modules\npm\lib\cache.js:689:10)
npm ERR!     at D:\toolkit\nodejs\node_modules\npm\lib\cache.js:611:10
npm ERR!     at saved (D:\toolkit\nodejs\node_modules\npm\node_modules\npm-registry-client\lib\get.js:138:7)
npm ERR!     at Object.oncomplete (fs.js:107:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     
npm ERR! or email it to:
npm ERR!     

npm ERR! System Windows_NT 6.1.7601
npm ERR! command "D:\\toolkit\\nodejs\\\\node.exe" "D:\\toolkit\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install"
npm ERR! cwd D:\workspace\javascript\nodejs-cnpm
npm ERR! node -v v0.10.5
npm ERR! npm -v 1.2.19
npm http 304 https://registry.npmjs.org/gulp-concat
npm http 304 https://registry.npmjs.org/gulp-jshint
npm http 304 https://registry.npmjs.org/gulp-minify-css
npm http 304 https://registry.npmjs.org/gulp-changed
npm http 304 https://registry.npmjs.org/gulp-util
npm http 304 https://registry.npmjs.org/gulp
npm http 304 https://registry.npmjs.org/gulp-rename
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     D:\workspace\javascript\nodejs-cnpm\npm-debug.log
npm ERR! not ok code 0

2. 官方解决方案

查看NPM官方的说明Issue列表( https://github.com/npm/npm/issues/4984 ),这个问题已经被解决,但解决办法确实很不友好。

如果在Linux系统中,通过一条命令更新npm可以解决。

npm install -g npm

在Window环境中,必须升级NPM到1.4.10以上的版本,我重新安装了node-v0.10.31-x64.msi,对应的NPM为1.4.23,再此运行npm install命令,依赖包下载运行正常。

升级后的系统环境

  • Win7 64bit
  • Node 0.10.31
  • NPM 1.4.23

下载依赖包,运行正常。


~ npm install
npm WARN package.json nodejs-cnpm@0.0.1 No repository field.
npm WARN package.json nodejs-cnpm@0.0.1 No README data
npm WARN deprecated gulp-ngmin@0.3.0: Deprecated in favor of gulp-ng-annotate: https://github.com/Kagami/gulp-ng-annotat
e - Reasoning: https://github.com/btford/ngmin/issues/93
gulp-rename@1.2.0 node_modules\gulp-rename

gulp-changed@1.0.0 node_modules\gulp-changed
└── through2@0.6.1 (xtend@4.0.0, readable-stream@1.0.31)

gulp-util@3.0.1 node_modules\gulp-util
├── lodash._reinterpolate@2.4.1
├── dateformat@1.0.8-1.2.3
├── minimist@1.1.0
├── lodash@2.4.1
├── chalk@0.5.1 (escape-string-regexp@1.0.1, ansi-styles@1.1.0, supports-color@0.2.0, strip-ansi@0.3.0, has-ansi@0.1.0)
├── through2@0.6.1 (xtend@4.0.0, readable-stream@1.0.31)
├── multipipe@0.1.1 (duplexer2@0.0.2)
├── vinyl@0.4.2 (clone-stats@0.0.1)
└── lodash.template@2.4.1 (lodash.values@2.4.1, lodash.defaults@2.4.1, lodash._escapestringchar@2.4.1, lodash.templatesettings@2.4.1, lodash.keys@2.4.1, lodash.escape@2.4.1)

gulp-uglify@1.0.0 node_modules\gulp-uglify
├── deepmerge@0.2.7
├── vinyl-sourcemaps-apply@0.1.1 (source-map@0.1.38)
├── through2@0.6.1 (xtend@4.0.0, readable-stream@1.0.31)
└── uglify-js@2.4.15 (uglify-to-browserify@1.0.2, async@0.2.10, optimist@0.3.7, source-map@0.1.34)

gulp-minify-css@0.3.7 node_modules\gulp-minify-css
├── memory-cache@0.0.5
├── bufferstreams@0.0.1
├── clean-css@2.2.15 (commander@2.2.0)
├── through2@0.5.1 (xtend@3.0.0, readable-stream@1.0.31)
└── gulp-util@2.2.20 (lodash._reinterpolate@2.4.1, dateformat@1.0.8-1.2.3, minimist@0.2.0, chalk@0.5.1, vinyl@0.2.3,lodash.template@2.4.1, multipipe@0.1.1)

gulp-concat@2.3.4 node_modules\gulp-concat
├── through@2.3.4
├── concat-with-sourcemaps@0.1.3 (source-map@0.1.38)
└── gulp-util@2.2.20 (dateformat@1.0.8-1.2.3, lodash._reinterpolate@2.4.1, minimist@0.2.0, chalk@0.5.1, multipipe@0.1.1, vinyl@0.2.3, lodash.template@2.4.1, through2@0.5.1)

gulp-ngmin@0.3.0 node_modules\gulp-ngmin
├── gulp-util@2.2.20 (lodash._reinterpolate@2.4.1, dateformat@1.0.8-1.2.3, minimist@0.2.0, chalk@0.5.1, vinyl@0.2.3,through2@0.5.1, lodash.template@2.4.1, multipipe@0.1.1)
├── through2@0.4.2 (xtend@2.1.2, readable-stream@1.0.31)
└── ngmin@0.5.0 (astral@0.1.0, clone@0.1.18, ngmin-dynamic@0.0.1, astral-angular-annotate@0.0.2, commander@1.1.1, esprima@1.0.4, escodegen@0.0.28)

gulp@3.8.7 node_modules\gulp
├── tildify@0.2.0
├── interpret@0.3.6
├── pretty-hrtime@0.2.1
├── deprecated@0.0.1
├── archy@0.0.2
├── minimist@0.2.0
├── semver@3.0.1
├── orchestrator@0.3.7 (sequencify@0.0.7, stream-consume@0.1.0, end-of-stream@0.1.5)
├── chalk@0.5.1 (escape-string-regexp@1.0.1, ansi-styles@1.1.0, supports-color@0.2.0, strip-ansi@0.3.0, has-ansi@0.1.0)
├── liftoff@0.12.1 (extend@1.3.0, resolve@0.7.4, findup-sync@0.1.3)
└── vinyl-fs@0.3.7 (graceful-fs@3.0.2, strip-bom@1.0.0, mkdirp@0.5.0, lodash@2.4.1, vinyl@0.4.2, through2@0.6.1, glob-stream@3.1.15, glob-watcher@0.0.6)

gulp-jshint@1.8.4 node_modules\gulp-jshint
├── lodash@2.4.1
├── rcloader@0.1.2 (rcfinder@0.1.8)
├── minimatch@0.3.0 (sigmund@1.0.0, lru-cache@2.5.0)
├── through2@0.5.1 (xtend@3.0.0, readable-stream@1.0.31)
└── jshint@2.5.5 (strip-json-comments@0.1.3, underscore@1.6.0, exit@0.1.2, console-browserify@1.1.0, shelljs@0.3.0, cli@0.6.4, htmlparser2@3.7.3)

向这种强制性的升级,对于开发者来说是很不友好的、很难接受的。一个稳定运行的应用,只是为了改动一个小功能,被这种霸王的条件强制升级,有可能应用的整个环境都被破坏了,其他的很多包也要跟着升级,代价很大啊!

3. 其他解决方案

我在测试中发现了,除了强制升级NPM以外,还有一种解决方案,就是利用CNPM代替NPM来进行依赖管理,也能够正常地下载依赖包。

CNPM 是一个Nodejs的库,致力于打造私有的 NPM 注册服务。当然,除了私有库功能以外,CNPM官网还提供了NPM同步的服务。CNPM的配置及使用,将在下一篇文章中介绍,请参考文章CNPM搭建私有的NPM服务。让我们远离NPM包下载的错误吧,专心写好程序才是重点!

转载请注明出处:
http://blog.fens.me/nodejs-npm-no-compatible-version

打赏作者

快速创建基于npm的nodejs库

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-npm-package

nodejs-npm

前言

用Node实现的功能越来越多,代码越来越复杂,我们就开始考虑如何把代码从项目中抽出来,形成单独的类库(模块)管理。就像我们所依赖其他第三方类库一样。

本文将介绍如何定义开发一个类库,包括命令开发,发布到npm中,让其他人也可以使用。

目录

  1. npm是什么?
  2. 快速创建包
  3. 创建命令行工具
  4. 本地安装lowercase包
  5. 项目上传到github
  6. 通过npm发布包
  7. 通过npm安装包

1. npm是什么?

NPM的全称是,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块的标准。

Nodejs自身提供了基本的模块,但是开发实际应用过程中仅仅依靠这些基本模块则还需要较多的工作。幸运的是,Nodejs库和框架为我们提供了帮助,让我们减少工作量。但是成百上千的库或者框架管理起来又很麻烦,有了NPM,可以很快的找到特定服务要使用的包,进行下载、安装以及管理已经安装的包。

类似于Java中的Maven,Ubuntu中的apt-get, Ruby中的Gem, Python中pypi等…

NPM模块发布页:https://npmjs.org/

2. 快速创建包

项目描述:读取文件,把所有的大写文字转换成小写文字,控制台输出。

系统环境:

  • win7 64bit
  • Nodejs:v0.10.5
  • Npm:1.2.19

创建项目


~ D:\workspace\javascript>mkdir nodejs-package && cd nodejs-package

创建项目结构


~ D:\workspace\javascript\nodejs-package>mkdir bin
~ D:\workspace\javascript\nodejs-package>touch bin/lowercase
~ D:\workspace\javascript\nodejs-package>touch bin/lowercase.bat
~ D:\workspace\javascript\nodejs-package>mkdir test
~ D:\workspace\javascript\nodejs-package>mkdir test/data
~ D:\workspace\javascript\nodejs-package>touch test/data/sample.txt
~ D:\workspace\javascript\nodejs-package>touch lowercase.js
~ D:\workspace\javascript\nodejs-package>touch example.js
~ D:\workspace\javascript\nodejs-package>touch README.md

nodejs-package-folder

项目结构说明

  • bin目录: 用于存放命令的目录
  • bin/lowercase文件: Linux命令行可执行文件
  • bin/lowercase.bat文件: Win命令行可执行文件
  • test目录: 用于存放测试代码的目录
  • test/data目录: 用于存放测试数据的目录
  • test/data/sample.txt: 测试数据文件
  • lowercase.js文件: 核心功能代码文件
  • example.js文件: 例子代码文件
  • package.json文件: 项目描述及依赖文件
  • README.md文件: 项目说明文件

1). 创建文件:package.json


~ D:\workspace\javascript\nodejs-package>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install  --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (nodejs-package) lowercase
version: (0.0.0) 0.0.1
description: A demo package
entry point: (index.js)
test command:
git repository:
keywords:
author: Conan Zhang
license: (BSD) MIT
About to write to D:\workspace\javascript\nodejs-package\package.json:

{
  "name": "lowercase",
  "version": "0.0.1",
  "description": "A demo package",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "dependencies": {
    "moment": "~2.4.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": "",
  "author": "Conan Zhang",
  "license": "MIT",
  "readmeFilename": "README.md"
}

Is this ok? (yes) yes
npm WARN package.json lowercase@0.0.1 No readme data!

修改文件:package.json


~ vi package.json

{
    "name": "lowercase_demo",
    "version": "0.0.1",
    "description": "A demo package of lowercase",
    "keywords":[
        "demo","lowercase"
    ],
    "author": "Conan Zhang  (http://blog.fens.me)",
    "license": "MIT",
    "main": "lowercase.js",
    "repository": {
        "type":"git",
        "url":"https://github.com/bsspirit/lowercase_demo"
    },
    "engines": {
        "node": ">=v0.10.5"
    },
    "readmeFilename": "README.md"
}

2). 编辑文件:lowercase.js


~ vi lowercase.js

"use strict"
var fs = require('fs');

exports.lowerCase = function (myfile) {
    console.log(myfile);

    if (fs.existsSync(myfile)) {
        var content = fs.readFileSync(myfile, 'utf8');
        console.log(content.toLowerCase());
    } else {
        console.log("File does not exist - " + myfile);
    }
}

3). 编辑文件:example.js


~ vi example

"use strict"

var lowercase = require('./lowercase.js');
var myfile="test/data/sample.txt"
lowercase.lowerCase(myfile);

4). 编辑文件:test/data/sample.txt


~ vi sample.txt

JAVA
NODEJS
PYTHON
PHP
.NET
R
RUBY
C
C++
GO

5). 运行:example.js


~ D:\workspace\javascript\nodejs-package>node example.js
test/data/sample.txt
java
nodejs
python
php
.net
r
ruby
c
c++
go

6). 编辑文件:README.md


~ vi README.md

lowercase
========================

A demo package of lowercase

```{bash}
npm install lowercase_demo
```

## author

Conan Zhang, http://blog.fens.me

## License

MIT

3. 创建命令行工具

1). 编辑文件:bin/lowercase


~ vi lowercase

#!/usr/bin/env node

var myfile = process.argv.slice(2);

var path = require('path');
var fs = require('fs');
var dir = path.dirname(fs.realpathSync(__filename))+"/../";
require(dir+'lowercase.js').lowerCase(dir+myfile);

2). 编辑文件:bin/lowercase.bat


~ vi lowercase.bat

node.exe bin/lowercase %1

3). 运行lowercase.bat


~ D:\workspace\javascript\nodejs-package>bin\lowercase.bat test\data\sample.txt

D:\workspace\javascript\nodejs-package>node.exe bin/lowercase test\data\sample.txt
D:\workspace\javascript\nodejs-package\bin/../test\data\sample.txt
java
nodejs
python
php
.net
r
ruby
c
c++
go

4. 本地安装lowercase包

新建项目,并安装lowercase依赖库


~ D:\workspace\javascript>mkdir nodejs-package-project && cd nodejs-package-project
~ D:\workspace\javascript\nodejs-package-project>npm install ..\nodejs-package
lowercase_demo@0.0.1 node_modules\lowercase_demo

nodejs-package-project

新建运行文件:app.js


~ vi app.js

var lowercase = require('lowercase_demo');
var myfile="data.txt"
lowercase.lowerCase(myfile);

数据文件: data.txt


~ vi data.txt

APP
BACCDADDS

运行app.js


~ D:\workspace\javascript\nodejs-package-project>node app.js
data.txt
app
baccdadds

5. 项目上传到github

把lowercase_demo库,上传到github。


~ git init
~ git add .
~ git commit -m 'init'
~ git remote add origin git@github.com:bsspirit/lowercase_demo.git
~ git push origin master

项目github地址:https://github.com/bsspirit/lowercase_demo

注:大家可以基于这个demo项目基础上,继续完成包的开发。

5. 通过npm发布包

在npm上,注册新用户


~ D:\workspace\javascript\nodejs-package>npm adduser
Username: bsspirit
Password:
Email: bsspirit@gmail.com
npm http PUT https://registry.npmjs.org/-/user/org.couchdb.user:bsspirit
npm http 409 https://registry.npmjs.org/-/user/org.couchdb.user:bsspirit
npm http GET https://registry.npmjs.org/-/user/org.couchdb.user:bsspirit
npm http 200 https://registry.npmjs.org/-/user/org.couchdb.user:bsspirit
npm http PUT https://registry.npmjs.org/-/user/org.couchdb.user:bsspirit/-rev/2-25eae797548e61
npm http 201 https://registry.npmjs.org/-/user/org.couchdb.user:bsspirit/-rev/2-25eae797548e61

在npm上,发布项目


~ D:\workspace\javascript\nodejs-package>npm publish
npm http PUT https://registry.npmjs.org/lowercase_demo
npm http 201 https://registry.npmjs.org/lowercase_demo
npm http GET https://registry.npmjs.org/lowercase_demo
npm http 200 https://registry.npmjs.org/lowercase_demo
npm http PUT https://registry.npmjs.org/lowercase_demo/-/lowercase_demo-0.0.1.tgz/-rev/1-162a1
e
npm http 201 https://registry.npmjs.org/lowercase_demo/-/lowercase_demo-0.0.1.tgz/-rev/1-162a1
e
npm http PUT https://registry.npmjs.org/lowercase_demo/0.0.1/-tag/latest
npm http 201 https://registry.npmjs.org/lowercase_demo/0.0.1/-tag/latest
+ lowercase_demo@0.0.1

6. 通过npm安装

通过npm下载安装


~ D:\workspace\javascript>mkdir nodejs-package-project2 && cd nodejs-package-project2
~ D:\workspace\javascript\nodejs-package-project2>npm install lowercase_demo
npm http GET https://registry.npmjs.org/lowercase_demo
npm http 200 https://registry.npmjs.org/lowercase_demo
lowercase_demo@0.0.1 node_modules\lowercase_demo

全局安装lowercase_demo


~ D:\workspace\javascript\nodejs-package-project2>npm install lowercase_demo -g
npm http GET https://registry.npmjs.org/lowercase_demo
npm http 304 https://registry.npmjs.org/lowercase_demo
D:\toolkit\nodejs\lowercase -> D:\toolkit\nodejs\node_modules\lowercase_demo\bin\lowercase
npm ERR! peerinvalid The package generator-karma does not satisfy its siblings' peerDependenci
npm ERR! peerinvalid Peer generator-angular@0.4.0 wants generator-karma@~0.5.0

npm ERR! System Windows_NT 6.1.7601
npm ERR! command "D:\\toolkit\\nodejs\\\\node.exe" "D:\\toolkit\\nodejs\\node_modules\\npm\\bi
lowercase_demo" "-g"
npm ERR! cwd D:\workspace\javascript\nodejs-package-project2
npm ERR! node -v v0.10.5
npm ERR! npm -v 1.2.19
npm ERR! code EPEERINVALID
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     D:\workspace\javascript\nodejs-package-project2\npm-debug.log
npm ERR! not ok code 0

错误不是lowercase_demo的,没有关系。

执行全局命令:lowercase


~ D:\workspace\javascript\nodejs-package-project2>lowercase test\data\sample.txt
D:\toolkit\nodejs\node_modules\lowercase_demo\bin/../test\data\sample.txt
java
nodejs
python
php
.net
r
ruby
c
c++
go

注: 关于命令lowercase,因为代码中定义的是相对目录,所以只能访问D:\toolkit\nodejs\node_modules\lowercase_demo\目录的数据文件。

这样,我们自定义的lowercase_demo库,开发完成,发布到npm官方依赖管理,并且安装成功!整体流程走了一遍发现还是挺简单的。

你也来动手试试吧!

转载请注明出处:
http://blog.fens.me/nodejs-npm-package

打赏作者

Browserify 跑在浏览器上的Node程序

从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基于V8,同时打开20-30个网页都很流畅。Nodejs标准的web开发框架Express,可以帮助我们迅速建立web站点,比起PHP的开发效率更高,而且学习曲线更低。非常适合小型网站,个性化网站,我们自己的Geek网站!!

关于作者

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/nodejs-browserify/

nodejs-browserify

前言

Nodejs的出现,为Javascript开辟了一条新的大路,让Javascript获得了新生。虽然Nodejs也基于Javascript语法和解释器,但是前后端各自有各自的库,无法重用真的很不舒服。

Browserify 通过预编译的方法,让Javascript前端可以直接使用Node后端的程序。我们可以用一套代码完成前后端,不仅工作量变少了,程序重用性增强,还可以直接在浏览器中使用大量的NPM第三方开源库的功能。

Web时代,将是我们创新与创造的新起点。

目录

  1. Browserify介绍
  2. Browserify安装
  3. Browserify命令行参数
  4. 在浏览器中运行Nodejs程序
  5. 在浏览器中模块化调用Nodejs程序

1. Browserify介绍

Browserify的出现可以让Nodejs模块跑在浏览器中,用require()的语法格式来组织前端的代码,加载npm的模块。在浏览器中,调用browserify编译后的代码,同样写在<script>标签中。

用 Browserify 的操作,分为3个步骤。

  • 1. 写node程序或者模块
  • 2. 用Browserify 预编译成 bundle.js
  • 3. 在HTML页面中加载bundle.js

Browserify 的发布页:http://browserify.org/

2. Browserify安装

系统环境

  • win7 64bit
  • Nodejs:v0.10.5
  • Npm:1.2.19

Browserify安装


~ D:\workspace\javascript>mkdir nodejs-browserify && cd nodejs-browserify

browserify@2.36.1 node_modules\browserify
├── inherits@1.0.0
├── deep-equal@0.1.0
├── duplexer@0.1.1
├── shell-quote@0.0.1
├── parents@0.0.2
├── through@2.3.4
├── stream-combiner@0.0.2 (duplexer@0.0.4)
├── deps-sort@0.1.1 (minimist@0.0.5)
├── optimist@0.5.2 (wordwrap@0.0.2)
├── browser-resolve@1.2.1 (resolve@0.6.1)
├── JSONStream@0.6.4 (jsonparse@0.0.5, through@2.2.7)
├── syntax-error@0.0.1 (esprima@0.9.9)
├── concat-stream@1.0.1 (bops@0.0.6)
├── insert-module-globals@1.3.1 (process@0.5.1, commondir@0.0.1, duplexer@0.0.4, through@2.2.7, JSONStream@0.4.4, lex
ical-scope@0.0.14)
├── module-deps@1.1.0 (minimist@0.0.5, resolve@0.6.1, detective@2.1.2)
├── browser-pack@1.1.0 (combine-source-map@0.3.0)
├── umd@1.3.1 (rfile@1.0.0, ruglify@1.0.0, uglify-js@2.4.6)
└── browser-builtins@2.0.5 (constants-browserify@0.0.1, os-browserify@0.1.1, console-browserify@1.0.1, vm-browserify@
0.0.1, punycode@1.2.3, buffer-browserify@0.2.2, crypto-browserify@1.0.9, http-browserify@0.1.14, zlib-browserify@0.0.3)

全局安装,安装过程提示错误。不过没有关系!


~ D:\workspace\javascript\nodejs-browserify>npm install browserify -g

D:\toolkit\nodejs\browserify -> D:\toolkit\nodejs\node_modules\browserify\bin\cmd.js
npm ERR! peerinvalid The package generator-karma does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer generator-angular@0.4.0 wants generator-karma@~0.5.0

npm ERR! System Windows_NT 6.1.7601
npm ERR! command "D:\\toolkit\\nodejs\\\\node.exe" "D:\\toolkit\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install" "
browserify" "-g"
npm ERR! cwd D:\workspace\javascript\nodejs-browserify
npm ERR! node -v v0.10.5
npm ERR! npm -v 1.2.19
npm ERR! code EPEERINVALID
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     D:\workspace\javascript\nodejs-browserify\npm-debug.log
npm ERR! not ok code 0

3. Browserify命令行参数

使用Browserify命令正常。


~ D:\workspace\javascript\nodejs-browserify>browserify
Usage: browserify [entry files] {OPTIONS}

Standard Options:

    --outfile, -o  Write the browserify bundle to this file.
                   If unspecified, browserify prints to stdout.

    --require, -r  A module name or file to bundle.require()
                   Optionally use a colon separator to set the target.

      --entry, -e  An entry point of your app

     --ignore, -i  Omit a file from the output bundle.

   --external, -x  Reference a file from another bundle.

  --transform, -t  Use a transform module on top-level files.

    --command, -c  Use a transform command on top-level files.

  --standalone -s  Generate a UMD bundle for the supplied export name.
                   This bundle works with other module systems and sets the name
                   given as a window global if no module system is found.

       --debug -d  Enable source maps that allow you to debug your files
                   separately.

       --help, -h  Show this message

For advanced options, type `browserify --help advanced`.

Specify a parameter.
  • –outfile, -o: browserify日志打印到文件
  • –require, -r: 绑定模块名或文件,用逗号分隔
  • –entry, -e: 应用程序的入口
  • –ignore, -i: 省略输出
  • –external, -x: 从其他绑定引入文件
  • –transform, -t: 对上层文件进行转换
  • –command, -c: 对上层文件使用转换命令
  • –standalone -s: 生成一个UMB的绑定的接口,提供给其他模块使用。
  • –debug -d: 激活source maps调试文件
  • –help, -h: 显示帮助信息

高级命令:


~ D:\workspace\javascript\nodejs-browserify>browserify --help advanced
Advanced Options:

  --insert-globals, --ig, --fast    [default: false]

    Skip detection and always insert definitions for process, global,
    __filename, and __dirname.

    benefit: faster builds
    cost: extra bytes

  --detect-globals, --dg            [default: true]

    Detect the presence of process, global, __filename, and __dirname and define
    these values when present.

    benefit: npm modules more likely to work
    cost: slower builds

  --ignore-missing, --im            [default: false]

    Ignore `require()` statements that don't resolve to anything.

  --noparse=FILE

    Don't parse FILE at all. This will make bundling much, much faster for giant
    libs like jquery or threejs.

  --deps

    Instead of standard bundle output, print the dependency array generated by
    module-deps.

  --list

    Print each file in the dependency graph. Useful for makefiles.

  --extension=EXTENSION

    Consider files with specified EXTENSION as modules, this option can used
    multiple times.
  • –insert-globals, –ig, –fast: 跳过检查,定义全局变量。[default:false]
  • –detect-globals, –dg: 检查全局变量是否存在。 [default:true]<
  • –ignore-missing, –im: 忽略require()函数。[default: false]
  • –noparse=FILE: 不解析文件,直接build。
  • –deps: 打印完整输出日志
  • –list: 打印每个文件的依赖关系
  • –extension=EXTENSION: 指名扩展名的文件做为模块加载,允许多次设置

4. Browserify使用:在浏览器中运行Nodejs程序

新建4个文件:

  • multiply.js: 乘法计算
  • square.js: 平方计算,依赖multiply.js
  • index.js: node启动程序,调用square.js
  • index.html: 用于显示的HTML网页

新建文件:multiply.js


~ vi multiply.js

module.exports = function (a, b) {
    console.log("js:multiply");
    return a * b;
};

新建文件:square.js


~ vi square.js

var multiply = require('./multiply');
module.exports = function (n) {
    console.log("js:square");
    return multiply(n, n);
};

新建文件:index.js


~ vi index.js

var square = require('./square');
console.log("js:index");
console.log(square(125));

在node环境中运行


~ node index.js
js:index
js:square
js:multiply
15625

用browserify编译index.js文件到bundle.js


~ browserify index.js > bundle.js

新建文件:index.html


<!DOCTYPE html>
<html>
<head>
<title>Browserify</title>
<style>input{width:50px;}</style>
</head>
<body>
<h1>Browserify</h1>
<script src="bundle.js"></script>
</body>
</html>

在index.html中,我们加载刚才生成的bundle.js文件。

在浏览器中预览效果:

browserify-console

5. 在浏览器中模块化调用Nodejs函数

新建文件:

  • multiply.js: 同上面的文件
  • module.html: 用于显示的HTML网页

查看文件:multiply.js


~ vi multiply.js

module.exports = function (a, b) {
    console.log("js:multiply");
    return a * b;
};

用browserify编译multiply.js文件到bundle.js,作为模块

~ browserify -r ./multiply.js > bundle.js

新建文件:module.html


<!DOCTYPE html>
<html>
<head>
<title>Browserify</title>
<style>input{width:50px;}</style>
</head>
<body>
<form>
<p>
<input type="text" id="x" value="2"/> * <input type="text" id="y" value="3" /> = <span id="result"></span>
</p>
<input type="button" onclick="add()" value="M1"/>
<input type="button" onclick="add2()" value="M2"/>
</form>
<script src="bower_components/jquery/jquery.min.js"></script>
<script src="bundle.js"></script>
<script>
function add(){
var x = parseInt($('#x').val());
var y = parseInt($('#y').val());
console.log(x*y);
$('#result').text(x*y);
}

var m = require('./multiply.js');
function add2(){
var x = parseInt($('#x').val());
var y = parseInt($('#y').val());
console.log(m);
console.log(x*y);
$('#result').text(m(x,y));
}
</script>
</body>
</html>

在浏览器中打开:
browserify-click

  • 点击M1,通过add1函数计算出6
  • 点击M2,通过add2函数,调用bundle.js中的multiply.js的函数,计算出6

转载请注明出处:
http://blog.fens.me/nodejs-browserify/

打赏作者