一个gulp用于开发与生产的示例
gulp是一款流行的前端构建工具,可以帮我们完成许多工作:监听文件修改、刷新浏览器、编译Less/Scss、压缩代码、添加md5、合并文件等。gulp的配置和使用特别简单,学习gulp过程中顺便写了一个小示例。
可以在GitHub上下载该示例:https://github.com/gymmer/gulp-example
准备工作
- gulp是基于Node.js的。因此需先安装Node。
- 接下来使用npm安装gulp:
sudo npm install -g gulp。-g表示安装到全局环境,可以在任何项目中使用gulp。 - 进入到项目所在目录。
- 如果项目没有基于npm,则使用
npm init创建package.json。 - 在项目中安装gulp:
npm install --save-dev gulp。--save-dev表示安装的同时更新package.json中的依赖。
项目结构
示例采用了如下的项目结构:
.
├── README.md // git的README文件
├── dist // 生产环境目录。通过gulp构建自动生成
├── gulpfile.js // gulp的配置文件
├── node_modules // node必备
├── package.json // node必备
└── src // 开发环境目录。存放项目的源代码
├── css // 样式目录。保存CSS文件和字体文件
│ ├── compile // CSS文件目录。保存less/sass编译后生成的CSS文件
│ ├── fonts // 字体文件目录。保存Font Awesome或其他字体文件
│ ├── lib // CSS文件目录。保存引用的第三方CSS文件,如Bootstrap
│ └── user // CSS文件目录。保存用户自定义的CSS文件
├── img // 图片目录。保存图片文件
├── index.html // 项目的HTML入口文件
├── js // 脚本目录。保存JavaScript文件
│ ├── lib // JS文件目录。保存引用的第三方JS文件,如jQuery
│ └── user // JS文件目录。保存用户自定义的JS文件
├── less // Less文件目录
└── sass // Sass文件目录
示例中,CSS和JS将第三方库和用户自定义文件分开存放,虽然为gulp的配置带来稍许难度,但是更有利于项目的逻辑结构。
插件一览
gulp生态圈有很多成熟的插件,示例中用到的有:
"devDependencies": {
"gulp": "^3.9.1",
"gulp-cache": "^0.4.6",
"gulp-clean": "^0.3.2",
"gulp-clean-css": "^3.3.1",
"gulp-compass": "^2.1.0",
"gulp-connect": "^5.0.0",
"gulp-htmlmin": "^3.0.0",
"gulp-imagemin": "^3.2.0",
"gulp-jshint": "^2.0.4",
"gulp-less": "^3.3.0",
"gulp-load-plugins": "^1.5.0",
"gulp-notify": "^3.0.0",
"gulp-plumber": "^1.1.0",
"gulp-rev": "^7.1.2",
"gulp-rev-collector": "^1.1.1",
"gulp-sass": "^3.1.0",
"gulp-uglify": "^2.1.2",
"jshint": "^2.9.4"
}
配置一览
gulp的配置依赖于文件gulpfile.js。这是示例配置文件一览,接下来将介绍每个插件:
'use strict';
var gulp = require('gulp');
var plugins = require('gulp-load-plugins')();
// JS代码校验。只校验用户自定义的js文件,不校验第三方js文件,如jQuery
gulp.task('jslint', function() {
return gulp.src('src/js/user/**/*.js')
.pipe(plugins.jshint())
.pipe(plugins.jshint.reporter());
});
// 监听所有文件改动:自动刷新
gulp.task('reload', function() {
return gulp.src('src/**/*')
.pipe(plugins.connect.reload());
});
// 编译less文件,并监听less文件改动:重新编译+自动刷新
gulp.task('less', function() {
return gulp.src('src/less/**/*.less')
.pipe(plugins.plumber({errorHandler: plugins.notify.onError('Error: <%= error.message %>')})) // 防止less出错,自动退出watch
.pipe(plugins.less())
.pipe(gulp.dest('src/css/compile'))
.pipe(plugins.connect.reload());
});
// 编译sass文件,并监听sass文件改动:重新编译+自动刷新
gulp.task('sass', function() {
return gulp.src('src/sass/**/*.{sass,scss}')
.pipe(plugins.plumber({errorHandler: plugins.notify.onError('Error: <%= error.message %>')})) // 防止sass出错,自动退出watch
// (1) 如果只使用 sass, 请使用sass插件:
// .pipe(plugins.sass({
// outputStyle: 'expanded' // 可选:nested (默认) | expanded | compact | compressed
// }))
// (2) 如果使用 compass, 请使用compass插件:
.pipe(plugins.compass({
css: 'src/css/compile',
sass: 'src/sass',
image: 'src/img',
style: 'expanded' // 可选:nested (默认) | expanded | compact | compressed
}))
.pipe(gulp.dest('src/css/compile'))
.pipe(plugins.connect.reload());
});
// 监听文件改动
gulp.task('watch', function() {
gulp.watch('src/**/*', ['reload']);
gulp.watch('src/less/**/*.less', ['less']);
gulp.watch('src/less/**/*.{sass,scss}', ['sass']);
});
// 运行一个服务器
gulp.task('server', function() {
plugins.connect.server({
root: 'src',
port: 8080, // Can not be 80
livereload: true
});
});
// 默认任务
gulp.task('default', function() {
gulp.run('jslint', 'reload', 'less', 'sass', 'watch', 'server');
});
// build
gulp.task('clean', function() {
return gulp.src('dist')
.pipe(plugins.clean());
});
gulp.task('build-js', function() {
return gulp.src('src/**/*.js')
.pipe(plugins.uglify()) // JS压缩
.pipe(plugins.rev()) // 添加MD5
.pipe(gulp.dest('dist')) // 保存JS文件
.pipe(plugins.rev.manifest()) // 生成MD5映射
.pipe(gulp.dest('dist/rev/js')); // 保存映射
});
gulp.task('build-css', ['less', 'sass'], function() { // 编译less/sass
return gulp.src('src/**/*.css')
.pipe(plugins.cleanCss()) // CSS压缩
.pipe(plugins.rev()) // 添加MD5
.pipe(gulp.dest('dist')) // 保存CSS文件
.pipe(plugins.rev.manifest()) // 生成MD5映射
.pipe(gulp.dest('dist/rev/css')); // 保存映射
});
gulp.task('build-html', ['build-js', 'build-css'], function() { // 依赖:需先生成映射
return gulp.src(['dist/rev/**/*.json', 'src/**/*.html'])
.pipe(plugins.revCollector()) // 根据映射,替换文件名
.pipe(plugins.htmlmin({collapseWhitespace: true})) // HTML压缩
.pipe(gulp.dest('dist')); // 保存HTML文件
});
gulp.task('build-fonts', function() {
return gulp.src('src/**/*.{eot,ttf,woff,woff2,otf}')
.pipe(gulp.dest('dist'));
});
gulp.task('build-img', function() {
return gulp.src('src/**/*.{png,jpg,gif,jpeg,svg}')
.pipe(plugins.cache(plugins.imagemin({ // 图片压缩
interlaced: true
})))
.pipe(gulp.dest('dist'));
});
gulp.task('build', ['clean'], function() {
return gulp.run('build-html', 'build-fonts', 'build-img', function() {
gulp.src('dist/rev').pipe(plugins.clean());
});
});
配置详解
通常开发环境和生产环境对项目构建的需求是不一样的。开发环境侧重于调试代码,如监听文件修改、CSS预编译等。而生产环境侧重于项目的上线与部署,如压缩代码、压缩图片、添加md5等。为此,示例定义了两项gulp任务,以满足开发与生产的不同需求。
另外,每一个gulp插件都有丰富的功能和配置,本示例的目的不在于讲解每个插件的详细用法,而在于演示如何组合使用常用插件的基本功能,完成日常开发任务。
自动加载插件 (gulp-load-plugins)
官网:https://www.npmjs.com/package/gulp-load-plugins
安装:
npm install --save-dev gulp-load-plugins
使用gulp插件的一般过程是:
- 使用npm安装在局部环境,并更新
package.json:npm install --save-dev gulp-foo-plugin - 在
gulpfile.js中加载插件:var foo = require('gulp-foo-plugin') - 在合适的地方使用插件:
gulp.src('src/*.js').pipe(foo())
如果加载太多gulp插件,gulpfile.js文件开头会有大量require代码,导致文件冗长,并且容易遗漏:
var gulp = require('gulp');
var foo = require('gulp-foo-plugin');
var boo = require('gulp-boo-plugin');
var bar = require('gulp-bar-plugin');
gulp.task('foo', function() {
return gulp.src('src/*.js')
.pipe(foo())
.pipe(gulp.dest('dist/*.js'));
});
gulp.task('boo', function() {
return gulp.src('src/*.css')
.pipe(boo())
.pipe(gulp.dest('dist/*.css'));
});
gulp.task('bar', function() {
return gulp.src('src/*.less')
.pipe(bar())
.pipe(gulp.dest('dist/*.less'));
});
而gulp-load-plugins可以避免这样的问题。
- 安装
gulp-load-plugins:npm install --save-dev gulp-load-plugins - 安装其他插件:
npm install --save-dev gulp-foo-plugin, gulp-boo-plugin, gulp-bar-plugin - 在
gulpfile.js中只需加载gulp-load-plugins:var plugins = require('gulp-load-plugins')() - 使用其他插件时,将其作为
plugins对象的方法进行调用。如下:
var gulp = require('gulp');
var plugins = require('gulp-load-plugins')();
gulp.task('foo', function() {
return gulp.src('src/*.js')
.pipe(plugins.fooPlugin())
.pipe(gulp.dest('dist/*.js'));
});
gulp.task('boo', function() {
return gulp.src('src/*.css')
.pipe(plugins.booPlugin())
.pipe(gulp.dest('dist/*.css'));
});
gulp.task('bar', function() {
return gulp.src('src/*.less')
.pipe(plugins.barPlugin())
.pipe(gulp.dest('dist/*.less'));
});
这样,就不必写冗长的require()了!
gulp-load-plugins会自动寻找package.json中以gulp-为前缀的依赖项。所以一定记得更新package.json。
本示例将大量使用gulp-load-plugins。
开发环境
本地服务器 (gulp-connect)
官网:https://www.npmjs.com/package/gulp-connect
安装:
npm install --save-dev gulp-connect
本地调试时通常需要搭建一个web服务器。我选用的是gulp-connect,配合gulp.watch()还可以实现自动刷新浏览器。
// 运行一个服务器
gulp.task('server', function() {
plugins.connect.server({
root: 'src', // 根目录
port: 8080, // 端口号。经测试,如果设置为80会报错。
livereload: true // 启用livereload,刷新浏览器
});
});
gulp-connect还可以启动多个server,并为每个server指定名称。具体看应用场景。
监听文件修改 + 自动刷新 (gulp.watch)
利用gulp-connect的livereload功能,和gulp.watch()函数,可以实现监听文件的修改,并自动刷新浏览器。
// 监听所有文件改动:自动刷新
gulp.task('reload', function() {
return gulp.src('src/**/*')
.pipe(plugins.connect.reload());
});
// 监听文件改动
gulp.task('watch', function() {
gulp.watch('src/**/*', ['reload']);
gulp.watch('src/less/**/*.less', ['less']);
gulp.watch('src/less/**/*.{sass,scss}', ['sass']);
});
这里比较暴力,直接监听了所有文件的修改。可以根据文件类型定义具体的规则。比如,希望修改less/sass文件的同时,重新编译并刷新浏览器。那么需要在less/sass任务中,触发connect.reload()。less/sass任务在后文有详细介绍。
JS代码校验 (gulp-jshint)
官网:https://www.npmjs.com/package/gulp-jshint
安装:
npm install --save-dev gulp-jshint jshint
代码校验可以使程序更健壮、更严谨,哪怕漏掉一个无关紧要的分号,都逃不过jshint的法眼。
使用比较简单。需要注意的是,在本示例的项目结构中,第三方JS文件和自定义JS文件分开存储,因此只校验了自定义的JS文件。
// JS代码校验。只校验用户自定义的js文件,不校验第三方js文件,如jQuery
gulp.task('jslint', function() {
return gulp.src('src/js/user/**/*.js')
.pipe(plugins.jshint())
.pipe(plugins.jshint.reporter());
});
使用Less (gulp-less)
官网:https://www.npmjs.com/package/gulp-less
安装:
npm install --save-dev gulp-less gulp-plumber gulp-notify
编译less至CSS文件。基本用法为:
gulp.task('less', function() {
return gulp.src('src/less/**/*.less')
.pipe(plugins.less())
.pipe(gulp.dest('src/css/compile'));
});
虽然编译生成了CSS,但是并不能满足需求。
首先,前面介绍过,如果希望修改less文件的同时,编译less并刷新浏览器,则需要在less任务中,触发connect.reload()。
其次,当编译less时出现语法错误,会导致watch终止,而错误信息需要进入命令行中查看。于是你会发现,修改less后浏览器不会自动刷新了,查看CSS发现less没有被编译,而整个过程竟然没有主动提醒我!解决方法是gulp-plumber+gulp-notify。
完整的解决方案如下:
// 编译less文件,并监听less文件改动:重新编译+自动刷新
gulp.task('less', function() {
return gulp.src('src/less/**/*.less')
.pipe(plugins.plumber({errorHandler: plugins.notify.onError('Error: <%= error.message %>')})) // 防止less出错,自动退出watch
.pipe(plugins.less())
.pipe(gulp.dest('src/css/compile'))
.pipe(plugins.connect.reload());
});
使用Sass (gulp-sass)
官网:https://www.npmjs.com/package/gulp-sass
安装:
npm install --save-dev gulp-sass gulp-plumber gulp-notify
与Less相比,几点不同是:
- Sass有两种文件后缀名,
.sass和.scss。最保险的方法是都编译一下。 - Sass可以指定编译生成CSS的格式。有四种格式可选:nested(默认)、expanded、compact、compressed
// 编译sass文件,并监听sass文件改动:重新编译+自动刷新
gulp.task('sass', function() {
return gulp.src('src/sass/**/*.{sass,scss}')
.pipe(plugins.plumber({errorHandler: plugins.notify.onError('Error: <%= error.message %>')})) // 防止sass出错,自动退出watch
.pipe(plugins.sass({
outputStyle: 'expanded' // CSS格式
}))
.pipe(gulp.dest('src/css/compile'))
.pipe(plugins.connect.reload());
});
使用Compass (gulp-compass)
官网:https://www.npmjs.com/package/gulp-compass
准备:需安装compass:
gem install compass安装:
npm install --save-dev gulp-compass gulp-plumber gulp-notify
Compass是Sass的神器。使用Compass插件的配置要稍稍复杂:
gulp.task('compass', function() {
return gulp.src('src/sass/**/*.{sass,scss}')
.pipe(plugins.plumber({errorHandler: plugins.notify.onError('Error: <%= error.message %>')})) // 防止sass出错,自动退出watch
.pipe(plugins.compass({
css: 'src/css/compile',
sass: 'src/sass',
image: 'src/img',
style: 'expanded' // CSS格式
}))
.pipe(gulp.dest('src/css/compile'))
.pipe(plugins.connect.reload());
});
gulp-sass和gulp-compass都是编译Sass,何必分家,搞得那么累?于是,我合并了这两个任务,应用时根据具体场景,注释掉相应代码即可。
// 编译sass文件,并监听sass文件改动:重新编译+自动刷新
gulp.task('sass', function() {
return gulp.src('src/sass/**/*.{sass,scss}')
.pipe(plugins.plumber({errorHandler: plugins.notify.onError('Error: <%= error.message %>')})) // 防止sass出错,自动退出watch
// (1) 如果只使用 sass, 请使用sass插件:
// .pipe(plugins.sass({
// outputStyle: 'expanded'
// }))
// (2) 如果使用 compass, 请使用compass插件:
.pipe(plugins.compass({
css: 'src/css/compile',
sass: 'src/sass',
image: 'src/img',
style: 'expanded'
}))
.pipe(gulp.dest('src/css/compile'))
.pipe(plugins.connect.reload());
});
任务组合
这么多小任务,是时候组合一下了。考虑到最常使用的是开发环境,而生产环境只是在上线迭代时才接触。因此,示例将defalut任务分配给开发环境。
// 默认任务
gulp.task('default', function() {
gulp.run('jslint', 'reload', 'less', 'sass', 'watch', 'server');
});
生产环境
清空构建目录 (gulp-clean)
官网:https://www.npmjs.com/package/gulp-clean
安装:
npm install --save-dev gulp-clean
每次构建目录,如果希望清理上次构建的文件,可以使用gulp-clean插件,免去了手动删除的操作。
gulp.task('clean', function() {
return gulp.src('dist')
.pipe(plugins.clean());
});
压缩JS (gulp-uglify)
官网:https://www.npmjs.com/package/gulp-uglify
安装:
npm install --save-dev gulp-uglify
方法:
gulp.task('minify-js', function() {
return gulp.src('src/**/*.js')
.pipe(plugins.uglify()) // JS压缩
.pipe(gulp.dest('dist')); // 保存JS文件
});
压缩CSS (gulp-clean-css)
官网:https://www.npmjs.com/package/gulp-clean-css
安装:
npm install --save-dev gulp-clean-css
方法:
gulp.task('minify-css', ['less', 'sass'], function() { // 编译less/sass
return gulp.src('src/**/*.css')
.pipe(plugins.cleanCss()) // CSS压缩
.pipe(gulp.dest('dist')); // 保存CSS文件
});
需要注意的是,本示例在压缩CSS之前,进行了一次Less/Sass编译,防止CSS文件丢失。
有的教程会提到使用gulp-minify-css,不过npm官网已不推荐gulp-minify-css:
This package has been deprecated. Please use gulp-clean-css instead.
压缩HTML (gulp-htmlmin)
官网:https://www.npmjs.com/package/gulp-htmlmin
安装:
npm install --save-dev gulp-htmlmin
方法:
gulp.task('minify-html', function() {
return gulp.src('src/**/*.html')
.pipe(htmlmin({collapseWhitespace: true})) // HTML压缩
.pipe(gulp.dest('dist')); // 保存HTML文件
});
有的教程会提到使用gulp-minify-html,不过npm官网已不推荐gulp-minify-html:
This package has been deprecated in favor of gulp-htmlmin, which should be faster and more comprehensive.
压缩图片 (gulp-imagemin)
官网:https://www.npmjs.com/package/gulp-imagemin
安装:
npm install --save-dev gulp-imagemin gulp-cache
方法:
gulp.task('build-img', function() {
return gulp.src('src/**/*.{png,jpg,gif,jpeg,svg}')
.pipe(plugins.cache(plugins.imagemin({ // 图片压缩
interlaced: true
})))
.pipe(gulp.dest('dist'));
});
添加MD5 (gulp-rev)
官网:https://www.npmjs.com/package/gulp-rev
安装:
npm install --save-dev gulp-rev
项目上线时 ,通常会为静态资源文件添加一个“后缀”,用来解决缓存更新问题。常用的后缀有时间戳、版本号、文件MD5值。本示例采用MD5值。
gulp-rev插件会根据原文件生成一个新文件,其文件名会自动追加MD5。原文件与新文件的映射关系也需要保留下来,路径替换时会用到映射关系。
方法:
gulp.task('MD5', function() {
return gulp.src('src/*.css')
.pipe(plugins.rev()) // 添加MD5
.pipe(gulp.dest('dist'))
.pipe(plugins.rev.manifest()) // 生成MD5映射
.pipe(gulp.dest('./rev')); // 保存映射
});
将压缩JS、压缩CSS和添加MD5这三项任务组合起来,便有了:
gulp.task('build-js', function() {
return gulp.src('src/**/*.js')
.pipe(plugins.uglify()) // JS压缩
.pipe(plugins.rev()) // 添加MD5
.pipe(gulp.dest('dist')) // 保存JS文件
.pipe(plugins.rev.manifest()) // 生成MD5映射
.pipe(gulp.dest('dist/rev/js')); // 保存映射
});
gulp.task('build-css', ['less', 'sass'], function() { // 编译less/sass
return gulp.src('src/**/*.css')
.pipe(plugins.cleanCss()) // CSS压缩
.pipe(plugins.rev()) // 添加MD5
.pipe(gulp.dest('dist')) // 保存CSS文件
.pipe(plugins.rev.manifest()) // 生成MD5映射
.pipe(gulp.dest('dist/rev/css')); // 保存映射
});
路径替换 (gulp-rev-collector)
官网:https://www.npmjs.com/package/gulp-rev-collector
安装:
npm install --save-dev gulp-rev-collector
添加MD5会导致静态资源文件名的更改。因此HTML文件中需要对路径做替换,才能保证正确的引用关系。
需要注意的是,路径替换的依据是gulp-rev插件生成的映射关系文件,因此它依赖build-js和build-css任务。
gulp.task('build-html', ['build-js', 'build-css'], function() {
return gulp.src(['dist/rev/**/*.json', 'src/**/*.html'])
.pipe(plugins.revCollector()) // 根据映射,替换文件名
.pipe(htmlmin({collapseWhitespace: true})) // HTML压缩
.pipe(gulp.dest('dist')); // 保存HTML文件
});
拷贝其他文件
项目中有一些文件在整个周期中不会被修改,上线发布时也无需任何处理,如字体文件。那么,直接将这类文件复制到构建目录即可。
gulp.task('build-fonts', function() {
return gulp.src('src/**/*.{eot,ttf,woff,woff2,otf}')
.pipe(gulp.dest('dist'));
});
任务组合
生产环境的配置已大致完成。将上述任务组合:
gulp.task('build', ['clean'], function() {
return gulp.run('build-html', 'build-fonts', 'build-img');
});
清空rev
添加MD5任务中生成的映射文件,在完成路径替换后就结束了自己的使命。可以将其删除,使构建目录更加清爽。方法是,在build任务中增加回调参数,使用gulp-clean插件清空映射文件目录。
gulp.task('build', ['clean'], function() {
return gulp.run('build-html', 'build-fonts', 'build-img', function() {
gulp.src('dist/rev').pipe(plugins.clean());
});
});
其他
.gitignore
如果使用git做版本控制,有一些目录是不需要提交的,可以用.gitignore文件指定。例如:
/node_modules
/dist
/.sass-cache
.DS_Store
其他功能推荐
- sourcemap:
gulp-sourcemaps - 合并文件:
gulp-concat - 重命名文件:
gulp-rename
参考
一个gulp用于开发与生产的示例的更多相关文章
- 做一个gulp+webpack+vue的单页应用开发架子
1.目标 最近项目上的事情不多,根据我自己的开发习惯,决定开发一些简单的开发架子,方便以后事情多的时候直接套用.本文讲的一个gulp+webpack+vue的单页应用架子,想要达到的目的: 可以通过命 ...
- SCRUM 是一个用于开发和维护复杂产品的框架
转自:http://www.scrumcn.com/agile/scrum-knowledge-library/scrum.html#tab-id-1 Scrum 是一个用于开发和维护复杂产品的框架 ...
- TVM:一个端到端的用于开发深度学习负载以适应多种硬件平台的IR栈
TVM:一个端到端的用于开发深度学习负载以适应多种硬件平台的IR栈 本文对TVM的论文进行了翻译整理 深度学习如今无处不在且必不可少.这次创新部分得益于可扩展的深度学习系统,比如 TensorFlo ...
- AppBoxFuture实战: 如何同步开发与生产环境的模型
框架是用抽象模型驱动的方式来生成应用系统的,这样可以将这些模型序列化为相应的模型包文件,通过反序列化导入至其他部署环境内,从而实现开发环境与生产环境的同步,包括对应的数据库结构的同步.下面通过示例 ...
- [敏捷开发实践](2) 用于开发和维持复杂产品的敏捷开发框架Scrum
[敏捷开发实践](2) 用于开发和维持复杂产品的敏捷开发框架Scrum 1,Scrum概述 上篇中提到敏捷开发有两种主流的方法,一个是XP,另一个是Scrum,本篇简要介绍Scrum方法.Scrum是 ...
- webpack开发与生产环境配置
前言 作者去年就开始使用webpack, 最早的接触就来自于vue-cli.那个时候工作重点主要也是 vue 的使用,对webpack的配置是知之甚少,期间有问题也是询问大牛 @吕大豹.顺便说一句,对 ...
- SpringBoot yml 配置 多配置文件,开发环境,生产环境配置文件分开
原文地址:https://www.cnblogs.com/baoyi/p/SpringBoot_YML.html 1. 在 spring boot 中,有两种配置文件,一种是application.p ...
- webpack快速入门——实战技巧:开发和生产并行设置
package.json中,devDependencies和dependencies是不同的 devDependencies:开发依赖 dependencies:生产依赖(线上) 1.安装生产环境的依 ...
- webpack开发和生产两个环境的配置详解
一开始在接触webpack 的时候,简直痛不欲生,现在回头看,做个注释,当然参考了很多文章.这是一个关于vue 开发的webpack 架构会列举出来webpack 系列教程Webpack——令人困惑的 ...
随机推荐
- [国家集训队]最长双回文串 manacher
---题面--- 题解: 首先有一个直观的想法,如果我们可以求出对于位置i的最长后缀回文串和最长前缀回文串,那么我们枚举分界点然后合并前缀和后缀不就可以得到答案了么? 所以我们的目标就是求出这两个数列 ...
- BZOJ1853:[SCOI2010]幸运数字 & BZOJ2393:Cirno的完美算数教室——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=1853 https://www.lydsy.com/JudgeOnline/problem.php? ...
- BZOJ1269 [AHOI2006]文本编辑器editor 【82行splay】
1269: [AHOI2006]文本编辑器editor Time Limit: 10 Sec Memory Limit: 162 MB Submit: 4633 Solved: 1782 [Sub ...
- 项目管理---git----快速使用git笔记(二)------git的本地安装
下载安装包 在使用Git前我们需要先安装 Git.Git 目前支持 Linux/Unix.Solaris.Mac和 Windows 平台上运行. Git 各平台安装包下载地址为:http://git- ...
- 继续bzoj
我应该可以打卡下班了,回来继续bzoj
- SpringMVC源码解析-HTTP请求处理和分发
1.HandlerMapping的配置和设计 在初始化完成时,所有的handlerMapping都已经被加载,handlerMapping存储着HTTP请求对应的映射数据,每一个handlerMapp ...
- Multi-target tracking with Single Moving Camera
引自:http://www.eecs.umich.edu/vision/mttproject.html Wongun Choi, Caroline Pantofaru, Silvio Savarese ...
- selenium - 获取断言信息
断言:通过脚本提取相应元素的数值,将实际结果与预期结果进行比较.通常获取title,URL,text等信息进行断言. from selenium import webdriver from time ...
- HDU 3605 最大流+状态压缩
Escape Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Subm ...
- Android SearchView设置与用法的那点事儿
// 设置该SearchView默认是否自动缩小为图标 mSearchView.setIconifiedByDefault(false); // 为该SearchView组件设置事件监听器 mSear ...