
[前端工程師都有用哪些比較靠譜的小工具?](https://www.zhihu.com/question/20241338)
[大公司或專業團隊目前流行的前端工具有什么?](https://www.zhihu.com/question/28638304?sort=created)
---
[TOC]
[頂級的JavaScript框架、庫、工具及其使用](http://blog.csdn.net/powertoolsteam/article/details/52765058)
# 前端工作流程
## 目錄結構
首先來說說 基本結構吧
開發時的目錄對比:

相比之下:個人覺得左側適合每個目錄本身相對獨立的項目 ,更好!
類似這樣的結構:
~~~
src
|--- ccomponent
|--- tab
|--- main.js
|--- main.tpl
|--- main.css
|--- img //圖片目錄
~~~
開發和部署時目錄結構-參考:
~~~
/*-------單頁面項目結構--------*/
|---build/ 自動化構建腳本
|---dist/ 默認發布根目錄
index.html 訪問地址http://localhost
|---static/ 資源目錄
|---common.js
|---common.css
|---default.js
|---default.css
|---other.js
|---other.css
|---other/ 訪問地址http://localhost/other
|---index.html
|---src/ 應用源碼
|---assets/ 資源目錄
|---imgs/ 公共圖片
|---font/ 字體圖標
|---config.js 公共配置(name , logo...)
|---global.less 公共樣式(reset...)
|---lib.js 各種框架(vue, vue-router, vux, jquery, fastclick...)
|---components 公共組件
|---index-other.vue
|---apps 單頁面應用目錄
|---default
|---main.js 當前應用入口
|---config.js 當前應用配置
|---app.vue
!---page/
|---page1.vue 路由頁面組件
|---page2.vue
|---vuex/ 應用狀態管理
|---store.js
|---mutation-type.js
|---mutations.js
|---actions.js
|---getters.js
|---other
|---同index
|---template.html 生成html模板
/*--------多頁面項目結構--------*/
├── app
│ ├── controller
│ │ ├── test
│ │ │ └── test.js
│ ├── extend
│ ├── lib
│ ├── middleware
│ ├── mocks
│ ├── proxy
│ ├── router.js
│ ├── view
│ │ ├── about // 服務器編譯的jsbundle文件
│ │ │ └── about.js
│ │ ├── home
│ │ │ └── home.js // 服務器編譯的jsbundle文件
│ │ └── layout // 用于根據指定的layout生成對應的html頁面, 用于服務器渲染失敗時,采用客戶端渲染
│ │ └── layout.html
│ └── web // 前端工程目錄
│ ├── asset // 存放公共js,css資源
│ ├── framework // 前端公共庫和第三方庫
│ │ ├── fastclick
│ │ │ └── fastclick.js
│ │ ├── sdk
│ │ │ ├── sdk.js
│ │ ├── storage
│ │ │ └── storage.js
│ │ └── vue // 與vue相關的公開代碼
│ │ ├── app.js // 前后端調用入口, 默認引入componet/directive/filter
│ │ ├── component.js // 組件入口, 可以增加component目錄,類似下面的directive
│ │ ├── directive // directive 目錄,存放各種directive組件
│ │ ├── directive.js // directive引用入口
│ │ └── filter.js // filter引用入口
│ ├── page // 前端頁面和webpack構建目錄, 也就是webpack打包配置entryDir
│ │ ├── home // 每個頁面遵循目錄名, js文件名, scss文件名, vue文件名相同
│ │ │ ├── home.js // 服務器render渲染時, 傳入 render('home/home.js', data)
│ │ │ ├── home.scss
│ │ │ ├── home.vue
│ │ │ ├── images // 頁面自有圖片,公共圖片和css放到asset下面
│ │ │ │ └── icon_more.png
│ │ │ └── w-week // 頁面自有組件,公共組件放到widget下面
│ │ │ ├── w-week.scss
│ │ │ └── w-week.vue
│ │ └── test // 每個頁面遵循目錄名, js文件名, scss文件名, vue文件名相同
│ │ ├── test.js // 服務器render渲染時, 傳入 render('test/test.js', data)
│ │ └── test.vue
│ ├── store // 引入vuex 的基本規范, 可以分模塊
│ │ ├── app
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ ├── mutation-type.js
│ │ │ └── mutations.js
│ │ └── store.js
│ └── component // 公共業務組件, 比如loading, toast等, 遵循目錄名, js文件名, scss文件名, vue文件名相同
│ ├── loading
│ │ ├── loading.scss
│ │ └── loading.vue
│ ├── test
│ │ ├── test.vue
│ │ └── test.scss
│ └── toast
│ ├── toast.scss
│ └── toast.vue
├── build // webpack 自定義配置入口, 會與默認配置進行合并(看似這么多,其實這里只是占個位說明一下)
│ ├── base
│ │ └── index.js // 公共配置
│ ├── client // 客戶端webpack編譯配置
│ │ ├── dev.js
│ │ ├── prod.js
│ │ └── index.js
│ ├── server // 服務端webpack編譯配置
│ │ ├── dev.js
│ │ ├── prod.js
│ │ └── index.js
│ └── index.js
├── config
│ ├── config.default.js
│ ├── config.local.js
│ ├── config.prod.js
│ ├── config.test.js
│ └── plugin.js
├── doc
├── index.js
├── public // webpack編譯目錄結構, render文件查找目錄
│ ├── manifest.json // 資源依賴表
│ ├── static
│ │ ├── css
│ │ │ ├── home
│ │ │ │ ├── home.07012d33.css
│ │ │ └── test
│ │ │ ├── test.4bbb32ce.css
│ │ ├── img
│ │ │ ├── change_top.4735c57.png
│ │ │ └── intro.0e66266.png
│ ├── test
│ │ └── test.js
│ └── vendor.js // 生成的公共打包庫
~~~
## DOM操作
首推原生,如果嫌麻煩,可以`jQuery`,`ZeptoJs`等!
## 前端模塊化
seajs(CMD規范)和requirejs(AMD規范)就是解決模塊化問題比較好的兩個庫。
推薦[requirejs](http://www.requirejs.org/)。
## 實用的前端工具:
### Git
```js
.gitigonre //你想要忽略的文件或者目錄
/mtk/ //過濾整個文件夾
*.zip //過濾所有.zip文件
/mtk/do.c //過濾某個具體文件
.gitattribute //指定文件的對比合并方式(常用非文本文件)
// refs:https://git-scm.com/book/zh/v1/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-Git%E5%B1%9E%E6%80%A7
```
### [npm](https://www.npmjs.com/)
#### npm VS Bower
Bower是Witter推出的包管理器,它與NPM區別在于:
在實際項目中,npm和Bower都會被運用。并且Bower的安裝和升級全都依賴于npm,使用如許下命令就可以全局安裝Bower:
~~~
npm install -g bower
~~~
之后你就可以使用
~~~
bower install *
~~~
1. npm主要運用于Node.js項目的內部依賴包管理,安裝的模塊位于項目根目錄下的node_module文件夾內。
2. Bower大部分情況下用于前端開發,bower 能依據配置文件自動下載相關依賴,非常方便,這也是推薦使用 bower 的原因之一,對于CSS/js模塊等內容進行依賴。依賴的下載目錄結構可以自定義。
為何不用npm一個工具對前后端進行統一的依賴管理呢?

實際上,npm設計之初就采用了的是嵌套的依賴關系樹,這種方式顯然對前端不好;而Bower則采用扁平的依賴關系管理方式,使用上更符合前端開發習慣。
不過,現在越來越多出名的JS依賴包可以跨前后端共同使用,所以Bower和npm上面有不少可以通用的內容。實際項目中,我們可以采用npm作為于后端;Bower作用于前端。讓前后端共用開發語言的同時,不同端開發工程師能夠更好的利用手上的工具提升開發效率。
具體請參考如下:
[如何安裝NPM和Bower](https://webdesign.tutsplus.com/tutorials/how-to-install-npm-and-bower--cms-23451)
http://stackoverflow.com/questions/18641899/what-is-the-difference-between-bower-and-npm
[npm、bower、jamjs 等包管理器,哪個比較好用?](https://www.zhihu.com/question/24414899)
#### 安裝
**macOS**
通過 Homebrew 包管理工具安裝 Yarn。 如果你還未安裝 Node.js,Homebrew 會自動為你安裝。
~~~
brew install yarn
~~~
**Windows**下通過 Chocolatey 安裝:
Chocolatey 是一個針對 Windows 平臺的包管理工具:
~~~
choco install yarn
~~~
### bower(推薦使用npm,Duo)
在Web開發中,我們經常會用到bootstrap, JQuery這些CSS, 前端javascript框架。 如何在我們的項目中管理Web前端框架? 包括引入,檢查依賴, 更新,刪除?這將會用到另外一個很好的工具: [Bower](http://Bower.io)。
初始化當前工程的bower,`bower init`,此操作會在當前目錄下生成bower.json文件.
試著在項目文件夾下,下載`jquery` 和 `underscore`
`bower install jquery underscore`
然后就可以看到項目文件夾下多了`bower_components`(默認目錄),再就是兩個插件包了

初步這樣也就行了,但是`/bower_components`這個目錄有點讓人不習慣,我想把東西下載到我指定的目錄里。
需要加一個`.bowerrc`文件,已經存在就修改。注意,不需要名字什么的,只要新增一個`.bowerrc`就行了。
提示:用`cmd`命令創建文件如下
`type null >.bowerrc`
由于目錄變更,我們需要修改bower的路徑,bower的路徑在`.bowerrrc`文件中,將其內容改為:
```JSON
{
"directory": "app/public/bower_components"
}
```
Available configuration variables, in `.bowerrc`. format:
```js
{
"cwd": "~/my-project",
"directory": "bower_components",
"registry": "https://bower.herokuapp.com",
"shorthand-resolver": "git://github.com/{{owner}}/{{package}}.git",
"proxy": "http://proxy.local",
"https-proxy": "https://proxy.local",
"ca": "/var/certificate.pem",
"color": true,
"timeout": 60000,
"strict-ssl": true,
"storage": {
"packages" : "~/.bower/packages",
"registry" : "~/.bower/registry",
"links" : "~/.bower/links"
},
"interactive": true,
"resolvers": [
"mercurial-bower-resolver"
],
"shallowCloneHosts": [
"myGitHost.example.com"
],
"scripts": {
"preinstall": "",
"postinstall": "",
"preuninstall": ""
},
"ignoredDependencies": [
"jquery"
]
}
// 摘自:https://github.com/bower/spec/blob/master/config.md
```
你可以通過`bower init`初始化一個`bower.json`文件來管理依賴。你可以通過通過根目錄的`.bowerrc`來配置bower。
### Yeoman
[Yeoman](http://yeoman.io/)是一個腳手架工具,Yeoman包括了三個部分yo(腳手架工具)、grunt/gulp(構建工具)、npm/bower(包管理器).聽說gulp更容易上手,可以方便的為你產生一個初始項目, 標準的文件夾布局, 標準的包依賴, 初始的頁面例子。 Yeoman提供樂意一些generators, 用來生成不同的項目。
這些generators有些由官方提供,有些由社區提供。
再比如想要構建angularjs項目,可以這樣做:
先安裝`generator-angular`庫,在命令行窗口輸入 `npm install –g generator-angular`
再輸入命令`yo angular`。在執行`yo angular`(或其他項目)命令后,工程全部構建完后,命令行會預編譯測試,可能比較慢,這個時候如果不想等待可以按`ctrl+c`退出。
當然每個人可能的需要不一致,那么你可以手動修改生成的項目結構。
### Gulp前端任務打包工具
http://www.gulpjs.com.cn
`gulp`是一個前端構建工具,與gruntjs相比,gulpjs無需寫一大堆繁雜的配置參數,API也非常簡單,學習起來很容易,而且gulpjs使用的是nodejs中stream來讀取和操作數據,其速度更快。如果你還沒有使用過前端構建工具,或者覺得gruntjs太難用的話,那就嘗試一下gulp吧。
在`gulp`中這個文件叫做`gulpfile.js`。新建一個文件名為`gulpfile.js`的文件,然后放到你的項目目錄中。
此時我們的目錄結構是這樣子的:
~~~
├── gulpfile.js
├── node_modules
│ └── gulp
└── package.json
~~~
```js
/*
//導入工具包 require('node_modules里對應模塊')
var gulp = require('gulp'), //本地安裝gulp所用到的地方
less = require('gulp-less');
//定義一個testLess任務(自定義任務名稱)
gulp.task('testLess', function () {
gulp.src('src/less/index.less') //該任務針對的文件
.pipe(less()) //該任務調用的模塊
.pipe(gulp.dest('src/css')); //將會在src/css下生成index.css
});
gulp.task('default',['testLess', 'elseTask']); //定義默認任務 elseTask為其他任務,該示例沒有定義elseTask任務
//gulp.task(name[, deps], fn) 定義任務 name:任務名稱 deps:依賴任務名稱 fn:回調函數
//gulp.src(globs[, options]) 執行任務處理的文件 globs:處理的文件路徑(字符串或者字符串數組)
//gulp.dest(path[, options]) 處理完后文件生成路徑
*/
// generated on 2016-08-26 using generator-webapp 2.1.0
const gulp = require('gulp');
//可以批量require package.json中的devDependencies插件,不必一個一個導入了
const gulpLoadPlugins = require('gulp-load-plugins');
// 瀏覽器自動刷新插件
const browserSync = require('browser-sync');
//刪除文件和文件夾
const del = require('del');
//wiredep解決了bower前端庫引入進html的問題
const wiredep = require('wiredep').stream;
// 本地開發代理跨域請求用的插件
const proxyMiddleware = require('http-proxy-middleware');
const $ = gulpLoadPlugins();
const reload = browserSync.reload;
// 定義proxy規則,供下面創建服務使用,以/service/開頭的代理到target域名下
const proxy= proxyMiddleware(['/service/'],{target:'http://xxx.xxxx.com',changeOrigin: true});
// 編譯sass
gulp.task('styles', () => {
return gulp.src('app/styles/*.scss')
//plumber 是一個錯誤處理插件,當出現錯誤時,不會立即卡主,而是進入 plumber,防止程序運行終止。plumber可以阻止 gulp 插件發生錯誤導致進程退出并輸出錯誤日志。
.pipe($.plumber())
//sourcemaps 是用來生成映射文件的一個插件,map 文件記錄了從 Sass 編譯成 CSS 的過程中,每一行的 Sass 代碼對應哪一行的 CSS 代碼。在scss編譯過程中,添加映射關系,可以方便調試;
//在文件流中需要兩條語句:
//***plugins.sourcemaps.init()
//如果要輸出sourcemaps文件的話,可以在write(path)添加路徑;
//***plugins.sourcemaps.write()
.pipe($.sourcemaps.init())
//sass 是核心的編譯 Sass 的插件,指定了輸出格式 expanded,precision 指定了當輸出十進制數字時,使用多少位的精度,然后指定了路徑和錯誤日志。
//嵌套輸出方式 nested
// 展開輸出方式 expanded
// 緊湊輸出方式 compact
// 壓縮輸出方式 compressed
.pipe($.sass.sync({
outputStyle: 'expanded',
precision: 10,
includePaths: ['.']
}).on('error', $.sass.logError))
//添加瀏覽器前綴
.pipe($.autoprefixer({browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']}))
.pipe($.sourcemaps.write())
// .tmp 臨時目錄,后面還會有一個目錄是 dist 目錄,試想一下,如果我們編譯了 BootStrap 而在 HTML 中沒有引用,那編譯來還有必要嗎?所以說,.tmp 作為臨時目錄,它可以存放被編譯后的文件,但是不一定會被引用。被真正引用的文件才是真正有用的文件,我們將它放到 dist 目錄。所以接下來的 HTML 處理就是檢查一下有哪些 CSS 和 JS 被引用了,可以將它們合并,然后將新的文件放到 dist 并更新它的引用路徑。
.pipe(gulp.dest('.tmp/styles'))
.pipe(reload({stream: true}));
});
// 編譯js
gulp.task('scripts', () => {
return gulp.src('app/scripts/**/*.js')
.pipe($.plumber())
.pipe($.sourcemaps.init())
.pipe($.babel())
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest('.tmp/scripts'))
.pipe(reload({stream: true}));
});
function lint(files, options) {
return gulp.src(files)
.pipe(reload({stream: true, once: true}))
.pipe($.eslint(options))
.pipe($.eslint.format())
.pipe($.if(!browserSync.active, $.eslint.failAfterError()));
}
gulp.task('lint', () => {
return lint('app/scripts/**/*.js', {
fix: true
})
.pipe(gulp.dest('app/scripts'));
});
gulp.task('lint:test', () => {
return lint('test/spec/**/*.js', {
fix: true,
env: {
mocha: true
}
})
.pipe(gulp.dest('test/spec/**/*.js'));
});
// 編譯html
gulp.task('html', ['styles', 'scripts'], () => {
return gulp.src('app/*.html')
//useref 這個插件,它可以檢測 HTML 中引用的 CSS 和 JS,可以執行合并和壓縮,然后更新新的路徑。
.pipe($.useref({searchPath: ['.tmp', 'app', '.']}))
.pipe($.if('*.js', $.uglify()))
.pipe($.if('*.css', $.cssnano({safe: true, autoprefixer: false})))
// options = {
// removeComments: true, //清除HTML注釋
// collapseWhitespace: true, //壓縮HTML
// collapseBooleanAttributes: true, //省略布爾屬性的值 <input checked="true"/> ==> <input checked />
// removeEmptyAttributes: true, //刪除所有空格作屬性值 <input id="" /> ==> <input />
// removeScriptTypeAttributes: true, //刪除<script>的type="text/javascript"
// removeStyleLinkTypeAttributes: true, //刪除<style>和<link>的type="text/css"
// minifyJS: true, //壓縮頁面JS
// minifyCSS: true //壓縮頁面CSS
// };
.pipe($.if('*.html', $.htmlmin({collapseWhitespace: true})))
//替換成線上路徑
.pipe($.replace(/\"images\//g, '"statics/images/'))
.pipe(gulp.dest('dist'));
});
gulp.task('images', () => {
return gulp.src('app/images/**/*')
//只壓縮修改的圖片,沒壓縮的從緩存文件讀取
//optimizationLevel: 5, //類型:Number 默認:3 取值范圍:0-7(優化等級)
// progressive: true, //類型:Boolean 默認:false 無損壓縮jpg圖片
// interlaced: true, //類型:Boolean 默認:false 隔行掃描gif進行渲染
// multipass: true //類型:Boolean 默認:false 多次優化svg直到完全優化
// svgoPlugins: [{removeViewBox: false}],//不要移除svg的viewbox屬性
// use: [pngquant()] //使用pngquant深度壓縮png圖片的imagemin插件
.pipe($.cache($.imagemin({
progressive: true,
interlaced: true,
// don't remove IDs from SVGs, they are often used
// as hooks for embedding and styling
svgoPlugins: [{cleanupIDs: false}]
})))
.pipe(gulp.dest('dist/images'));
});
gulp.task('fonts', () => {
return gulp.src(require('main-bower-files')('**/*.{eot,svg,ttf,woff,woff2}', function (err) {})
.concat('app/fonts/**/*'))
.pipe(gulp.dest('.tmp/fonts'))
.pipe(gulp.dest('dist/fonts'));
});
gulp.task('extras', () => {
return gulp.src([
'app/*.*',
'!app/*.html'
], {
dot: true
}).pipe(gulp.dest('dist'));
});
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));
gulp.task('serve', ['styles', 'scripts', 'fonts'], () => {
browserSync({
notify: false,
port: 9000,
server: {
baseDir: ['.tmp', 'app'],
routes: {
'/bower_components': 'bower_components'
},
//這是代理跨域,規則上面已經定義了
middleware: [proxy]
}
});
gulp.watch([
'app/*.html',
'app/images/**/*',
'.tmp/fonts/**/*'
]).on('change', reload);
gulp.watch('app/styles/**/*.scss', ['styles']);
gulp.watch('app/scripts/**/*.js', ['scripts']);
gulp.watch('app/fonts/**/*', ['fonts']);
gulp.watch('bower.json', ['wiredep', 'fonts']);
});
gulp.task('serve:dist', () => {
browserSync({
notify: false,
port: 9000,
server: {
baseDir: ['dist']
}
});
});
gulp.task('serve:test', ['scripts'], () => {
browserSync({
notify: false,
port: 9000,
ui: false,
server: {
baseDir: 'test',
routes: {
'/scripts': '.tmp/scripts',
'/bower_components': 'bower_components'
}
}
});
gulp.watch('app/scripts/**/*.js', ['scripts']);
gulp.watch('test/spec/**/*.js').on('change', reload);
gulp.watch('test/spec/**/*.js', ['lint:test']);
});
// inject bower components
gulp.task('wiredep', () => {
gulp.src('app/styles/*.scss')
.pipe(wiredep({
ignorePath: /^(\.\.\/)+/
}))
.pipe(gulp.dest('app/styles'));
gulp.src('app/*.html')
.pipe(wiredep({
exclude: ['bootstrap-sass'],
ignorePath: /^(\.\.\/)*\.\./
}))
.pipe(gulp.dest('app'));
});
//執行build之前先執行數組列表里的任務
gulp.task('build', ['lint', 'html', 'images', 'fonts', 'extras'], () => {
return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
});
//gulp==gulp default 默認執行的任務
gulp.task('default', ['clean'], () => {
gulp.start('build');
});
```
### Grunt
一個Javascript Task Runner(Javascript任務運行器),其基于NodeJS,可用于自動化構建、測試、生成文檔的項目管理工具
Grunt.js并不是僅僅是構建工具,實際上他只是任務運行器,管理每個子任務的自動化運行,我們還能使用他做更多東西。
`Grunt`,被稱為js世界的構建工具,相比于 grunt 的頻繁 IO 操作,gulp 的流操作,能更快地更便捷地完成構建工作,使得它漸漸被`gulp`所超越。所以推薦使用gulp進行前端繁瑣的構建。
它需要Gruntfile.js作為主文件,用于定義任務,以及任務組的執行順序等。
以下為一份樣板文件(復雜起來不忍直視):
```js
/*********************
說明:文件結構基于 HTML5Boilerplate:
+ index.html
- css
+ main.css
- js
- vendor
+ main.js
+ img/
***************************/
/*global module:false*/
module.exports = function (grunt) {
'use strict';
grunt.initConfig({
csslint: {
/* 檢查 CSS 語法 */
src: ['css/**/*.css']
},
jshint: {
/* 檢查 js 語法 */
all: ['Gruntfile.js', 'js/main.js', 'js/lib/*.js']
},
imagemin: {
/* 壓縮優化圖片大小 */
dist: {
options: {
optimizationLevel: 3
},
files: [
{
expand: true,
cwd: 'img/',
src: ['**/*.{png,jpg,jpeg}'], // 優化 img 目錄下所有 png/jpg/jpeg 圖片
dest: 'img/' // 優化后的圖片保存位置,默認覆蓋
}
]
}
},
concat: {
/* 合并 CSS 文件 */
css: {
src: ['css/normalize.min.css', 'css/cssgrids-min.css', 'css/helper.css', 'css/main.css', '...'],
/* 根據目錄下文件情況配置 */
dest: 'css/all.css'
},
js: {
src: [''],
/* 根據目錄下文件情況配置 如果可以使用 require.js/LABjs 等配置更佳 */
dest: 'js/all.js'
}
},
cssmin: {
/*壓縮 CSS 文件為 .min.css */
options: {
keepSpecialComments: 0 /* 移除 CSS 文件中的所有注釋 */
},
minify: {
expand: true,
cwd: 'css/',
src: ['all.css'],
dest: 'css/',
ext: '.min.css'
}
},
uglify: {
/* 最小化、混淆、合并 JavaScript 文件 */
target: {
files: {
'js/all.min.js': ['js/all.js']
}
},
minjs: { //最小化、混淆所有 js/ 目錄下的 JavaScript 文件
files: [{
expand: true,
cwd: 'js/',
src: ['**/*.js', '!**/*.min.js'],
dest: 'js/',
ext: '.min.js'
}]
}
},
watch: {
/* 監控文件變化并執行相應任務 */
img: {
files: ['img/**/*.{png,jpg,jpeg}'],
options: {
livereload: true
}
},
css: {
options: {
event: ['changed', 'added'],
livereload: true
},
files: ['css/**/*.css']
},
js: {
options: {
livereload: true
},
files: ['js/**/*.js']
},
html: {
options: {
livereload: true
},
files: ['*.html']
}
}
});
grunt.loadNpmTasks('grunt-contrib-csslint');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
// 定義默認任務
grunt.registerTask('default', ['csslint', 'jshint', 'imagemin', 'cssmin', 'concat', 'uglify']);
grunt.registerTask('css', ['concat:css', 'cssmin']);
grunt.registerTask('dev', ['csslint', 'jshint']);
grunt.registerTask('dest', ['imagemin', 'concat:css', 'cssmin', 'uglify:minjs']);
};
```
### PostCSS
https://github.com/postcss/postcss
#### Sass和PostCSS
因為你已經使用了Node.js來運行Gulp或Grunt和PostCSS,所以使用Sass最簡單的方法就是使用[LibSass](https://github.com/sass/LibSass/releases/tag/3.0rc1)。**而且LibSass編譯速度也要比Ruby Sass快很多**。在下面的教程中,將通過[gulp-sass](https://www.npmjs.com/package/gulp-sass)或[grunt-contrib-sass](https://github.com/gruntjs/grunt-contrib-sass)模塊來部署LibSass。
#### 通過Gulp來配置
使用`npm install gulp-sass --save-dev`將`gulp-sass`模塊安裝到你的項目中。
接下來像下面一樣更新你的gulpfile.js文件:
```js
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var sass = require('gulp-sass');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
gulp.task('css', function () {
var processors = [
autoprefixer,
cssnano
];
return gulp.src('./src/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(postcss(processors))
.pipe(gulp.dest('./dest'));
});
```
修改了默認的`gulpfile.js`文件:
添加變量,加載`gulp-sass`,`autoprefixer`和`cssnano`
將autoprefixer和cssnano變量放在processors數組內
將要編譯的源文件名.css的擴展名修改為.scss
添加pipe(),.pipe(sass()...)用來處理Sass,需要確保的是**處理Sass要放在PostCSS前面**
現在我們可以寫一些測試代碼來確保Sass和PostCSS都能正常編譯。
#### 參考
http://www.w3cplus.com/PostCSS/using-postcss-together-with-sass-stylus-or-less.html
https://www.ibm.com/developerworks/cn/web/1604-postcss-css/
### JSHint (推薦使用ESLint)
JSHint默認使用用戶home目錄下的`.jshintrc`文件(json格式)作為配置文件。
[JSHint](http://www.jshint.com/)是一個強大的javascript代碼檢測工具,不僅可以幫助我們檢測到可能的代碼錯誤,也能幫助我們有效的避免編碼的錯誤。
可以在你的項目根目錄下添加一個.jshintrc文件,JSHint會在檢測文件時從文件所在目錄往上找,直到找到jshintrc文件為止。
模板內容如下:
```js
{
"curly": true, // true: Require {} for every new block or scope
"eqeqeq": true, // true: Require triple equals (===) for comparison
"immed": true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
"latedef": true, // true: Require variables/functions to be defined before being used
"newcap": true, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg": true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
"sub": true, // true: Prohibit use of empty blocks
"undef": true, // true: Require all non-global variables to be declared (prevents global leaks)
"boss": true, // true: Require all defined variables be used
"eqnull": true, // true: Requires all functions run in ES5 Strict Mode
"es3": true, // {int} Max number of formal params allowed per function
"node": true, // {int} Max depth of nested blocks (within functions)
"-W117": true // {int} Max number statements per function
}
```
-----
### ESLint
http://eslint.cn/
[詳解 ESLint 規則,規范你的代碼](https://segmentfault.com/a/1190000006194584)
可組裝的JavaScript和JSX檢查工具
**.eslintignore**
引入三方js庫,結果不符合eslint規范,可以在.eslintignore文件中添加要eslint忽視的文件路徑就行了
例如:
~~~
build/*.js
config/*.js
~~~
**規則定義**
ESLint 支持幾種格式的配置文件,如果同一個目錄下有多個配置文件,ESLint 只會使用一個。優先級順序如下:
~~~
JavaScript - 使用 .eslintrc.js 然后輸出一個配置對象。
YAML - 使用 .eslintrc.yaml 或 .eslintrc.yml 去定義配置的結構。
JSON -使用 .eslintrc.json 去定義配置的結構,ESLint 的 JSON 文件允許 JavaScript 風格的注釋。
Deprecated -使用 .eslintrc,可以使 JSON 也可以是 YAML。
package.json - 在 package.json 里創建一個 eslintConfig屬性,在那里定義你的配置。
~~~
### [Duo](http://duojs.org/)
Duo是在Component的基礎上開發的,語法和配置文件基本通用,并且借鑒了Browserify和Go語言的一些特點,相當地強大和好用。
### [browserify](http://w3cbus.com/tool/browserify.html)
如果我們需要讓node的一些模塊在瀏覽器里也能很好的用起來,哇~當然你首先需要知道node
1. 通過[browserify](http://browserify.org/)的封裝,可以直接讓node程序運行在瀏覽器中。
2. browserify其實是把原node的程序自動重新改寫了,把所有的依賴都壓縮到1個文件中,變成一個純的js文件,在瀏覽器中運行。
3. browserify封裝是自動完成的,我們只需要執行一條命令就可以了,
#### 使用
[通過 npm使用jQuery 插件](http://www.css88.com/archives/5537)
Xee:由于`browserify`打出的包可能會很大,所以總的來說前端一般都是使用`bower`(但是為了肯定npm會越來越好,還有Duo啊!)。畢竟很多庫(jquery)原本就是支持瀏覽器端的。為何還要脫褲子放屁呢?
### browser-sync
如果我們做頁面需要實時看到效果,加入多個顯示器有了,那么我們修改完了還要手動刷新,肯定我們不愿做,[browser-sync](http://browser-sync.io)是一個基于nodejs的一個插件,用于前端調試,好處是該插件可以同步一個網段內的所有頁面,比方說,假如你要做一個響應式的網頁的時候,該插件就可以節省非常多的時候,例如,你要調試iPhone5,iphone6,iPhone6s,ipad,三星等設備的分辨率。
## CSS預處理器
### SCSS
推薦 [Sass](http://sass-lang.com/),搭配[Compass](http://compass-style.org/).
Sass本身只是一個編譯器,Compass在它的基礎上,封裝了一系列有用的模塊和模板,補充Sass的功能。它們之間的關系,有點像Javascript和jQuery、Ruby和Rails、python和Django的關系。Compass是用Ruby語言開發的,所以安裝它之前,必須安裝Ruby。
從 Sass 3開始**被稱為 “SCSS”( 時髦的css(Sassy CSS)),它是css3語法的的拓展級,就是說每一個語法正確的CSS3文件也是合法的SCSS文件,SCSS文件使用.scss作為拓展名。
## PostCSS
適用于普通的CSS而不使用特定的語法,由于它在CSS編譯后運行。
因為你已經使用了Node.js來運行Gulp或Grunt和PostCSS,所以使用Sass最簡單的方法就是使用[LibSass](https://github.com/sass/LibSass/releases)。而且LibSass編譯速度也要比Ruby Sass快很多。下面,將通過gulp-sass`模塊來部署LibSass。
**通過Gulp來配置**
使用`npm install gulp-sass --save-dev`將`gulp-sass`模塊安裝到你的項目中。
接下來像下面一樣更新你的gulpfile.js文件:
```js
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var sass = require('gulp-sass');
var autoprefixer = require('autoprefixer');
var cssnano = require('cssnano');
gulp.task('css', function () {
var processors = [
autoprefixer,
cssnano
];
return gulp.src('./src/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(postcss(processors))
.pipe(gulp.dest('./dest'));
});
```
修改了默認的`gulpfile.js`文件:
添加變量,加載`gulp-sass`,`autoprefixer`和`cssnano`
將autoprefixer和cssnano變量放在processors數組內
將要編譯的源文件名.css的擴展名修改為.scss
添加`pipe(),.pipe(sass()...)`用來處理Sass,需要確保的是處理Sass要放在PostCSS前面
現在我們可以寫一些測試代碼來確保Sass和PostCSS都能正常編譯。
**測試預處理器**
將src/style.css文件重命名為src/style.scss,并且在文件中添加下面的測試代碼:
```
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
```
運行gulp css,并且看看dest/中有沒有一個新文件style.css,并且文件中的內容:
```
body {
font: 100% Helvetica, sans-serif;
color: #333; }
```
**測試PostCSS**
現在,在style.scss文件中添加前面提供測試PostCSS的代碼。并且運行gulp css之后,查看dest/style.css文件:
```css
body{font:100% Helvetica,sans-serif;color:#333}.css_nano,.css_nano+p,[class*=css_nano]{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin:1rem 2.5rem 2rem 1.5rem;font-weight:400;padding:1.75rem;width:46.5rem}
```
## JavaScript預處理器
### Babel
http://babeljs.io/
### TypeScript
# HTML處理器
## Pug
https://pugjs.org
https://pugjs.org/api/getting-started.html
## [PostHTML 后處理器](https://github.com/posthtml/posthtml)
## 測試
CasperJS 感覺上mocha,jasmine更偏向于本地純js調試,
而CasperJS這基于PhantomJS的工具則更適合瀏覽器調試。
## JS前端模板引擎
JavaScript 模板引擎作為數據與界面分離工作中最重要一環,越來越受開發者關注,從而出現在各大型網站中;模版解釋的好處在于不再需要再寫大量而不清晰的 JS 插入 dom 結構語句。那么他們各自性能怎么樣?

### 什么是模版引擎
~~~
// 模板文件:
var template = '<p>Hello,my name is <%name%>. I am <%age%> years old.</p>';
// 數據:
var data ={
name:'zyn',
age:31
}
// 模板引擎:
var TemplateEngine = function (tpl,data){
var regex = /<%([^%>]+)?%>/g;
while(match = regex.exec(tpl)){
tpl = tpl.replace(match[0],data[match[1]])
}
return tpl
}
// HTML文件:
var string=TemplateEngine(template,data)
document.body.innerHTML= string
~~~
> [五分鐘了解模板引擎原理,閱讀后做出自己的模板引擎](https://www.jianshu.com/p/9091e8a343e4)
> [https://www.zhihu.com/question/32524504](https://www.zhihu.com/question/32524504)
### [artTemplate](https://github.com/aui/artTemplate)
騰訊出品
### mustache
[Mustache](https://github.com/janl/mustache.js) 是一個logic-less(無邏輯或輕邏輯)語法模板。可以用于組織HTML、配置文件、源代碼在內的任何東西。Mustache使用JavaScript對象的值,用來擴展模板代碼中的大括號標簽。
### [doT](https://github.com/olado/doT)
中文:http://dotjs.cn/
最快和簡潔的JavaScript模板引擎,同時用于Node.js和瀏覽器。
### [HandleBars.js](http://handlebarsjs.com/)
http://www.ghostchina.com/introducing-the-handlebars-js-templating-engine/ 。
### Nunjucks
[Nunjucks](https://github.com/mozilla/nunjucks) 是一套富功能的模板引擎。模板語言功能強大,支持塊繼承、自動轉義、宏、異步控制等功能。
### 模板性能對比
通過對各模板引擎測試結果,可以看出
artTemplate,juicer與doT引擎模板整體性能要有絕對優勢;
其中 doT 引擎模板在IE與safari瀏覽器表現非常優越;
tmpl 模板引擎在IE中運行能完美勝出,但在其它瀏覽器中表現就差很多;
各個模板引擎下載地址:
artTemplate(騰訊) https://github.com/aui/artTemplate
doT:https://github.com/olado/doT
tmpl:https://github.com/BorisMoore/jquery-tmpl
handlebars:http://handlebarsjs.com/
mustache:https://github.com/janl/mustache.js
## mock數據
[永不離線的測試接口服務——justreq](https://segmentfault.com/a/1190000008275112)
## EditorConfig
[EditorConfig](http://editorconfig.org/)通過`.editorconfig`文件幫助開發人員不同的編輯器和IDE之間定義和維護一致的編碼風格。EditorConfig項目由一個文件格式定義的編碼風格和一些使編輯閱讀的文件格式和堅持定義的樣式的文本編輯器插件組成,EditorConfig文件內容容易閱讀,而且容易和版本控制系統協調工作。
```python
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8
# 4 space indentation
[*.py]
indent_style = space
indent_size = 4
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2
```
## 總結
所以在實際前端構建流程里面,你會發現以下的流程。
### 代碼優化
* LESS、SASS 自動編譯
* Autoprefixer 前綴自動補全
* 自動生成圖片 CSS 屬性,width & height
* CSS Sprite 雪碧圖合成
* JS、CSS、HTML 壓縮
* 按需加載
* 延遲加載
### 解決方案
* 項目初始化。如果你用了 yeoman 或者 HTML5 Boilerplate,你就懂我說什么
* 作用域污染。前端自帶問題。
* eslint 驗證,代碼驗證驗證
* Retina @2x & @3x 自動生成適配
* px -> rem 兼容適配方案
* 智能 WebP 解決方案
* 非覆蓋式升級,文件指紋
* CDN 文件緩存,緩存更新
* 自動化測試
* 調試和部署
- 講解 Markdown
- 示例
- SVN
- Git筆記
- github 相關
- DESIGNER'S GUIDE TO DPI
- JS 模塊化
- CommonJS、AMD、CMD、UMD、ES6
- AMD
- RequrieJS
- r.js
- 模塊化打包
- 學習Chrome DevTools
- chrome://inspect
- Chrome DevTools 之 Elements
- Chrome DevTools 之 Console
- Chrome DevTools 之 Sources
- Chrome DevTools 之 Network
- Chrome DevTools 之 Memory
- Chrome DevTools 之 Performance
- Chrome DevTools 之 Resources
- Chrome DevTools 之 Security
- Chrome DevTools 之 Audits
- 技巧
- Node.js
- 基礎知識
- package.json 詳解
- corepack
- npm
- yarn
- pnpm
- yalc
- 庫處理
- Babel
- 相關庫
- 轉譯基礎
- 插件
- AST
- Rollup
- 基礎
- 插件
- Webpack
- 詳解配置
- 實現 loader
- webpack 進階
- plugin 用法
- 輔助工具
- 解答疑惑
- 開發工具集合
- 花樣百出的打包工具
- 紛雜的構建系統
- monorepo
- 前端工作流
- 爬蟲
- 測試篇
- 綜合
- Jest
- playwright
- Puppeteer
- cypress
- webdriverIO
- TestCafe
- 其他
- 工程開發
- gulp篇
- Building With Gulp
- Sass篇
- PostCSS篇
- combo服務
- 編碼規范檢查
- 前端優化
- 優化策略
- 高性能HTML5
- 瀏覽器端性能
- 前后端分離篇
- 分離部署
- API 文檔框架
- 項目開發環境
- 基于 JWT 的 Token 認證
- 扯皮時間
- 持續集成及后續服務
- 靜態服務器搭建
- mock與調試
- browserslist
- Project Starter
- Docker
- 文檔網站生成
- ddd