ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
![Web Designer's workflow](https://box.kancloud.cn/2016-06-18_5765165a6398c.png) [前端工程师都有用哪些比较靠谱的小工具?](https://www.zhihu.com/question/20241338) [大公司或专业团队目前流行的前端工具有什么?](https://www.zhihu.com/question/28638304?sort=created) --- [TOC] [顶级的JavaScript框架、库、工具及其使用](http://blog.csdn.net/powertoolsteam/article/details/52765058) # 前端工作流程 ## 目录结构 首先来说说 基本结构吧 开发时的目录对比: ![目录结构](https://box.kancloud.cn/1fbee57a2207dce8c218261c5c81dc89_600x285.png) 相比之下:个人觉得左侧适合每个目录本身相对独立的项目 ,更好! 类似这样的结构: ~~~ 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一个工具对前后端进行统一的依赖管理呢? ![](https://box.kancloud.cn/79bc3c74221159da5c1e4fb53a727156_790x566.png) 实际上,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`(默认目录),再就是两个插件包了 ![](http://upload-images.jianshu.io/upload_images/1621531-6dc940bcca9fd503.png) 初步这样也就行了,但是`/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 结构语句。那么他们各自性能怎么样? ![](https://img.kancloud.cn/b0/c0/b0c065e7a8f76c2ebae4ad04054ce405_1135x473.png) ### 什么是模版引擎 ~~~ // 模板文件: 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 文件缓存,缓存更新 * 自动化测试 * 调试和部署