Stage1
git使用技巧:在.gitconfig文件中配置git常用快件键
[alias]
ci = commit -a -v
st = status -s
br = branch
throw = reset --hard HEAD
thrown = reset --hard HEAD^
安装Node
安装nvm
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.27.1/install.sh | bash
退出 shell 重新登录,执行
nvm ls-remote
安装 Node.js
$ nvm install 5.1.1
安装完成后,查看一下
$ nvm ls
这时候可以看到自己安装的所有 Node.js 版本,输出应如下:
v4.0.0
-> v5.0.0
system
default -> 5.0 (-> v5.0.0)
node -> stable (-> v5.0.0) (default)
stable -> 5.0 (-> v5.0.0) (default)
iojs -> iojs- (-> N/A) (default)
完善安装
上述过程完成后,有时会出现,当开启一个新的 shell 窗口时,找不到 node 命令的情况。这种情况一般来自两个原因
1、shell 不知道 nvm 的存在
2、nvm 已经存在,但是没有 default 的 Node.js 版本可用。
解决方式:
1、检查 ~/.profile 或者 ~/.bash_profile 中有没有这样两句
export NVM_DIR="/Users/YOURUSERNAME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
没有的话,加进去。这两句会在 bash 启动的时候被调用,然后注册 nvm 命令。
2、调用 $ nvm ls
看看像不像上述图1中一样,有 default 的指向。
如果没有的话,执行
$ nvm alias default 5.1.1
然后再
$ nvm ls
更改全局安装路径
npm get prefix #查看npm装包位置
/usr/local
默认情况下,npm 全局装包会安装到 /usr/local/ 之中,默认情况下,如果不用 sudo ,很可能会报权限错误。最好的方式是修改一下全局安装的位置. 具体步骤如下:
1、来到当前用户主目录下,新建安装位置
$ cd ~
$ mkdir .npm-global
2、把 npm 全局安装位置改为这个文件夹
$ npm config set prefix '~/.npm-global'
3、可执行文件的路径也要导出一下,到您命令行的启动加载文件中,例如我用的是bash ,所以是 ~/.bash_profile
默认情况下可能是 .bashrc 或者 .profile 文件,添加下面内容:
export PATH=~/.npm-global/bin:$PATH
然后使用source命令加载一下
$ source ~/.bash_profile
接下来就可通过npm安装包了,例如全局安装gulp
$npm i -g gulp
$which gulp
/Users/peter/.npm-global/bin/gulp
安装 gulp
前提是 nodejs 已经装好。这样,先来把 gulp 全局安装一次
$ npm i -g gulp
这样的目的是为了拥有 gulp 这个系统命令。然后,新建项目,比如
$ mkdir project
$ cd project
进入项目后,还要把 gulp 在项目内安装一次
$ npm init # 生成一个 package.json 文件
$ npm i --save-dev gulp
这样做的目的是,保证项目内部的 gulpfile.js 中,使用 require('gulp')
的时候不会报错。
gulp常用API
gulp.task('taskname', [ taskDep1, taskDep2 ],taskContentFunc)
//定义一个任务,声明它的名称, 任务依赖, 和任务内容.
Gulp 4 add new task execution system - gulp.parallel and gulp.series
gulp.task('taskname', gulp.series('taskDep1', gulp.parallel('taskDep2', 'taskDep3'),taskContentFunc)
Each step that can be done in concurrent will be combined in a gulp.parallel function. The others are ordered in a gulp.series function. Like that:
(参考文档)[https://fettblog.eu/gulp-4-parallel-and-series/]
gulp.src( file[s] )
//读取文件,参数为文件路径字符串或数组, 支持通配符.
gulp.dest( destPath )
//写入文件, 作为pipe的一个流程.文件夹不存在时会被自动创建.
gulp.watch(files, [taskDep, taskDep2])
//监控文件,执行任务.
进阶1:dest匹配src
gulp.dest( destPath )会将流中的文件写入到destPath中, 但并不是所有的文件都写在destPath的根目录下, 有的可能是在其下又创建子目录,其中的规则是怎样的呢~?
dest是与src相匹配的. src读取文件路径获取文件,主要有三种情况:
指定的文件:['/foo-1/bar-1.js', '/foo-1/bar-2.js','/foo-2/bar2.js'].
模糊匹配文件名的文件: ['/foo-1/bar-*.js', 'foo-2/bar-*.js'].
模糊匹配路径下的文件: [/*/bar-*.js]
以上三种情况读取的文件, 前两种会写入到destPath的根目录下, 而最后一种情况, 会在destPath下新建foo-1和foo-2文件夹然后写三个文件到相应的文件夹里. 发现规律了吗~?
dest会将src”匹配”到的文件路径写出来~(这个匹配必须是纯粹的匹配, 全匹配, 如果是foo式的半匹配就不会写文件路径) 第一和第二种匹配到的是指定文件, 第三种匹配到的是符合规则的路径下的文件, 所以会出现上面的情况. 也就是说, 如果想将源文件的路径也dest到目标路径, 那就需要将路径也放在”匹配”中.
文件匹配路径
foo.js指明特定某个文件
*.js匹配当前目录下的所有js文件,不指名扩展名则匹配所有类型
*/*.js匹配所有第一层子文件夹的js文件,第二层请用*/*/.js
**/*.js匹配所有文件夹层次下的js文件, 包括当前目录
exclude
排除的方法就是在文件匹配pattern前加!, 跟.gitignore类似. 但有些地方需要注意:如果任务需要你使用*/递归匹配, 那么执行exclude也需要递归exclude, 即!exclude/path/**/*
.
这个坑是笔者在最近写atom-shell程序时遇到的: 我将atom-shell.app放在了项目目录, 需要构建成OSX的app时就把项目目录中所有的文件都拷贝到atom-shell.app下的contents/resources/app目录下. 所有文件, 当然是要用*/递归匹配喽~, 后面再跟!./atom-shell.app, 而OSX下的.app文件其实就是文件夹, 递归匹配加非递归exclude, 就造成了其实.app也被读取的状况, 然后就无限引用了… 不过gulp有自己的保护机制, 没有出死循环这样的傻事.
正确的作法是['**/*', '!./atom-shell.app', '!./atom-shell.app/**/*']
. 这样就可以把app完全exclude掉了
gulp常用插件
"devDependencies": {
"gulp": "*", // 基础
"gulp-load-plugins" : "*",
"gulp-if": "*", // 根据不同的环境,切换方法
"gulp-util": "*", // 如果有自定义方法,可能会用到
"gulp-clean": "*", // 清理路径下文件
"gulp-rename": "*", // 重命名文件,比如上节提到 _ 需要还原回去
"gulp-concat": "*", // 文件合并
"gulp-jshint": "*", // jshint 检查一些格式,这个是为了统一团队的代码风格的
"gulp-browserify": "*", // 利用 CommonJS 的格式,直接让浏览器也能用类似的方式
"gulp-uglify": "*", // 替换压缩
"gulp-cssnano" // Minify CSS with cssnano.
"gulp-rev" // Static asset revisioning by appending content hash to filenames: unicorn.css => unicorn-d41d8cd98f.css
"gulp-htmlmin": "*", // 压缩html代码
"gulp-jade": "*", // jade
"gulp-stylus": "*", // stylus
"gulp-sourcemaps", // 处理JS时,生成SourceMap
"gulp-mocha": "*", // 测试框架
"chai": "*",
"jscov": "*",
"del", //Delete files/folders using globs
"gulp-changed": "*" // 有变化的才操作,没变化的就跳过,可进一步优化效率
}
####gulp使用中的坑–流不兼容 使用gulp时,你可能会陷入“流不兼容”的问题。这主要是因为常规流和Vinyl文件对象有差异,或是使用了仅支持buffer(不支持流)库的gulp插件与常规流不兼容。
比如说,你不能直接将常规流与gulp和(或)gulp插件相连。我们创建一个可读流,并尝试使用gulp-uglify和gulp-rename来进行转换,将最后得到的内容交给gulp.dest()。下面就是个错误的例子:
var uglify = require('gulp-uglify'),
rename = require('gulp-rename');
gulp.task('bundle', function() {
return fs.createReadStream('app.js')
.pipe(uglify())
.pipe(rename('bundle.min.js'))
.pipe(gulp.dest('dist/'));
});
为什么我们不能将可读流和一个gulp插件直接相连?gulp难道不就是一个基于流的构建系统吗?是的,但上面的例子忽视了一个事实,gulp插件期望的输入是Vinyl文件对象。你不能直接将一个可读流与一个以Vinyl文件对象作为输入的函数(插件)相连。
####Vinyl文件对象 gulp使用了vinyl-fs,它实现了gulp.src()和gulp.dest()方法。vinyl-fs使用vinyl文件对象——一种“虚拟文件格式”。如果我们需要将gulp和(或)gulp插件与常规的可读流一起使用,我们就需要先把可读流转换为vinyl。
使用vinyl-source-stream是个不错的选择,如下:
var source = require('vinyl-source-stream'),
marked = require('gulp-marked');
fs.createReadStream('*.md')
.pipe(source())
.pipe(marked())
.pipe(gulp.dest('dist/'));
另外一个例子首先通过browserify封装并最终将其转换为一个vinyl流:
var browserify = require('browserify'),
uglify = require('gulp-uglify'),
source = require('vinyl-source-stream');
gulp.task('bundle', function() {
return browserify('./src/app.js')
.bundle()
.pipe(source(‘bundle.min.js))
.pipe(uglify())
.pipe(gulp.dest('dist/'));
});
哎呦不错哦。注意我们不再需要使用gulp-rename了,因为vinyl-source-stream创建了一个拥有指定文件名的vinyl文件实例(这样gulp.dest方法将使用这个文件名)
####流和buffer
既然你有兴趣使用gulp,这篇文章假设你已经了解了流的基础知识。无论是buffer还是流,vinyl的虚拟文件都能包含在内。使用常规可读流时,你可以监听data事件来检测数据碎片的到来:
fs.createReadStream('/usr/share/dict/words').on('data', function(chunk) {
console.log('Read %d bytes of data', chunk.length);
});
> Read 65536 bytes of data
> Read 65536 bytes of data
> Read 65536 bytes of data
> Read 65536 bytes of data
> ...
不同的是,使用gulp.src()会将转换成buffer的vinyl文件对象重新写入到流中。也就是说,你获得的不再是数据碎片,而是将内容转换成buffer后的(虚拟)文件。vinyl文件格式拥有一个属性来表示里面是buffer还是流,gulp默认使用buffer:
gulp.src('/usr/share/dict/words').on('data', function(file) {
console.log('Read %d bytes of data', file.contents.length);
});
> Read 2493109 bytes of data
这个例子说明了在文件被完整加入到流之前数据会被转换成buffer。
####从流到buffer
由于所需的输入(输出)流和gulp插件不尽相同,你可能需要将流转换成buffer(反之亦然)。之前已经有过介绍,大多数插件使用buffer(尽管他们的一部分也支持流)。比如gulp-uglify和gulp-traceur。你可以通过gulp-buffer来转换成buffer:
var source = require('vinyl-source-stream'),
buffer = require('gulp-buffer'),
uglify = require('gulp-uglify');
fs.createReadStream('./src/app.js')
.pipe(source('app.min.js'))
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest('dist/'));
####将buffer转换为流
你也可以使用gulp-streamify或gulp-stream将一个使用buffer的插件的输出转化为一个可读流。这样处理之后,跟在使用buffer的插件后面的(只能)使用流的插件也能正常工作了。
var wrap = require('gulp-wrap'),
streamify = require('gulp-streamify'),
uglify = require('gulp-uglify'),
gzip = require('gulp-gzip');
gulp.src('app.js', {buffer: false})
.pipe(wrap('(function(){<%= contents %>}());'))
.pipe(streamify(uglify()))
.pipe(gulp.dest('build'))
.pipe(gzip())
.pipe(gulp.dest('build'));
###不是所有事都需要插件
虽然已经有很多使用且方便的插件,很多任务以及转换可以不使用插件而轻易完成。插件会带来一些问题,你需要依赖一个额外的npm模块,一个插件接口和(反应迟钝?)的维护者,等等。如果一个任务可以不使用插件而使用原生模块就能轻易完成,绝大多数情况下,都建议不要使用插件。能够理解上面所说的概念,并能够在所处的情况下做出正确的决定,这点非常重要。
####安装sass
到项目文件夹内,然后输入:
npm i --save-dev gulp-sass
注意,gulp-sass 依赖于 libsass ,这是一个 C++ 的包,需要在本地编译,所以要确保本地 Mac 机器上是有 Xcode 的。 装好之后,gulpfile.js 中写下面的内容
var gulp = require('gulp');
var sass = require('gulp-sass');
gulp.task('sass', function(){
gulp.src('main.scss')
.pipe(sass())
.pipe(gulp.dest('css'));
});
####强大的 gulp 管道线
比如,还可以扩展添加 gulp-autoprefixer 进来
$ npm i gulp-autoprefixer -D
然后到gulpfile.js中添加
var prefix = require('gulp-autoprefixer');
.pipe(prefix())
这样,在输出的 main.css 中,就可以看到 vendor prefix 已经自动添加了。
####gulp watch
var gulp = require('gulp');
var sass = require('gulp-sass');
var prefix = require('gulp-autoprefixer');
gulp.task('sass', function(){
gulp.src('styles/main.scss')
.pipe(sass())
.pipe(prefix())
.pipe(gulp.dest('css'));
});
gulp.task('watch', function(){
gulp.watch('styles/*.scss', ['sass']);
});
####定制自己的色盘 google material 调色盘
####主色
主色要至少占据页面 30% 的区域,可以配合黑白灰,共同构成页面的大背景。
####强调色
用来凸显一些重要操作或内容。
####dark/light 背景色
700 的深色背景可以用来做状态栏,突出一些比较重要的操作,300 的浅色区域可以用来放次要信息。参考:Google 官方的 Material 色盘使用说明 。
####主从文字颜色
要体现内容层次,一方面可以用字体大小,但是如果配上主从字体颜色,效果会更好。 关于颜色使用,官方是给了 spec 的。 用到的字体设置:
font-family: "Helvetica Neue", "Segoe UI", Helvetica, Arial, "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
###stage2
对项目进行组件化重构,突出一个概念:组件化。会用到 react 和 webpack 。
####资源 国内淘宝npm镜像
####React
####安装 npm i install -g ####在项目中引用react
var React = require('react');
var Books = React.createClass({
render:function(){
return(
<div className="books clearfix">
<div className="book"><img src="images/github.jpg" alt className="cover" /></div>
<div className="book"><img src="images/tealeaf-http.jpg" alt className="cover" /></div>
<div className="book"><img src="images/tlcl-book.jpg" alt className="cover" /></div>
</div>
)
}
});
module.exports = Books; //将Books封装成node模块,以便外部调用;
####webpack
到 webpack 官网 ,可以看到介绍很简单,是一个 module bundler (不管有多少个输入文件,输出只有一个bundle.js)。
- 提供原生js不支持的require()功能。
-
提供loader。 #####安装
npm install webpack -g
#####配置webpack.config.js
module.exports = {
entry: "./entry.js",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
//compile jsx
{ test: /\.js$/, loader: "babel" },
//compile sass
{ test: /\.scss$/, loader: "style!css!autoprefixer!sass" }
]
}
};
创建入口文件entry.js
var React = require('react');
var App = require('./components/App.js');
require('./styles/main.scss');
React.render(<App /> , document.getElementById('app'));
然后再命令行中输入webpack命令
$ wbpack
#####常用loader
- bable-loader 用来compile jsx文件;
- style-loader
- css-loader
- sass-loader
- autoprefixer-loader
#####监视sass文件变化 webpack –watch