关于gulp:从实战带你认识gulp打包前端项目并实现防缓存

gulp是什么?一个基于node的前端自动化工作构建工具,应用经典回调+链式调用的形式实现工作的自动化 (src.pipe(...).pipe),gulp其实和webpack很类似,然而gulp侧重点不同,gulp更偏重前端流程自动化、工作执行(通过工作使开发提效),就像一条流水线。而webpack则是更偏重用于打包前端资源,所有皆可打包成模块。官网文档:https://www.gulpjs.com.cn/ gulp的利用场景?为什么用gulp?1.构建前端自动化流程比拟好的计划,一些反复的人工操作能够让gulp去做,并且代码量不大,晋升开发效率(自动化实现前端工作流工作:单元测试、优化、打包)。 2.与其余构建工具相比开发简略,易上手。基于nodejs 文件系统流,运行速度快。 3.更适宜原生前端我的项目的打包。有助于了解前端工程化。 4.公布通用型组件或者npm库的时候能够用gulp来进行打包。 gulp的装置在你的我的项目目录中执行 npm install -g gulp 在根目录下创立gulp的配置文件gulpfile.js,install一下文件中的依赖,之后就能够间接在这个文件中定义咱们的gulp工作了 var gulp=require("gulp");//引入gulp模块gulp.task('default',function(){ console.log('hello world');});而后间接终端中进入当前目录运行 gulp 命令就开始执行工作了。gulp前面也能够加上要执行的工作名,例如gulp task1,如果没有指定工作名,则会执行工作名为default的默认工作。gulp罕用的几个api : task, series, parallel, src, pipe, dest task: 创立一个工作series:程序执行多个工作prallel:并行执行多个工作src:读取数据源转换成streampipe:管道-能够在两头对数据流进行解决dest:输入数据流到指标门路gulp理论利用之原生前端我的项目打包:以一个jQuery原生我的项目为例子,目录构造: 门路表:因为我的项目构造有点非凡,资源比拟扩散,html的js、css保留在对应模块文件夹中。而公共的js、css却在html的里面的文件中,所以就设置了2个入口(以js资源为例):一个根目录入口、一个html入口   scriptsjs: {//根目录入口    src: [      "./temp/js/**/*.js",//temp/js/之下的所有文件夹下的js      "!./temp/**/*.min.js", //不匹配压缩过的js,避免二次压缩      "!./temp/js/common.js",       "!./temp/mpcc/**/*.js",//这个文件不须要压缩解决所以不匹配    ],    dest: destDir + "/js",//进口  },  scriptshtml: {//html入口    src: [      "./temp/html/**/*.js",      "!./temp/html/BasicSet/RoleManage/js/*.js",//不匹配      "!./temp/html/BasicSet/UserAuthorization/js/*.js",    ],    dest: destDir + "/html",  },你没看错,是不是有点像webpack中的entry和output。* 通配符是代表所有文件夹、!是代表不匹配。这里能够本人选哪些文件不须要进行匹配 ...

March 6, 2022 · 9 min · jiezi

关于gulp:一个gulp构建工作流案例

一个构gulp自动化构建工作流案例须要对款式文件,js文件,html文件,图片字体文件,其余额定文件顺次构建工作,并在此过程中实现对文件的压缩合并 const { src, dest, series, parallel, watch,} = require('gulp');const loadPlugins = require('gulp-load-plugins')const plugins = loadPlugins() // 加载插件模块const sass = require('gulp-sass')(require('sass'));// sass.compiler = require("node-sass");// const plugins.babel = require('gulp-babel')// const plugins.swig = require('gulp-swig')// const plugins.imagemin = require('gulp-imagemin')const del = require('del') // 革除文件插件const browserSync = require('browser-sync') // 提供一个能够热更新的开发服务器const bs = browserSync.create() // 创立一个开发服务器const data = `your template data`// 清理dist文件夹const clean = () => { return del(['dist', 'temp'])}const style = () => { // base参数保留了src目录前面的基准门路 return src('src/assets/styles/*.scss', { base: 'src' }) .pipe(sass({ outputStyle: 'expanded' })) // 齐全开展 .pipe(dest('temp')) // 放到长期目录 .pipe(bs.reload({ stream: true })) // 外部文件流信息推到浏览器}const script = () => { return src('src/assets/scripts/*.js', { base: 'src' }) .pipe(plugins.babel({ presets: ['@babel/preset-env'] // 蕴含了最新的js语法 })) .pipe(dest('temp')) .pipe(bs.reload({ stream: true }))}const page = () => { return src('src/**/*.html', { base: 'src' }) // **代表了src目录下任意html文件 .pipe(plugins.swig({ data, // 动态数据模板编译输入 defaults: { cache: false // 避免模板缓存导致页面不能及时更新 } })) .pipe(dest('temp')) .pipe(bs.reload({ stream: true }))}const image = () => { return src('src/assets/images/**', { base: 'src' }) .pipe(plugins.imagemin()) .pipe(dest('dist'))}const font = () => { return src('src/assets/fonts/**', { base: 'src' }) .pipe(plugins.imagemin()) .pipe(dest('dist'))}const extra = () => { // 拷贝额定文件 return src('public/**', { base: 'public' }) .pipe(dest('dist'))}const server = () => { watch('src/assets/styles/*.scss', style) watch('src/assets/scripts/*.js', script) watch('src/*.html', page) // 上面三个工作,只须要上线的时候公布进来即可,开发阶段的构建须要缩小构建,进步构建效率 // watch('src/assets/image/**', image) // watch('src/assets/fonts/**', font) // watch('public/**', extra) watch([ 'src/assets/images/**', 'src/assets/fonts/**', 'public/**' ], bs.reload) bs.init({ notify: false, port: 2180, // files: 'dist/**', // 监听文件夹 srcipt,style,page因为bs.realod,这里不必再监听 // open: false, // 勾销关上浏览器 server: { baseDir: ['temp', 'src', 'public'], // 服务器运行根目录,数组内为顺次寻找目录 routes: { '/node_modules': 'node_modules' } } })}const useref = () => { return src('temp/*.html', { base: 'temp' }) .pipe(plugins.useref({ searchPath: ['temp', '.'] })) // 解决构建正文,合并到一个文件中 // 压缩html,js,css .pipe(plugins.if(/\.js$/, plugins.uglify())) .pipe(plugins.if(/\.css$/, plugins.cleanCss())) .pipe(plugins.if(/\.html$/, plugins.htmlmin({ collapseWhitespace: true, // 解决html文件空格 minifyCSS: true, minifyJS: true }))) .pipe(dest('release'))}const compile = parallel(style, script, page) // 并行执行三个工作,组合为一个compile工作// build之前执行clean工作,上线之前执行buildconst build = series(clean, parallel(series(compile, useref), image, font, extra));const develop = series(compile, server)module.exports = { build, clean, develop,}

January 28, 2022 · 2 min · jiezi

关于gulp:Gulp基本概念及应用

gulp简介,根本应用Gulp.js 是一个自动化构建工具,开发者能够应用它在我的项目开发过程中主动执行常见工作。 yarn add gulp 装置gulp的时候会装置gulp-cli。gulpfile.js中导出一个函数,最新的gulp中勾销了同步代码模式,每一个工作都是异步工作,最初须要调用回调函数或其余形式标记工作实现。如例子中如果没有done,会报错.如果工作名是default,运行时的命令和grunt相似,间接运行yarn gulp即可。 exports.foo = done => { console.log("foo task") done() // 标识工作实现 }gulp4.0中仍然保留了之前版本的工作导出形式,然而这种形式曾经不举荐,举荐导出函数的形式应用gulp const gulp = require('gulp') gulp.task('bar', done => { console.log("bar task") done() })series,parallel组合工作gulp能够通过series,parallel来组合工作,series串行执行,parallel并行执行,比方js,css在编译时就能够并行执行,比方部署工作时先要执行编译工作再进行其余工作,工作串行执行。根本应用形式如下 const { series, parallel} = require('gulp')const task1 = done => { setTimeout(() => { console.log("task1 working") done() }, 1000);}const task2 = done => { setTimeout(() => { console.log("task2 working") done() }, 1000);}const task3 = done => { setTimeout(() => { console.log("task3 working") done() }, 1000);}exports.foo = series(task1, task2, task3)exports.bar = parallel(task1, task2, task3)串行并行 ...

January 28, 2022 · 2 min · jiezi

关于gulp:Gulp-结构化最佳实践

在 Gulp 的官网文档中,Gulp 的工作都是写在 gulpfile.js 这一个文件中的,如果工作数量不多,这并不会有什么问题,但当工作数量较多时,会造成代码可读性差,难以保护,多人合作时还会容易造成抵触。因而,更好的解决形式是把 Gulp 的代码结构化。 开始结构化https://github.com/QMUI/qmui_web 这是一个前端框架,次要由一个 SASS 办法合集与内置的工作流形成,其中工作流局部提供了一系列的工作用于解决前端流程,并且因为是可配置的框架,须要读取配置文件,因而尽管原有的 gulpfile.js 的代码并不宏大,但依然须要进行结构化解决,本文将会具体阐明如何进行结构化解决。 次要的思路是把 gulpfile.js 中的工作扩散到独立的文件中编写,而后在 gulpfile.js 中引入这些 task。因而最简便的办法是把每个 task 独自写在独立的文件中,以 task 名命名文件名,在 gulpfile.js 中把这些文件读取进去,例如: workflow/task/clean.jsvar del = require('del');gulp.task('clean', '清理多余文件(清理内容在 config.json 中配置)', function() { // force: true 即容许 del 管制本目录以外的文件 del(common.config.cleanFileType, {force: true}); console.log(common.plugins.util.colors.green('QMUI Clean: ') + '清理所有的 ' + common.config.cleanFileType + ' 文件');});gulpfile.jsvar gulp = require('gulp'), requireDir = require('require-dir');// 遍历目录,加载 task 代码requireDir('./workflow/task', { recurse: true });gulp.task('default', ['clean']);这种办法操作起来比较简单,同时根本不须要改变原有的代码,只需对 gulpfile.js 稍作改变即可。但同时也引入了一些问题,例如,文章结尾说过的,像 QMUI 这类须要读取公共配置文件的需要,这里就无奈解决,各个工作中如果须要引入配置表,都须要独自引入,同时像工具办法这类内容也会反复引入,造成节约。因而实际上,clean.js 中也不是像下面的例子那样编写的,而是采纳 module 的形式拆分工作。 ...

August 31, 2021 · 2 min · jiezi

关于gulp:Gulp-API

本节咱们来看一下 Gulp 中的 API 办法,如下所示: 办法形容src()创立用于从文件系统读取 Vinyl 对象的流dest()创立一个用于将 Vinyl 对象写入到文件系统的流symlink()创立一个流(stream),用于连贯 Vinyl 对象到文件系统lastRun()检索在以后运行过程中胜利实现工作的最初一次工夫series()将工作函数和/或组合操作组合成更大的操作,这些操作将按程序顺次执行parallel()将工作性能和/或组合操作组合成同时执行的较大操作watch()监听 globs 并在产生更改时运行工作task()在工作零碎中定义工作registry()容许将自定义的注册表插入到工作零碎中,以期提供共享工作或加强性能tree()获取当前任务依赖关系树——在极少数状况下须要它Vinyl虚构的文件格式Vinyl.isVinyl()检测一个对象(object)是否是一个 Vinyl 实例Vinyl.isCustomProp()确定一个属性是否由 Vinyl 在外部进行治理咱们在应用 gulp 时,个别只须要用到 4 个 API,别离是 gulp.src()、gulp.dest()、gulp.task()、gulp.watch(),上面咱们具体介绍一个这 4 个罕用 API 的应用。 gulp.src()办法gulp.src() 办法用于创立一个流。然而要留神的是这个流里的内容不是原始的文件流,而是一个虚构文件对象流(vinyl files),这个虚构文件对象中存储着原始文件的门路、文件名、内容等信息。 语法如下所示: gulp.src(globs, [options])globs :文件匹配模式(类型正则表达式),用来匹配文件门路(包含文件名),也能够间接指定某个具体的文件门路。options:可选参数,通常状况下不须要用到。示例: 例如上面这个例子,将 input 文件夹中的 .js 文件复制到 output 文件夹中: const { src, dest } = require('gulp');function copy() { return src('input/*.js') .pipe(dest('output/'));}exports.copy = copy;执行 gulp copy 命令后,文件胜利被复制。 gulp.dest()办法gulp.dest() 办法能够创立一个用于将 Vinyl 对象写入到文件系统的流。 语法如下: gulp.dest(path[ , options])path:为写入文件的门路。options:可选的参数对象,通常用不到。gulp.dest() 办法是和 gulp.src() 办法搭配应用的,例如上述这个复制文件的示例。 ...

May 22, 2021 · 1 min · jiezi

关于gulp:Gulp-插件

后面咱们讲到在学习压缩 JS、CSS、图片等文件时,须要用到一些相干的插件。Gulp 提供了一些有用的插件来解决 HTML 和 CSS,JavaScript,图形以及一些其余内容。上面咱们来看一下 gulp 中的一些不同类型插件。 HTML和CSS插件插件形容autoprefixer主动蕴含 CSS 属性的前缀gulp-browser-sync用于监督 CSS 目录中的所有 HTML 和 CSS 文件,并在文件更改时对所有浏览器中的页面执行实时从新加载gulp-useref用于替换对非优化脚本或样式表的援用gulp-email-design创立 HTML 电子邮件模板,将 CSS 款式转换为内联gulp-uncss优化 CSS 文件和查找未应用和反复的款式gulp-csso是一个 CSS 优化器,能够最小化 CSS 文件,从而放大文件大小gulp-htmlmin最小化 HTML 文件gulp-csscomb用于制作 CSS 的款式格式化程序gulp-csslint它指定一个 CSS lintergulp-htmlhint指定一个 HTML 验证器JavaScript插件插件形容gulp-autopolyfiller它与 autoprefixer 雷同,包含 JavaScript 的必要 polyfillgulp-jsfmt用于搜寻特定的代码段gulp-jscs用于查看 JavaScript 代码款式gulp-modernizr指定了用户浏览器提供的 HTML,CSS 和 JavaScript 性能gulp-express启动了gulp express.js 网络服务器gulp-requirejs应用 require. js 将 require.js AMD 模块组合成一个文件gulp-plato生成复杂性剖析报告gulp-complexity剖析了代码的复杂性和可维护性fixmyjs修复了 JSHint 的后果gulp-jscpd用作源代码的复制/粘贴检测器gulp-jsonlint是 JSON 验证器gulp-uglify放大了 JavaScript 文件gulp-concat连贯 CSS 文件单元测试插件插件形容gulp-nodeunit运行 Gulp 的节点单元测试gulp-jasmine用于报告与输入相干的问题gulp-qunit为 QUnit 测试提供根本的控制台输入,并应用 PhantomJS 节点模块和 PhantomJS 运行器 QUnit 插件gulp-mocha指定了 Mocha 四周的薄包装并运行 Mocha 测试gulp-karma已在 Gulp 中弃用图形插件插件形容gulpicon从 SVG 生成精灵并将它们转换为 PNGgulp-iconfont与 Web 字体一起用于从 SVG 创立 WOFF,EOT,TTF 文件gulp-imacss将图像文件转换为数据 URI 并将它们放入单个 CSS 文件中gulp-responsive为不同的设施生成响应式图像gulp-sharp它用于更改和调整图像的方向和背景gulp-svgstore将 SVG 文件与元素组合成一个文件gulp-imagemin&gulp-tinypng用于压缩 PNG,JPEG,GIF,SVG 等图像gulp-spritesmith用于从一组图像和 CSS 变量创立 spritesheet编译器插件插件形容gulp-less为 Gulp 提供了大量插件gulp-sass为 Gulp 提供 SASS 插件gulp-compass为 Gulp 提供指南针插件gulp-stylus用于将手写笔保留在 CSS 中gulp-coffee为 Gulp 提供 coffeescript 插件gulp-handlebars为 Gulp 提供了把手插件gulp-jst在 JST 中提供下划线模板gulp-react将 Facebook React JSX 模板指定为 JavaScriptgulp-nunjucks在 JST 中指定 Nunjucks 模板gulp- dustjs在 JST 中指定了 Dust 模板gulp-angular-templatecache在 templateCache 中指定 AngularJS 模板其余插件gulp-clean 插件删除文件和文件夹,gulp-copy 插件将文件从源文件复制到新目的地。 ...

May 21, 2021 · 1 min · jiezi

关于gulp:Gulp-编译Less和Sass

在理论利用中,咱们个别会应用 CSS 的预处理器来编写 CSS 代码,例如 Less 和 Sass 语言,通过将脚本解析成 CSS 的脚本语言,能够缩小 CSS 的反复,也能够节省时间。 本节咱们来学习如何通过 gulp 将 Less 和 Sass 编译成 CSS 代码。将 Less 编译成 CSS 须要应用 gulp-less 插件,将 Sass 编译成 CSS 须要用到 gulp-ruby-sass 插件。 将Less编译成CSS例如在我的项目根目录下的 less 文件夹中有一个 style.less 文件,文件内容如下所示: div{ color: #ccc; a{ color: white; font-size: 16px; } p{ font-size: 14px; line-height: 30px; }}咱们须要将这个 style.less 文件代码编译成 CSS 代码。 首先须要装置 gulp-less 插件,装置命令如下所示: npm install gulp-less装置好插件后,咱们能够在 gulpfile.js 文件中创立命令,代码如下所示: // 获取 gulpvar gulp = require('gulp')var gulp_less = require('gulp-less')gulp.task('less', function(cb) { gulp.src('less/*.less') .pipe(gulp_less()) .pipe(gulp.dest('dist/css')) cb()})而后咱们执行 gulp less 命令: ...

May 20, 2021 · 1 min · jiezi

关于gulp:Gulp-使用gulp压缩图片

在理论我的项目中,除了 HTML、CSS、JS 等文件,还会用到大量的图片。压缩图片可升高图片文件大小,进步页面关上速度。 如何压缩图片 应用 gulp 来压缩图片能够应用上面两个插件: gulp-imagemin:压缩率不显著,能够解决多种图片格式,能够引入更多第三方优化插件。gulp-smushit:压缩率比拟大,只能解决 JPG 和 PNG。例如咱们所有的图片压缩到 dist 目录下的 image 文件夹中,上面咱们应用 gulp-imagemin 插件来实现图片的压缩,在我的项目中,除了 PNG 和 JPG 格局的图片,也有可能有其余格局的图片。 示例: 首先装置 gulp-imagemin 插件,命令如下所示: npm install --save-dev gulp-imagemin插件装置胜利后,咱们就能够在 gulpfile.js 文件中编写代码: // 获取 gulpvar gulp = require('gulp')// 获取 uglify 模块var imagemin = require('gulp-imagemin')// 压缩图片工作gulp.task('images', function(cb) { // 找到图片 gulp.src('image/*') .pipe(imagemin({ progressive: true, })) .pipe(gulp.dest('dist/image')) cb()})运行 gulp images 命令:

May 18, 2021 · 1 min · jiezi

关于gulp:Gulp-使用gulp压缩CSS

咱们除了能够应用 gulp 压缩 JS 文件,还能够压缩 CSS,压缩 CSS 代码能够升高 CSS 文件的大小,进步网页的关上速度。 压缩CSS文件应用 gulp 来压缩 CSS 文件的操作步骤和压缩 JS 文件差不多,后面咱们学习了如何压缩 JS 文件,那么再学习压缩 CSS 文件就会感觉很简略啦。 压缩 CSS 文件同样须要用到相应的插件,对于 gulp 的 CSS 压缩插件,一共有如下三个: gulp-cssnanogulp-minify-cssgulp-clean-css下面三个插件,因为 gulp-minify-css 当初曾经被标记为 deprecated,因为咱们能够应用其余两个插件。 例如咱们所有的 .css 文件压缩到 dist 目录下的 css 文件夹中,具体操作如下所示。 装置插件首先装置 gulp-clean-css 插件,命令如下所示: npm install gulp-clean-css如下图所示: 在gulpfile.js文件中编写代码插件装置胜利后,咱们就能够在 gulpfile.js 文件中编写代码。 示例:// 获取 gulpvar gulp = require('gulp')var cleancss = require('gulp-clean-css')gulp.task('testcss', function(cb) { gulp.src('css/*.css') .pipe(cleancss()) .pipe(gulp.dest('dist/css')) cb()})运行 gulp testcss 命令,压缩 CSS 文件:此时我的项目根目录下的 dist 目录中会生成一个 CSS 文件夹,被压缩的 CSS 文件就放在这个文件夹中。 ...

May 17, 2021 · 1 min · jiezi

关于gulp:Gulp-使用gulp压缩JS

本节咱们学习如何应用 gulp 压缩 JS,在理论我的项目中,如果 JS 文件太大,那么可能导致页面加载变慢。所以咱们能够将这些 JS 文件进行压缩。咱们除了能够抉择应用各种工具手动来进行压缩,还能够通过 gulp 来实现 JS 文件的压缩。 压缩JS文件应用 gulp 来压缩 JS 文件,须要用到一个 gulp-uglify 插件,上面咱们一起来看一下,要如何压缩 JS 文件。 例如咱们要实现的工作是压缩 js 目录下的所有 .js 文件,将这些 JS 文件压缩到 dist 目录下的 js 文件夹中。 装置插件首先咱们须要装置 gulp-uglify 插件,关上命令行工具,或者间接在 VSCode 中关上终端。而后进入到 gulpfile.js 文件所在的目录下,如果你的我的项目中还没有这个文件,则须要创立这个文件哟,因为 gulp 的所有配置代码都写在 gulpfile.js 文件。。 如下图所示,在命令行工具中执行装置 gulp-uglify 插件的命令: npm install gulp-uglify 在gulpfile.js文件中编写代码插件装置胜利后,咱们就能够在 gulpfile.js 文件中编写代码,首先同样是利用 gulp 模块: // 获取 gulpvar gulp = require('gulp')而后获取 uglify 模块: var uglify = require('gulp-uglify')接着就能够通过 task() 办法创立压缩工作: gulp.task('script', function() { // 找到要压缩的js文件 gulp.src('js/*.js') // 压缩文件 .pipe(uglify()) // 将压缩后的文件存到只指定目录 .pipe(gulp.dest('dist/js'))})执行压缩命令而后咱们能够命令行工具中,执行 gulp script 命令,其中 script 是工作名称。 ...

May 16, 2021 · 1 min · jiezi

关于gulp:Gulp-globs匹配规则

本节咱们来学习 Gulp 中的 globs 的匹配规定。glob 是由一般字符或通配字符组成的字符串,用于匹配文件门路。咱们能够应用一个或多个 glob 匹配规定在文件系统中定位文件。 gulp.src()办法src() 办法须要一个 glob 字符串或一个 glob 字符串组成的数组来作为参数,确定哪些文件须要被操作。 gulp.src(globs[, options])globs:文件匹配模式,相似于正则表达式,用来匹配文件门路。options:可选参数,通常状况不须要用到。示例:gulp.src('./js/*.js') // * 匹配js文件夹下所有.js格局的文件gulp.src('./js/**/*.js') // ** 匹配js文件夹的0个或多个子文件夹gulp.src(['./js/*.js','!./js/index.js']) // ! 匹配除了index.js之外的所有js文件gulp.src('./js/**/{omui,common}.js') // {} 匹配{}里的文件名匹配模式gulp 外部应用了 node-glob 模块来实现其文件匹配性能。咱们能够应用上面这些非凡的字符来匹配咱们想要的文件。 单匹配模式: 匹配符形容*匹配文件门路中的 0 个或多个字符,但不会匹配门路分隔符,除非门路分隔符呈现在开端**匹配门路中的 0 个或多个目录及其子目录?匹配方括号中呈现的字符中的任意一个[...]匹配方括号中呈现的字符中的任意一个多匹配模式,同时应用多种匹配: 表达式形容!(pattern\pattern\pattern)匹配任何与括号中给定的任一模式都不匹配的?(pattern\pattern\pattern)匹配括号中给定的任一模式0次或1次+(pattern\pattern\pattern)匹配括号中给定的任一模式至多1次*(pattern\pattern\pattern)匹配括号中给定的任一模式0次或屡次@(pattern\pattern\pattern)匹配括号中给定的任一模式1次数组如果有多种匹配模式时,咱们能够在 src() 办法中应用数组。 应用数组的形式来匹配多种文件,例如上面代码匹配 js、css、html 三种文件:gulp.src(['js/*.js', 'css/*.css', '*.html'])应用数组的形式还有一个益处就是能够很不便的应用排除模式,在数组中的单个匹配模式前加上 ! 符号即是排除模式,,它会在匹配的后果中排除这个匹配,要留神一点的是不能在数组中的第一个元素中应用排除模式gulp.src([*.js,'!b*.js']) // 匹配所有js文件,但排除掉以b结尾的js文件gulp.src(['!b*.js',*.js]) // 不排除任何文件,因为排除模式不能呈现在数组的第一个元素中此外,还能够应用开展模式。开展模式以花括号 {} 作为定界符,依据它外面的内容,会开展为多个模式,最初匹配的后果为所有开展的模式相加起来失去的后果。 开展的例子如下: a{b,c}d: 会开展为 abd,acd。a{b,}c:会开展为 abc,ac。a{0..3}d:会开展为 a0d,a1d,a2d,a3d。a{b,c{d,e}f}g:会开展为 abg,acdfg,acefg。a{b,c}d{e,f}g:会开展为 abdeg,acdeg,abdeg,abdfg。字符串片段与分隔符字符串片段是指两个分隔符之间的所有字符组成的字符串,在 globs 中,分隔符永远是 / 字符,不辨别操作系统,即便是在采纳 \\ 作为分隔符的 Windows 操作系统中也是如此。在 globs 中,\\ 字符被保留作为转义字符应用。 ...

May 15, 2021 · 1 min · jiezi

关于gulp:Gulp-处理文件

Gulp 裸露了 src() 和 dest() 办法,用于解决计算机上寄存的文件。 其中 src() 办法承受一个 glob 参数,从文件系统中读取文件,而后生成一个 Node 流。它将所有匹配的文件读取到内存中并通过流进行解决。 由 src() 办法产生的流该当从工作中返回并收回异步实现的信号,就如 创立工作文档中所述。 示例:const { src, dest } = require('gulp');exports.default = function() { return src('src/*.js') .pipe(dest('output/'));}流提供的次要的 API 是用于链接转换或者是可写流的 .pipe() 办法。 const { src, dest } = require('gulp');const babel = require('gulp-babel');exports.default = function() { return src('src/*.js') .pipe(babel()) .pipe(dest('output/'));}dest() 承受一个输入目录作为参数,并且它还会产生一个 Node 流,通常作为终止流。当它接管通过管道传递的文件时,它将文件内容和其余细节写入给定目录中。gulp 还提供了 symlink() 办法,它的操作形式与dest() 相似,但会创立链接而不是文件。 大多数状况下,插件将应用.pipe() 办法搁置在 src() 和 dest() 之间,并将转换流中的文件。 向流中增加文件src() 办法能够放在管道的两头,依据给定的 glob 向流中增加文件,新退出的文件只会对后续的转换可用,如果 glob 匹配的文件与之前的有反复,它依然会再次增加文件。 ...

May 14, 2021 · 1 min · jiezi

关于gulp:Gulp-异步执行

Node 库有多种形式解决异步性能,最常见的模式是 error-first callbacks,除此之外,还有 streams、promise()、event emitters、child processes、observables。gulp 工作规范化了所有这些类型的异步性能。 工作实现告诉当从工作中返回 stream、promise、event emitter、child process 或 observable 时,胜利或谬误值将告诉 gulp 是否继续执行或完结。如果工作出错,gulp 将立刻完结执行并显示该谬误。 当应用 series() 组合多个工作时,任何一个工作的谬误将导致整个工作组合完结,并且不会进一步执行其余工作。当应用 parallel() 组合多个工作时,一个工作的谬误将完结整个工作组合的完结,然而其余并行的工作可能会执行完,也可能没有执行完。 返回 streamconst { src, dest } = require('gulp');function streamTask() { return src('*.js') .pipe(dest('output'));}exports.default = streamTask;返回 promisefunction promiseTask() { return Promise.resolve('the value is ignored');}exports.default = promiseTask;返回 event emiterconst { EventEmitter } = require('events');function eventEmitterTask() { const emitter = new EventEmitter(); // Emit has to happen async otherwise gulp isn't listening yet setTimeout(() => emitter.emit('finish'), 250); return emitter;}exports.default = eventEmitterTask;返回 child processconst { exec } = require('child_process');function childProcessTask() { return exec('date');}exports.default = childProcessTask;返回 observableconst { Observable } = require('rxjs');function observableTask() { return Observable.of(1, 2, 3);}exports.default = observableTask;返回 callback如果工作未返回任何内容,则必须应用 callback 来示意工作已实现,回调将作为以下示例中名为 cb() 的惟一参数传递给工作。 ...

May 8, 2021 · 1 min · jiezi

关于gulp:Gulp-导出任务

Gulp 中的工作能够是能够分为 public(私有)和 private (公有)类型。 私有工作:从 gulpfile 中被导出的工作称为私有工作,能够通过 gulp 命令间接调用。公有工作:在外部应用,通常作为 series() 或 parallel() 组合的组成部分。一个公有类型的工作在外观和行为上和其余工作是一样的,然而不可能被用户间接调用。如果须要将一个工作注册为私有类型的,只须要从 gulpfile.js 文件中将工作通过 export 导出即可。 如何导出工作咱们能够在 gulpfile.js 文件中,应用 export 命令导出工作,这样这个被导出的工作变为了一个私有工作(public task),能够被 gulp 命令间接调用。 示例:看上面这个例子: const { series } = require('gulp');// clean函数并未被导出,因而clean是公有工作,能够被用在 series() 组合中function clean(cb) { cb();}// build 函数被导出了,因而它是一个私有工作,能够被 gulp 命令间接调用,它也可用在series()组合中function build(cb) { cb();}// 导出 build 函数exports.build = build;exports.default = series(clean, build);执行 gulp --tasks 命令:在以前的 gulp 版本中,task() 办法用来将函数注册为工作。尽管这个 API 仍旧是能够应用的,然而导出将会是次要的注册机制,除非遇到 export 不起作用的状况。 组合工作Gulp 提供了两个弱小的组合办法: series() 和 parallel() 办法,这两个办法容许将多个独立的工作组合为一个更大的操作。这两个办法都能够承受任意数目的工作(task)函数或曾经组合的操作。series() 和 parallel() 办法能够相互嵌套至任意深度。 ...

May 6, 2021 · 1 min · jiezi

关于gulp:Gulp-第一个Gulp任务

本节咱们开始学习如何创立 Gulp 工作。每一个 Gulp 工作都是一个异步的 JavaScript 函数,这个函数是一个能够接管回调函数 callback 作为参数的函数,或者是一个返回 stream、promise、event emitter、child process 或 observable 类型值的函数。 gulp.task()办法gulp.task() 用于创立一个 gulp 工作,语法如下所示: gulp.task(name[, deps], fn)name: 示意工作的名称。deps :以后定义的工作须要依赖的其余工作,为一个数组。以后定义的工作会在所有依赖的工作执行结束后才开始执行。如果没有依赖,则省略这个参数。fn:为工作函数,咱们把工作要执行的代码都写在外面。是一个可选参数。给工作起一个惟一的名称后,咱们能够通过这个名称来执行工作,例如: > gulp 工作名在执行工作时,如果咱们不加工作名进行执行,也就是只输出 gulp 命令时 ,会执行名为 default 的默认工作,如果没有定义这个工作,将什么也不做。 创立gulpfile文件首先咱们须要在我的项目根目录下创立一个 gulpfile.js 文件。并在文件中引入 gulp: var gulp = require('gulp');用于通知 Node 去 node_modules 中查找 gulp 包,先在部分进行查找,找不到则去全局环境中查找。找到之后就会赋值给 gulp 变量,而后咱们就能够应用它了。 示例:例如创立一个名为 xkd 的工作: let gulp = require('gulp');gulp.task('xkd', done => { console.log("你好,侠课岛!") done()});执行 gulp xkd 命令,下图为运行后果: 运行后果第一行示意找到本地的 gulpfile.js 文件。运行后果第二行示意开始运行工作 xkd,这个 xkd 是咱们给工作定义的名称。运行后果第三行示意运行代码内的逻辑。运行后果第四行示意工作'xkd'运行完结,一共耗时5.27 ms执行多个工作gulp.task() 办法中的第二个参数为一个数组,数组中的值是工作名的汇合,当执行此工作时,会先执行数组中的工作。咱们来看一下例子。 ...

April 30, 2021 · 1 min · jiezi

关于gulp:Gulp-介绍与安装

Gulp 介绍与装置Gulp 是前端开发过程中一种对代码进行构建的工具,是自动化我的项目的构建利器。它不仅能对网站资源进行优化,而且在开发过程中很多反复的工作可能应用正确的工具主动实现,应用 Gulp 不仅能够轻松的编写代码,而且还大大的进步了咱们的工作效率。 Gulp 是基于 Node.js 的自动化工作运行器,它能自动化地实现前端代码(例如 HTML、CSS、JavaScript、Less、Sass、image 等文件)的测试、查看、合并、压缩、格式化、浏览器主动刷新、部署文件生成,并监听文件在改变后反复指定的这些步骤。 Gulp特点易于应用,通过代码的优质配置策略,使得 gulp 操作简略工作简单化,简单工作治理化。构建快捷,利用 Node.js 的作用咱们能够更疾速的构建我的项目从而缩小频繁的 IO 操作。简略易学,用起码的 API 更轻松的把握 gulp。插件高质,gulp 严格的插件指南能够确保咱们的工作更加高质无效。如何装置Gulp在装置 Gulp 之前,咱们须要先查看电脑上是否曾经正确装置 node、npm、npx,须要用到的命令如下所示: node --versionnpm --versionnpx --version如下图所示:如果上述工具还没有装置,能够先点击进行装置:https://nodejs.org/en/。 装置Gulp命令行工具装置 Gulp 命令行工具命令如下所示,其中 --global 示意全局装置: npm install --global gulp-cli装置实现后,能够创立我的项目目录并进入创立好的目录: > npx mkdirp my_gulp> cd my_gulp如下图所示: 这样咱们就在 C:\Users\lu\Desktop 目录下创立一个名为 my_gulp 的我的项目。 创立package.json文件如果咱们要在我的项目的根目录下创立一个 package.json 文件,能够执行如下所示命令: > npm init按下回车后,此命令会指引咱们设置我的项目名、版本、形容信息等,如下图所示,如果想要疾速创立 package.json 文件,能够执行 npm init -y 命令。 装置Gulp而后在我的项目根目录下执行如下命令,装置 Gulp,作为开发时依赖项: npm install --save-dev gulp装置实现之后,能够执行如下命令查看是否装置胜利: gulp --version如下图所示:此时我的项目根目录下会创立一个 package-lock.json 文件,并且 gulp 会被增加到 package.json 文件的 devDependencies 选项中。 ...

April 27, 2021 · 1 min · jiezi

关于gulp:Gulp

Gulp基于node平台开发的前端构建工具,将机械化操作编写成工作,想要执行机械化操作只须要输出命令即可,用机器执行手工,进步开发效率### Gulp的作用 我的项目上线 HTML CSS JS文件压缩合并语法转换(es6,less等等)公共文件抽离批改文件浏览器主动刷新Gulp的应用命令行工具:npm install cli -g 应用npm install gulp下载gulp库文件在我的项目根目录下建设gulpfile.js文件重构我的项目的文件夹构造 src目录搁置源代码文件 dist目录搁置构建后文件在gulpfile.js文件中编写工作.在命令行工具中执行gulp工作 Gulp中提供的办法gulp.src():获取工作要解决的文件gulp.dest():输入文件gulp.task():建设gulp工作gulp.watch():监控文件的变动// 引进gulp模块const gulp = require('gulp');// 建设gulp工作gulp.task('first', () => { //获取要解决的文件 gulp.src('./src/1.hello word.js') // 将解决好的工作输入到dist目录 .pipe(gulp.dest('./dist'))})Gulp插件gulp-htmlmin :html文件压缩gulp-csso :压缩cssgulp-babel :JavaScript语法转化gulp-less: less语法转化gulp-uglify :压缩混同JavaScriptgulp-file-include 公共文件蕴含browsersync 浏览器实时同步

October 23, 2020 · 1 min · jiezi

过滤器-和-拦截器6个区别别再傻傻分不清了

周末有个小伙伴加我微信,向我请教了一个问题:老哥,过滤器 (Filter) 和 拦截器 (Interceptor) 有啥区别啊? 听到题目我的第一感觉就是:简单! 毕竟这两种工具开发中用到的频率都相当高,应用起来也是比较简单的,可当我准备回复他的时候,竟然不知道从哪说起,支支吾吾了半天,场面炒鸡尴尬有木有,工作这么久一个基础问题答成这样,丢了大人了。 平时觉得简单的知识点,但通常都不会太关注细节,一旦被别人问起来,反倒说不出个所以然来。 归根结底,还是对这些知识了解的不够,一直停留在会用的阶段,以至于现在一看就会一说就废!这是典型基础不扎实的表现,哎·~,其实我也就是个虚胖! 知耻而后勇,下边结合实践,更直观的来感受一下两者到底有什么不同? 准备环境我们在项目中同时配置 拦截器 和 过滤器。 1、过滤器 (Filter) 过滤器的配置比较简单,直接实现Filter 接口即可,也可以通过@WebFilter注解实现对特定URL拦截,看到Filter 接口中定义了三个方法。 init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。注意:这个方法必须执行成功,否则过滤器会不起作用。doFilter() :容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。destroy(): 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次@Componentpublic class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("Filter 前置"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("Filter 处理中"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("Filter 后置"); }}2、拦截器 (Interceptor) ...

July 8, 2020 · 3 min · jiezi

gulp构建reacttypescript项目十一构建检查tsx

本文主要对以下部分进行处理; 构建tsx路径映射eslint检查tsx一、构建tsx1、安装相关依赖,本文选择tsify插件来解析tsx,tsify会根据tsconfig.json配置来解析tsx,传送门:https://www.npmjs.com/package...。 cnpm i -D tsify2、构建脚本 const _script = () => { return browserify({ entries: _path.main_js, debug: isDev, // 生成inline-sourcemap }).plugin(tsify) .transform(babelify, { presets: ['@babel/preset-env', '@babel/preset-react'], plugins: [ '@babel/plugin-transform-runtime', ['@babel/plugin-proposal-decorators', { 'legacy': true }], ['@babel/plugin-proposal-class-properties', { 'loose': true }] ] }) .bundle() .pipe(gulpif(isDev, exorcist(path.resolve(__dirname, 'dist/js/app.js.map')))) // 生成外部map .pipe(source('app.js')) .pipe(buffer()) .pipe(gulpif(isProd, uglify())) .pipe(gulpif(isProd, rename({suffix: '.min'}))) .pipe(gulp.dest('./dist/js')) .pipe(gulpif(isDev, connect.reload()));};3、tsconfig.json配置 { "compilerOptions": { "target": "es5", "module": "commonjs", "jsx": "react", "strict": true, "noImplicitAny": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }}二、路径映射路径映射需要配置两个地方,构建脚本和tsconfig.json,因为执行构建脚本时他并不知道tsconfig.json当中的路径配置,所以两个地方都需要统一配置。1、tsconfig.json加上路径映射 ...

June 29, 2020 · 1 min · jiezi

gulp构建react项目十根据不同环境进行构建配置eslintsourcemap

背景在项目工程化中,通常根据不同的环境对项目进行构建,一般环境主要有开发、测试、预生产、生产。开发环境下关注规范、测试,而其他环境主要关注性能、安全,比如开发环境下进行eslint检查,而其他环境不做eslint检查。 项目相关依赖 cnpm i -D cross-env gulp-if gulp-eslint babel-eslint gulp-sourcemaps exorcistexorcist用于在外部生成map文件目录结构 gulp├── src│ ├── components│ │ ├── Test│ │ | └── index.jsx│ │ ├── Child│ │ | ├── index.css│ │ | └── index.jsx│ │ ├── Count│ │ | ├── index.css│ │ | └── index.jsx│ └── App.jsx ├── node_modules├── .eslintignore├── .eslintrc.js├── index.js├── gulpfile.js├── index.html└── package.jsonpackage.json执行脚本 "scripts": { "dev": "cross-env NODE_ENV=dev gulp dev", "build": "cross-env NODE_ENV=prod gulp build" },脚本 ...

June 28, 2020 · 3 min · jiezi

gulp构建react项目八给linkscript引入链接加上版本号

相关依赖 // 根据文件生成hash值附加到html和css文件中的资源引用。cnpm i -D gulp-res-version项目结构 gulp├── src│ ├── components│ │ ├── Test│ │ | └── index.jsx│ │ ├── Child│ │ | ├── index.css│ │ | └── index.jsx│ │ ├── Count│ │ | ├── index.css│ │ | └── index.jsx│ └── App.jsx ├── node_modules├── index.js├── gulpfile.js├── index.html└── package.json脚本 // index.jsimport './src/App.jsx'// src/App.jsximport React from 'react'import { render } from 'react-dom'import Test from './components/Test/index.jsx'render(<Test />, document.getElementById("app"))// src\components\Test\index.jsximport React from 'react'import Child from '../Child/index.jsx'import Count from '../Count/index.jsx'export default class Test extends React.Component { state = { msg: 'hello, world' } render() { const { msg } = this.state return ( <React.Fragment> <Child msg={msg}/> <Count /> </React.Fragment> ) }}// src\components\Count\index.jsximport React from 'react'export default class Count extends React.Component { state = { count: 0, msg: '显示一个计数器' } subFn = () => { this.setState((prevState, props) => ({ count: prevState.count - 1 })) } plusFn = () => { this.setState((prevState, props) => ({ count: prevState.count + 1 })) } render() { const { count, msg } = this.state return ( <div> <p className="count-text">{msg}</p> <div> <button onClick={this.subFn}>-</button> <span>{count}</span> <button onClick={this.plusFn}>+</button> </div> </div> ) }}// src\components\Count\index.css.count-text { font-size: 14px; font-family: Arial, Helvetica, sans-serif; font-weight: 400; color: red;}// src\components\Test\index.jsximport React from 'react'const Child = (props) => <div className="color">{props.msg}</div>export default Child// src\components\Test\index.css.color { color: red;}构建脚本 ...

June 24, 2020 · 2 min · jiezi

gulp构建react项目七将jscsshtml压缩

相关依赖包 cnpm i -D gulp-uglify gulp-cssmin gulp-minify-html gulp-rename项目结构 gulp├── src│ ├── components│ │ ├── Test│ │ | └── index.jsx│ │ ├── Child│ │ | ├── index.css│ │ | └── index.jsx│ │ ├── Count│ │ | ├── index.css│ │ | └── index.jsx│ └── App.jsx ├── node_modules├── index.js├── gulpfile.js├── index.html└── package.json脚本 // index.jsimport './src/App.jsx'// src/App.jsximport React from 'react'import { render } from 'react-dom'import Test from './components/Test/index.jsx'render(<Test />, document.getElementById("app"))// src\components\Test\index.jsximport React from 'react'import Child from '../Child/index.jsx'import Count from '../Count/index.jsx'export default class Test extends React.Component { state = { msg: 'hello, world' } render() { const { msg } = this.state return ( <React.Fragment> <Child msg={msg}/> <Count /> </React.Fragment> ) }}// src\components\Count\index.jsximport React from 'react'export default class Count extends React.Component { state = { count: 0, msg: '显示一个计数器' } subFn = () => { this.setState((prevState, props) => ({ count: prevState.count - 1 })) } plusFn = () => { this.setState((prevState, props) => ({ count: prevState.count + 1 })) } render() { const { count, msg } = this.state return ( <div> <p className="count-text">{msg}</p> <div> <button onClick={this.subFn}>-</button> <span>{count}</span> <button onClick={this.plusFn}>+</button> </div> </div> ) }}// src\components\Count\index.css.count-text { font-size: 14px; font-family: Arial, Helvetica, sans-serif; font-weight: 400; color: red;}// src\components\Test\index.jsximport React from 'react'const Child = (props) => <div className="color">{props.msg}</div>export default Child// src\components\Test\index.css.color { color: red;}构建脚本 ...

June 24, 2020 · 2 min · jiezi

gulp构建react项目六gulpcheerio将打包后的jscss引入到html

项目结构 gulp├── src│ ├── components│ │ ├── Test│ │ | └── index.jsx│ │ ├── Child│ │ | ├── index.css│ │ | └── index.jsx│ └── App.jsx ├── node_modules├── index.js├── gulpfile.js├── index.html└── package.json依赖脚本 // index.jsimport './src/App.jsx'// App.jsximport React from 'react'import { render } from 'react-dom'import Test from './components/Test/index.jsx'render(<Test />, document.getElementById("app"))// Testimport React from 'react'import Child from '../Child/index.jsx'export default class Test extends React.Component { state = { msg: 'hello, world' } render() { const { msg } = this.state return <Child msg={msg}/> }}// Childimport React from 'react'const Child = (props) => <div className="color">{props.msg}</div>export default Childscss ...

June 23, 2020 · 2 min · jiezi

gulp构建react项目四处理css

项目结构 gulp01├── src│ ├── components│ │ ├── Test│ │ | └── index.jsx│ │ ├── Child│ │ | ├── index.css│ │ | └── index.jsx│ └── App.jsx├── node_modules├── index.js├── gulpfile.js├── index.html└── package.json项目依赖 脚本 // index.jsimport './src/App.jsx'// App.jsximport React from 'react'import { render } from 'react-dom'import Test from './components/Test/index.jsx'render(<Test />, document.getElementById("app"))// Testimport React from 'react'import Child from '../Child/index.jsx'export default class Test extends React.Component { state = { msg: 'hello, world' } render() { const { msg } = this.state return <Child msg={msg}/> }}// Childimport React from 'react'const Child = (props) => <div className="color">{props.msg}</div>export default Childcss ...

June 23, 2020 · 2 min · jiezi

gulp构建react项目五gulpsass处理scss

项目结构 gulp01├── src│ ├── components│ │ ├── Test│ │ | └── index.jsx│ │ ├── Child│ │ | ├── index.scss│ │ | └── index.jsx│ └── App.jsx├── node_modules├── index.js├── gulpfile.js├── index.html└── package.json项目依赖脚本 // index.jsimport './src/App.jsx'// App.jsximport React from 'react'import { render } from 'react-dom'import Test from './components/Test/index.jsx'render(<Test />, document.getElementById("app"))// Testimport React from 'react'import Child from '../Child/index.jsx'export default class Test extends React.Component { state = { msg: 'hello, world' } render() { const { msg } = this.state return <Child msg={msg}/> }}// Childimport React from 'react'const Child = (props) => <div className="color">{props.msg}</div>export default Childscss ...

June 23, 2020 · 1 min · jiezi

Webpack与GruntGulp的区别

随着前端发展如日冲天,前端项目也越来越复杂,得益于Nodejs的发展,前端模块化、组件化、工程化也大势所趋。这些年Grunt、Gulp到Webpack随着工程化的发展都大行其道。 前端工程化的早期,主要是解决重复任务的问题。Grunt、Gulp就是其中代表。比如: 压缩、编译less、sass、地址添加hash、替换等。 Grunt官网中就说: 对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,完成大部分无聊的工作。而如今的Webpack更像一套前端工程化解决方案。利用强大插件机制,解决前端静态资源依赖管理的问题。 Webpack作者Tobias回复与 Grunt Gulp NPM脚本的比较Tobias: NPM脚本对我而言足矣。实际上,说webpack是Grunt/Gulp的替代器并不完全准确。Grunt和Gulp以及NPM脚本都是任务执行程序。Webpack是_模块打包程序_。这两类程序的目标不一样。但webpack简化了必须“过度使用”Grunt和Gulp和NPM脚本才能实现的Web开发任务也是事实。NPM脚本才是Grunt和Gulp的替代品。不过,除了纯粹的构建之外,任务运行程序也有存在的理由,比如部署、代码检查、版本管理,等等。 Webpack与Grunt、Gulp运行机制# grunt gulp 思路【遍历源文件】->【匹配规则】->【打包】做不到按需加载,对打包的资源,是否用到,打包过程不关心。# webpack【入口】->【模块依赖加载】->【依赖分析】->【打包】在加载、分析、打包的过程中,可以针对性的做一些解决方案。比如:code split(拆分公共代码) Grunt与Gulp性能比较Grunt: 每个任务处理完成后存放在本地磁盘.tmp目录中,有本地磁盘的I/O操作,会导致打包速度比较慢。Gulp: gulp与grunt都是按任务执行,gulp有一个文件流的概念。每一步构建的结果并不会存在本地磁盘,而是保存在内存中,下一个步骤是可以使用上一个步骤的内存,大大增加了打包的速度。 参考:grunt官网webpack作者接受参访文章

July 3, 2019 · 1 min · jiezi

gulp小结

gulp是什么?一个自动化构建工具,基于nodejs的自动任务运行器。 为什么要使用它?易于使用,易于学习。它能自动化地完成javascript/coffee/sass/less/html/image/css 等文件的的测试、检查、合并、压缩、格式化、浏览器自动刷新、部署文件生成,并监听文件在改动后重复指定的这些步骤。在实现上,她借鉴了Unix操作系统的管道(pipe)思想,前一级的输出,直接变成后一级的输入,使得在操作上非常简单。 和grunt、webpack的区别gulp和grunt非常类似,但相比于grunt的频繁IO操作,gulp的流操作,能更快地更便捷地完成构建工作。前两者定位是工具,webpack则是种模块化解决方案。 说到 browserify / webpack ,那还要说到 seajs / requirejs 。这四个都是JS模块化的方案。其中seajs / require 是一种类型,browserify / webpack 是另一种类型。 seajs / require : 是一种在线"编译" 模块的方案,相当于在页面上加载一个 CMD/AMD 解释器。这样浏览器就认识了 define、exports、module 这些东西。也就实现了模块化。 browserify / webpack : 是一个预编译模块的方案,相比于上面 ,这个方案更加智能。 gulp也能调用webpack。 为什么要用4.0?组合任务。比如以前的gulp对多个异步任务很难控制,必须借助于第三方模块,如run-sequence、event-stream等,效果也并不理想。 现在gulp带来了两个新的api:gulp.series【顺序】和gulp.parallel【并行】,这两个革命性的api将帮助开发者解决恼人的任务流程控制问题。 //clear任务执行完后,才会执行copygulp.task("build", gulp.series("clear","copy") );//inject:home和inject:list这2个任务同时执行 gulp.task("inject-all", gulp.parallel("inject:home", "inject:list" ) );小技巧:一个任务中需要立即执行一下任务,以前版本有gulp run XX,新的没有,但可以这样: gulp.parallel('XX')();gulp.series('XX')();支持异步任务有3种方式确认gulp能够识别任务何时完成。后2者重要是return 回调返回一个流返回一个Promise更多参见这篇文章:http://codecloud.net/10666.html npm包管理包管理主要在根目录下的 package.json文件。scripts中是一些npm的任务,npm run dev 即可执行。 dependencies是项目中必须的包,目前我们没有用到,只有个vue。devDependencies是开发所用的包,发布到生产环境不需要的都放在这里,平时安装时需要用npm install -save-dev XX,可简写作npm i -D XX。 同时安装多个包可以这样:npm install -save-dev aa bb。或者将包复制到package文件里,直接在根目录命令行里npm i或npm install。 ...

June 20, 2019 · 2 min · jiezi

前端培训初级阶段场景实战20190613Nginx代理正确食用方式

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。 截止到 2019-05-30 期,所有成员都进行了一次分享。内部对课程进行了一些调整,之后会针对项目开始 review 。我这边预期准备进入中级阶段,中间还是会穿插一些实战。 前端培训目录 今天讲什么?nginx 的 servernginx 的 location 匹配规则nginx 的 root、rewrite、proxy_pass、aliasnginx 的命令以及报错日志今天为什么会开这个题目? 公司内部的前端构建工具升级(gulp),帮小伙伴处理了一下 nginx 的配置,辅助提升开发的体验。公司想要加快网页访问速度(前端缓存),为了测试,我改了我自己服务器的 nginx 配置。 PWA ()manifest ()其他方案(localStroage存)有老哥有科学有效的方案吗?缓存这块我还在实验中,我司有结果之后我会写个文章发出来。nginx 的 server定义虚拟主机相关。server 中通过 server_name 来匹配域名,listen来匹配端口 server_name用于匹配域名,需要已经映射的域名。举个栗子,我在阿里云有一台云服务器 IP:123.56.16.33:443。买了一个域名 lilnong.top。我现在把我的域名指向了我的ip。那所有请求我域名的都会到我这台服务器上。我需要用 server_name 来判断请求的是那台主机,再进行分发 listen用于匹配端口号,一般来说,我们当做服务的就需要加上 80 和 443 协议端口用途http80浏览器访问https443浏览器访问ftp21 server_name 与 host 匹配优先级完全匹配通配符在前的,如 *.lilnong.top在后的,如 www.lilnong.*正则匹配,如 ~^\.www\.lilnong\.com$如果都不匹配 优先选择 listen 配置项后有 default 或 default_server 的找到匹配 listen 端口的第一个 server 块nginx 的 location 匹配规则location 是什么?location 是用于在 server 服务中,根据 URL 进行匹配查找。属于 ngx_http_core_module 模块。 ...

June 10, 2019 · 2 min · jiezi

gulp构建小程序

目前来说,对于构建小程序的,类似taro这些框架,生态已经挺完善的了,没有什么必要再搞一套来折腾自己。但是,我司的小程序,是很早之前就开发的,我们负责人当时信不过这些开源的框架,于是自己用webpack搞了一套框架,但有一个比较严重的问题,有一些文件依赖重复打包了,导致小程序包体积比较大。 持续了一个多月,主包体积在2M左右徘徊,开发都很难做下去。我们负责人终于受不了了,给了我个任务,让我写一个构建小程序的工具,减少小程序包体积。 我们现在的框架对比一下原生小程序,其实差别不大,无非就是 ts => jssass=>wxsswxml=>wxmljson=>json由于我司小程序基础库是1.9.8的,不支持构建npm,所以node_modules的依赖包以及依赖路径需要自己处理,于是写了一个babel插件 babel-plugin-copy-npm。这么一想,其实不难,而且单文件编译,那不是gulp的强项吗!!! 最终效果: 而且由于增量更新,只修改改变的文件,所以编译的速度非常快。 项目地址:https://github.com/m-Ryan/ry-wx 最终流程大概如下:清除dist目录下的文件 => 编译文件到dist目录下=> 开发模式监听文件更改,生产环境压缩文件。 一、清除dist目录下的文件 (clean.js) const del = require('del');const fs = require('fs');const path = require('path');const cwd = process.cwd();module.exports = function clean() { if (!fs.existsSync(path.join(cwd, 'dist'))) { fs.mkdirSync('dist'); return Promise.resolve(null); } return del([ '*', '!npm' ], { force: true, cwd: path.join(cwd, 'dist') });};二、编译文件 1.编译typescript(compileJs.js)const gulp = require('gulp');const { babel } = require('gulp-load-plugins')();const path = require('path');const cwd = process.cwd();module.exports = function compileJs(filePath) { let file = 'src/**/*.ts'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp.src(file).pipe(babel()).pipe(gulp.dest(dist));};2.编译sass(compileSass.js)const gulp = require('gulp');const { sass, postcss, rename } = require('gulp-load-plugins')();const path = require('path');const cwd = process.cwd();const plugins = [ require('autoprefixer')({ browsers: [ 'ios >= 8', 'ChromeAndroid >= 53' ], remove: false, add: true }), require('postcss-pxtorpx')({ multiplier: 2, propList: [ '*' ] })];module.exports = function compileSass(filePath) { let file = 'src/**/*.scss'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp .src(file) .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError)) .pipe(postcss(plugins)) .pipe( rename({ extname: '.wxss' }) ) .pipe(gulp.dest(dist));};编译json,wxml,由于需要压缩,所以需要分开处理(copyJson.js) ...

May 31, 2019 · 3 min · jiezi

前端必修课ES2017下的构建工具原理与实战

ES2017+,你不再需要纠结于复杂的构建工具技术选型。 也不再需要gulp,grunt,yeoman,metalsmith,fis3。 以上的这些构建工具,可以脑海中永远划掉。 100行代码,你将透视构建工具的本质。 100行代码,你将拥有一个现代化、规范、测试驱动、高延展性的前端构建工具。 在阅读前,给大家一个小悬念:什么是链式操作、中间件机制?如何读取、构建文件树?如何实现批量模板渲染、代码转译?如何实现中间件间数据共享。相信学完这一课后,你会发现————这些专业术语,背后的原理实在。。。太简单了吧! 构建工具体验:弹窗+uglify+模板引擎+babel转码...如果想立即体验它的强大功能,可以命令行输入npx mofast example,将会构建一个mofast-example文件夹。 进入文件后运行node compile,即可体验功能。 顺便说一句,npx mofast example命令行本身,也是用本课的构建工具实现的。——是不是不可思议? 本课程代码已在npm上进行发布,直接安装即可npm i mofast -D即可在任何项目中使用mofast,替代gulp/grunt/yeoman/metalsmith/fis3进行安装使用。 本课程github地址为: https://github.com/wanthering... 在学完课程后,你就可以提交PR,一起维护这个库,使它的扩展性越来越强! 第一步:搭建github/npm标准开发栈请搭建好以下环境: jest 测试环境eslint 格式标准化环境babel es2017代码环境或者直接使用npx lunz mofast 然后一路回车。 构建出的文件系统如下 ├── .babelrc├── .editorconfig├── .eslintrc.js├── .gitignore├── README.md├── circle.yml├── package.json├── src│   └── index.js├── test│   └── index.spec.js└── yarn.lock第二步: 搭建文件沙盒环境构建工具,都需要进行文件系统的操作。 在测试时,常常污染本地的文件系统,造成一些重要文件的意外丢失和修改。 所以,我们往往会为测试做一个“沙盒环境” 在package.json同级目录下,输入命令 mkdir __mocks__ && touch __mocks__/fs.js yarn add memfs -D yarn add fs-extra创建__mocks__/fs.js文件后,写入: const { fs } = require('memfs')module.exports = fs然后在测试文件index.spec.js的第一行写下: ...

May 23, 2019 · 5 min · jiezi

可视化制作之地图制作技巧

背景通常可视化地图我们使用geojson数据+(echarts/highchart等)制作,经常我们业务需要的地图没有合适geojson数据,原因大致如下: 《测绘法》图表地图通常是简易版地图,很难与真实地图一致,导致结果:正规网站不能提供下载第三方能下载到的矢量地图数据只能到国级省级县区级别的行政划分变动频繁(比如前两年的杭州地图不包括临安)地图区域划分可能不同于行政划分思路本文给出的是本人独家解决方法是通过AI制作地图数据,以真实地图或者草图为底,秒出边界和中心,导出svg,通过正则(下面提供一个gulp插件转)转为geojson数据; 为什么使用AI有图层有组合有钢笔制作准确省事有前进有后退不怕出错出了制作地图geojson数据,还可以利用生产svg做各种吊炸天效果(比如3D地图晒个demo)本人美工大佬,精通PS AE AI等等;秀张鼠绘 案例使用方法1.下载git clone https://github.com/yuhonyon/svg2geojson.git2.安装npm i3.使用将 svg 文件直接放在 svg/ 目录下输入命令gulp在 dist/ 目录下将生产对应的目录,目录下有转换后的 geojson 文件以及行政中心的坐标文件和 svg 原文件 教学制作地图 geojson 数据的所有步骤设计地图草稿根据设计稿使用 ai 画矢量地图导出 svg使用 gulp 将 svg 转换为 geojson使用图表库制作地图设计地图草稿设计师设计地图草稿(只需明确行政划分区域即可),如下图 使用 AI 描出矢量图将设计草稿导入 AI新建图层,在图层内跟据设计稿使用钢笔工具描出一个行政区的行政(使用多边形描边)将该图层取名为行政区名字重复第 2 步,描出所有行政区 选择所有描点,转换尖角,去除不小心画出的曲线(导出的 svg 不是由 polygon 组成的而是 path 的时候使用这个方法,建议描完后就使用一次)在每个图层中心处再画一个圆形或者椭圆删除设计草稿的图层导出 svg,没有出错的话格式应该如下如果发现 poluygon 标签变成了 path,请注意第 4 步骤** 注意:导出的 svg 转换出的 geojson 制作的地图将会是垂直颠倒的(可能是坐标轴不一样,一个左上角一个右下角),所以我们要把我们制作的 AI 图垂直翻转后再导出 svg ** 将 svg 转换为 geojson效果

April 29, 2019 · 1 min · jiezi

gulp-gulpbetterrollup-rollup-构建-ES6-开发环境

gulp + gulp-better-rollup + rollup 构建 ES6 开发环境关于 Gulp 就不过多啰嗦了。常用的 js 模块打包工具主要有 webpack、rollup 和 browserify 三个,Gulp 构建 ES6 开发环境通常需要借助这三者之一来合并打包 ES6 模块代码。因此,Gulp 构建 ES6 开发环境的方案有很多,例如:webpack-stream、rollup-stream 、browserify等,本文讲述使用 gulp-better-rollup 的构建过程。gulp-better-rollup 可以将 rollup 更深入地集成到Gulps管道链中。 GitHub地址:https://github.com/JofunLiang/gulp-translation-es6-demo 构建基础的 ES6 语法转译环境首先,安装 gulp 工具,命令如下: $ npm install --save-dev gulp安装 gulp-better-rollup 插件,由于 gulp-better-rollup 需要 rollup 作为依赖,因此,还要安装 rollup 模块和 rollup-plugin-babel(rollup 和 babel 之间的无缝集成插件): $ npm install --save-dev gulp-better-rollup rollup rollup-plugin-babel安装 babel 核心插件: $ npm install --save-dev @babel/core @babel/preset-env安装完成后,配置 .babelrc 文件和 gulpfile.js文件,将这两个文件放在项目根目录下。 ...

April 29, 2019 · 2 min · jiezi

gulp-spritesmith报错记录 Error: Unsupported interlace method

先上图,自行对号入座!原本好好的脚步突然就报错了,查了下gulp-spritesmith的ISSUE居然是图片的内容有问题。。。WTF不折腾的解决方案就是直接用PS打开图片,存储为WEB所有格式,重新输出图片即可解决。。。参考链接:gulp-spritesmith

April 3, 2019 · 1 min · jiezi

gulp插件解决浏览器缓存问题

一、前言有些简单前端小项目,不需要涉及框架,前端打包压缩的话本妹子还是喜欢用gulp。本文将用gulp-rev和gulp-rev-rewrite解决cdn缓存问题。以及列出的是本妹子最常用的gulp插件,小伙伴们可以参考。案例地址:https://github.com/raoenhui/g…二、解决浏览器缓存问题gulp-rev1.为静态文件添加唯一hash值,如 unicorn.css → unicorn-d41d8cd98f.css。2.生成map映射文件,方便后面html更换文件名gulp.task(‘js’, () => gulp.src([’./src/app.js’, ‘./src/app2.js’]) .pipe(gulp.dest(‘dist’)) // 将源文件拷贝到打包目录 .pipe(rev()) .pipe(gulp.dest(‘dist’)) // 将生成的hash文件添加到打包目录 .pipe(rev.manifest(‘js-rev.json’)) .pipe(gulp.dest(‘dist’)) // 将map映射文件添加到打包目录);gulp.task(‘css’,()=> { gulp.src(’./src/.css’) .pipe(gulp.dest(‘dist’)) // 将生成的hash文件添加到打包目录 .pipe(rev()) .pipe(gulp.dest(‘dist’))// write rev’d assets to build dir .pipe(rev.manifest(‘css-rev.json’)) .pipe(gulp.dest(‘dist’)) // 将map映射文件添加到打包目录});gulp-rev-rewrite根据rev生成的manifest.json map映射文件, 去替换html文件中的引用名称,gulp.task(‘html’, () => { const jsManifest = gulp.src(‘dist/js-rev.json’); //获取js映射文件 const cssManifest = gulp.src(‘dist/css-rev.json’); //获取css映射文件 return gulp.src(’./.html’) .pipe(revRewrite({manifest: jsManifest})) // 把引用的js替换成有版本号的名字 .pipe(revRewrite({manifest: cssManifest})) // 把引用的css替换成有版本号的名字 .pipe(gulp.dest(‘dist’))});替换成功三、gulp其他常用插件JS相关gulp-babelbabel是一个 JavaScript 编译器。我们主要是用将ES6转换成可以在浏览器中运行的代码。而gulp-babel 的用法、功能和babel 是一样的。先运行 npm install –save-dev gulp-babel @babel/core @babel/preset-env @babel/plugin-transform-runtime,装好babel。const babel = require(‘gulp-babel’);gulp.task(‘js’, () => gulp.src(‘src/app.js’) .pipe(babel({ presets: [’@babel/env’], plugins: [’@babel/transform-runtime’] })) .pipe(gulp.dest(‘dist’)));gulp-sourcemaps找到编译源文件,方便调试源码。const sourcemaps = require(‘gulp-sourcemaps’);gulp.task(‘js’, () => gulp.src(‘src/app.js’) .pipe(sourcemaps.init()) .pipe(babel({ presets: [’@babel/env’], plugins: [’@babel/transform-runtime’] })) .pipe(sourcemaps.write(’.’)) .pipe(gulp.dest(‘dist’)));gulp-concat合并js文件const concat = require(‘gulp-concat’);gulp.task(‘js’, function() { return gulp.src([’./src/app.js’, ‘./src/app2.js’]) .pipe(concat(‘app.js’)) .pipe(gulp.dest(‘dist’));}); CSS相关gulp-postcssCSS预处理器。const postcss = require(‘gulp-postcss’);const autoprefixer = require(‘autoprefixer’); //添加css兼容性写法gulp.task(‘css’, function () { return gulp.src(’./src/.css’) .pipe(postcss([ autoprefixer({ browsers: [ ‘>1%’, ’last 4 versions’, ‘Firefox ESR’, ’not ie < 9’, ‘iOS >= 8’, ‘Android > 4.4’ ], flexbox: ’no-2009’, }) ])) .pipe(gulp.dest(’./dest’));});gulp-clean-css压缩CSSconst cleanCSS = require(‘gulp-clean-css’);gulp.task(‘css’, () => { return gulp.src(‘styles/.css’) .pipe(cleanCSS({compatibility: ‘ie8’})) .pipe(gulp.dest(‘dist’));});HTML相关gulp-inline-source将引用的js、css文件,插入html中,变成内联式引用。const inlinesource = require(‘gulp-inline-source’);gulp.task(‘html’, function () { return gulp.src(’./.html’) .pipe(inlinesource({ compress: false //是否压缩成一行,默认为true压缩 })) .pipe(gulp.dest(’./out’));});gulp-htmlmin压缩htmlconst htmlmin = require(‘gulp-htmlmin’);gulp.task(‘minify’, () => { return gulp.src(‘src/.html’) .pipe(htmlmin({ removeComments: true, //去除备注 collapseWhitespace: true //去除空白 })) .pipe(gulp.dest(‘dist’));}); 其他del删除文件或文件夹const del = require(‘del’);/* 清理一些不是必须的js,css文件 /gulp.task(‘clean’, function() { return del([’./dist/.js’, ‘./dist/*.css’ ]).then(function() { console.log(‘delete unnecessary files for firecrackers’); });});gulp-rename重命名文件const rename = require(‘gulp-rename’);gulp.task(‘html’, function() {.pipe(rename({ dirname: “.”, // 路径名 basename: “index”, // 主文件名 prefix: “pre-”, // 前缀 suffix: “-min”, // 后缀 extname: “.html” // 扩展名 })).pipe(gulp.dest(‘dist’))});其他链接案例地址:https://github.com/raoenhui/gulpExample.git原文地址:https://raoenhui.github.io/js/2019/03/03/gulpHappy coding .. :) ...

April 1, 2019 · 2 min · jiezi

gulp配置文件gulpfile.babel.js

‘use strict’var gulp = require(‘gulp’);var watch = require(‘gulp-watch’);var babel = require(‘gulp-babel’);let sourcemaps = require(‘gulp-sourcemaps’);let uglify = require(‘gulp-uglify’);gulp.task(’transform’, () => { return gulp.src(‘server//*.js’) // 匹配server文件夹下面的所有js文件 .pipe(sourcemaps.init()) // .pipe(babel()) .pipe(sourcemaps.write(’.’)) .pipe(gulp.dest(‘dist/server’)); // 写入 ‘dist/server/‘文件夹下});gulp.task(‘watch’, () => { return gulp.src(‘server//.js’) .pipe(watch(‘server/**/.js’, { verbose: true })) .pipe(sourcemaps.init()) .pipe(babel()) .pipe(uglify({ mangle: false })) .pipe(sourcemaps.write(’.’)) .pipe(gulp.dest(‘dist/server/’));});// 执行transform任务gulp.task(‘default’, () => { gulp.start(’transform’);});

March 15, 2019 · 1 min · jiezi

前端静态资源自动化处理版本号防缓存

前端静态资源自动化处理版本号防缓存浏览器会默认缓存网站的静态资源文件,如:js文件、css文件、图片等。缓存带来网站性能提升的同时也带来了一些困扰,最常见的问题就是不能及时更新静态资源,造成新版本发布时用户无法及时看到新版本的变化,严重影响了用户体验。上述问题,最简单的办法就是在资源的请求路径上添加版本号,格式如下:url?v=1.0.0每次在更改资源的时候,手动修改版本号,但是每次手动改那么多后缀有些费事,现在有很多的工具可以让我们更轻松的完成这项工具。本文将探讨使用目前最流行的前端构建工具 Gulp 和 Webpack 自动化为静态资源添加版本号防缓存处理。使用 Gulp 处理文件版本Gulp 是一个简单易用的前端自动化构建工具,非常适合于构建多页面的工作流程。安装 Gulp(这里使用的是 Gulp 4+ 版本):$ npm install –save-dev gulp安装 gulp-rev 插件:$ npm install –save-dev gulp-revgulp-rev 插件的作用就是为静态资源添加版本号。新建 gulpfile.js 文件:const gulp = require(‘gulp’);const rev = require(‘gulp-rev’);// 添加版本号gulp.task(‘rev’, () => { return gulp.src(‘src/css/.css’) .pipe(rev()) // 将所有匹配到的文件名全部生成相应的版本号 .pipe(gulp.dest(‘dist/css’)) .pipe(rev.manifest()) //把所有生成的带版本号的文件名保存到rev-manifest.json文件中 .pipe(gulp.dest(‘rev/css’)) //把rev-manifest.json文件保存到指定的路径});执行 rev 任务后,rev/css 文件加下多了一个 rev-manifest.json 文件。rev-manifest.json 文件的内容如下:{ “index.css”: “index-35c63c1fbe.css”}然后,安装 gulp-rev-collector 插件:$ npm install –save-dev gulp-rev-collectorgulp-rev-collector 插件主要是配合 gulp-rev 替换文件版本号。修改 gulpfile.js 文件:const gulp = require(‘gulp’);const rev = require(‘gulp-rev’);// 添加版本号gulp.task(‘rev’, () => { return gulp.src(‘src/css/.css’) .pipe(rev()) // 将所有匹配到的文件名全部生成相应的版本号 .pipe(gulp.dest(‘dist/css’)) .pipe(rev.manifest()) //把所有生成的带版本号的文件名保存到rev-manifest.json文件中 .pipe(gulp.dest(‘rev/css’)) //把rev-manifest.json文件保存到指定的路径});const revCollector = require(‘gulp-rev-collector’);// 控制文件版本号gulp.task(‘rev-collector’, () => { return gulp.src([‘rev//*.json’, ‘src//*.html’]) .pipe(revCollector({ replaceReved: true })) .pipe(gulp.dest(‘dist’))})gulp.task(‘default’, gulp.series(‘clean’, ‘rev’, ‘rev-collector’))执行 gulp 默认任务。检查 dist 下 index.html 文件 css 的版本是否替换成功。使用 Webpack 处理文件版本Webpack 是一个现代 JavaScript 应用程序的静态模块打包器,非常适合于构建单页面的工作流程,当然也可以构建多页面的工作流程。安装 Webpack(这里使用的是 webpack 4+ 版本)。$ npm install –save-dev webpack webpack-cli通过使用 output.filename 进行文件名替换,webpack 使用 [chunkhash] 替换文件名,在文件名中包含一个 chunk 相关(chunk-specific)的哈希。安装 clean-webpack-plugin 插件(清理文件夹):$ npm install –save-dev clean-webpack-pluginclean-webpack-plugin 插件的作用是清理文件夹,由于每次打包的文件版本不同,输出目录会生成很多不同版本的目标文件,所以需要清理文件夹。配置文件 webpack.config.js 如下:const path = require(‘path’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);module.exports = { entry: ‘./src/index.js’, output: { filename: ‘bundle.[chunkhash:5].js’, //这里设置 [chunkhash] 替换文件名,数字5为 chunkhash 的字符长度。 path: path.resolve(__dirname, ‘dist’) }, plugins: [ new CleanWebpackPlugin([‘dist’]) ]}在 src 目录新建一个 index.html 文件:<!DOCTYPE html><html> <head> <meta charset=“utf-8”> <title>Webpack实现静态资源版本管理自动化</title> </head> <body> <script src=“index.js”></script> </body></html>安装 html-webpack-plugin 插件:$ npm install –save-dev html-webpack-pluginhtml-webpack-plugin 插件编译 html 替换带有哈希值版本信息的资源文件。修改 webpack.config.js 文件:const path = require(‘path’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);const HtmlWebpackPlugin = require(‘html-webpack-plugin’);module.exports = { entry: ‘./src/index.js’, output: { filename: ‘bundle.[chunkhash:5].js’, //这里设置 [chunkhash] 替换文件名,数字5为 chunkhash 的字符长度。 path: path.resolve(__dirname, ‘dist’) }, plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title: ‘Webpack实现静态资源版本管理自动化’ }) ]}html-webpack-plugin 默认入口文件为 index.html,具体的参数配置请参考https://www.npmjs.com/package/html-webpack-plugin。关于 Webpack 处理缓存的更多教程请移步官方文档。符录usuallyjs函数库: https://github.com/JofunLiang/usuallyjs ...

March 5, 2019 · 2 min · jiezi

Gulp和webpack的区别

背景:今天了解了大厂前端任职的一些要求:里面写了要熟悉webpack打包工具和Gulp构建工具,作为前端新人,看到这个就想这两种工具有什么区别?在这里解答一下自已,而且希望可以帮助到额疑问的人.Gulp构建工具gulp是工具链,构建工具,可以配合各种插件做JS压缩,CSS压缩,less编译替代手机实现自动化工作.所以它的主要作用是1.构建工具2.自动化3.提高效率Webpack打包工具web是文件打包工具,可以把项目的各种js文件,css文件等打包合成一个或多个文件,主要用于模块化方案,预编译模块的方案所以它的主要作用是1.打包工具2.模块化识别3.编译模块代码方案当然也会有部分相似的功能,比如合并,区分.本文内容转载自此链接,可点击跳转.推荐一篇gulp入门的博文,点击可马上开始学习,作者的博客很给力喜欢

February 28, 2019 · 1 min · jiezi

使用gulp和scss构建样式库

目的为了更好地复用样式,以及出于练习gulp、scss和学习mocha的目的,我在尝试使用gulp、scss构建一个用于pc端的样式库,使用mocha进行浏览器端的测试。为了方便起见,脚本没有使用纯javascript编写,而是选择了jquery。目前,基本的框架已经搭好,正在完善样式中。目录结构lib –> 源代码库scss –> scss代码库mixins –> 共用mixinscomponents –> 组件layouts –> 布局text –> 文字和文本utilities –> 实用的scssstate –> 状态variables –> 变量js –> 组件使用的jsvendor –> 第三方资源(js和css)dist –> 打包后的文件(js和css)examples –> 例子(ejs)test –> 单元测试css命名方式样式库使用前缀+主体+表现的形式命名,比如.c-btn-color–primary。前端的部分使用单横杆连接,状态使用双横杆形式。命名有些丑陋,这是参考命名空间和BEM后的一种尝试。前缀主要区分各自的作用,它们包括:c —> 组件类u —> 实用类l —> 布局类is —> 状态类(显示、隐藏等)t —> 文字或排版类js —> js钩子(表示使用js)其它对于项目的详情,请点击这里遇到的问题由于第一次使用gulp,不可避免地遇到了一些问题,记录如下:gulp4的使用gulp的中文文档是gulp3的,安装gulp3的方法使用,会发现gulp没有找到任务的情况。在gulp4,创建一个任务应该是:function task() { // 需要返回stream、promise或者其他类型(详见gulp4文档) return gulp.src(…).pipe(…);}// 导出default任务exports.default = task;在多个任务的情况,可以使用series和parallel,来分别指定顺序执行和并行,而且可以相互嵌套。下面是一个例子:// 假设各个task已经定义。exports.default = series( task1, parallel(task2, task3));这样,导出的default任务就是先执行task1,然后task2和task3同时执行。gulp-order的使用我在项目中使用了gulp-concat用于拼接js文件,这时,遇到的问题是怎么确定文件的顺序,有的文件有顺序要求。这是一个例子:function task() { return gulp.src(“js/*.js”) .pipe(order([ “js/component.js”, “!js/index.js”, “js/index.js” ], {base: “./”})) .pipe(concat(“main.js”)) .pipe(dest(“dist”));}上面的任务表示先合并component.js然后合并非index.js的文件,最后合并index.js,至于base用于设置基本路径,不使用base可以会发现文件没有合并。最后由于本人能力有限,如有错误,欢迎指出;如果有什么建议,请不吝赐教。

February 21, 2019 · 1 min · jiezi

Gulp4 Koa项目简单配置示例

介绍这段配置是之前的gulp版本不适配新版本node后,更新到了gulp4的新写法。在业务中,目前使用这份配置的是一个Koa2+njk项目,所以增加了nodemon来启动server。分别用到的技术为:Less + autoprefixer + cleancss + sourceMapJs + es6(babel) + uglify + sourceMapBrowserSync For auto reloadNodemon for restart Koa2 server配置废话不多说,上代码:/* * Gulp4通用配置 * Author: Kinice * Time: 2018-12-26 /const gulp = require(‘gulp’)const path = require(‘path’)const less = require(‘gulp-less’)const browserSync = require(‘browser-sync’).create()const reload = browserSync.reloadconst cleancss = require(‘gulp-cssnano’)const autoprefixer = require(‘gulp-autoprefixer’)const pump = require(‘pump’)const uglify = require(‘gulp-uglify’)const sourcemaps = require(‘gulp-sourcemaps’)const babel = require(‘gulp-babel’)const nodemon = require(‘gulp-nodemon’)const changed = require(‘gulp-changed’)const config = require(’./config’)const port = process.env.PORT || config.port// 将所需的资源path放到一起便于管理const paths = { style: { src: ‘src/less/**/.less’, dest: ‘public/css/’ }, script: { src: ‘src/js//*.js’, dest: ‘public/js/’ }, view: { src: ‘views//*.njk’, dest: ‘views/’ }}// 处理less的taskfunction style(callback) { // pump提供了中断pipe的callback return pump([ gulp.src(path.join(__dirname, paths.style.src)), // 开启sourcemap以方便调试 sourcemaps.init(), less(), autoprefixer({ browsers: [ ‘>1%’, ’last 10 version’, ‘iOS >= 8’ ] }), cleancss(), sourcemaps.write(‘maps’), gulp.dest(path.join(__dirname, paths.style.dest)), reload({ stream: true }) ], callback)}// 处理js的taskfunction script(callback) { return pump([ gulp.src(path.join(__dirname, paths.script.src)), sourcemaps.init(), babel(), uglify(), sourcemaps.write(‘maps’), gulp.dest(path.join(__dirname, paths.script.dest)) ], callback)}// 监测文件修改并调用相应task之后刷新页面function watch() { gulp.watch(path.join(__dirname, paths.style.src), style) gulp.watch(path.join(__dirname, paths.script.src), script) gulp.watch(path.join(__dirname, ${paths.style.dest}*.css)).on(‘change’, reload) gulp.watch(path.join(__dirname, ${paths.script.dest}*.js)).on(‘change’, reload) gulp.watch(path.join(__dirname, ${paths.view.dest}*.njk)).on(‘change’, reload)}// 使用nodemon启动node server,如果不含node就去掉function server() { nodemon({ script: ‘app.js’ }) browserSync.init({ proxy: http://localhost:${port} })}exports.style = styleexports.script = scriptexports.watch = watch// 同步执行script和style tasklet build = gulp.parallel(script, style)// 先build,再同步启动node server和开启文件监测gulp.task(‘default’, gulp.series(build, gulp.parallel(server, watch))) ...

January 20, 2019 · 1 min · jiezi

Javascript五十问——从源头细说Webpack与Gulp

前言:Webpack 与 gulp是目前圈子内比较活跃的前端构建工具。网上有很多二者比较的文章,面试中也会经常遇到gulp,Webpack的区别这样的问题。对于初学者来说,对这二者往往容易认识不清,今天,就从事件的源头,说清楚Webpack与gulp。Gulp那是2014年,虽然JQuery风光多年,但是前端却暗流涌动;MVVM刚刚提出不久,Angular快速成长,而React和Vue也刚刚开源不到一年,尚属于冷门小语种。那个时候,前端工作者面临的主要矛盾在于日益增长的业务复杂化的需求同落后低效率的前端部署。开发工作者为了发布一个网站,往往会重复的进行一些与开发无关的工作,手动完成这些工作会带来很大的挫败感。这个时候,自动化构建工具及应运而生,gulp就是在大浪淘沙中的胜利者。Gulp是基于流的前端构建工具,nodejs的stream操作来读取和操作数据;可以实现文件的转换,压缩,合并,监听,自动部署等功能。gulp拥有强大的插件库,基本上满足开发需求,而且开发人员也可以根据自己的需求开发自定义插件。难得是,gulp只有五个api,容易上手。const gulp = require(‘gulp’);const sass = require(“gulp-sass”)gulp.task(“sassStyle”,function() { gulp.src(“style/*.scss”) .pipe(sass()) .pipe(gulp.dest(“style”))})上面就是一个基本的gulpfile配置文件,实现了scss文件到css文件的转换;在终端输入gulp sassStyle就能够进行文件处理了。对于gulp而言,会有一个task,这个task只会做一件事,比如将sass格式的文档转换成css文件;对于一个task而言,会有一个入口文件,即gulp.src,最会有一个目标文件,即gulp.dest;一入一出,可以将gulp理解为 一元函数,输入一个x,根据funcion产出一个y。Gulp简单,快速,自动化的构建方案,收获了很多开发者的喜爱。但是怎样的机遇,让webpack占据了前端工程化的半壁江山呢?Webpack解决方案永远是紧跟需求的脚步的。随着React与Vue份额越来越大,spa开发模式应用在越来越多的领域中,而ES6 Module语法的提出与大规模应用,模块化开发方式越来越受人们的青睐。致使前端文件之间的依赖性越来越高,这时候就需要一个工具能够解析这些依赖,并且将它们有条理的打包起来,优化请求,最好顺便能够解析成浏览器可以识别的语言——这正是webpack所承担的工作;而很多开发者,也是从react或者vue的项目入手webpack的。图片来源于互联网,侵删Webpack 是前端资源模块化 管理和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分割,等到实际需要的时候再异步加载——来自Webpack官方网站。所以Webpack只完成两件事:按需加载,打包。module.exports = { // 入口文件,是模块构建的起点,同时每一个入口文件对应最后生成的一个 chunk。 entry: { bundle: [ ‘webpack/hot/dev-server’, ‘webpack-dev-server/client?http://localhost:8080’, path.resolve(__dirname, ‘app/app.js’) ] }, // 文件路径指向(可加快打包过程)。 resolve: { alias: { ‘react’: pathToReact } }, // 生成文件,是模块构建的终点,包括输出文件与输出路径。 output: { path: path.resolve(__dirname, ‘build’), filename: ‘[name].js’ }, // 这里配置了处理各模块的 loader ,包括 css 预处理 loader ,es6 编译 loader,图片处理 loader。 module: { loaders: [ { test: /.js$/, loader: ‘babel’, query: { presets: [’es2015’, ‘react’] } } ], noParse: [pathToReact] }, // webpack 各插件对象,在 webpack 的事件流中执行对应的方法。 plugins: [ new webpack.HotModuleReplacementPlugin() ]};上面是比较简单的webpack配置文件 webpack.config.js,如果说gulp是一个一元函数,那么,webpack就是一个多元函数或者是加工厂;webpack从入口文件开始,递归找出所有依赖的代码块,再将代码块按照loader解析成新内容,而在webpack会在各个特定的时期广播对应事件,插件会监听这些事件,在某个事件中进行特定的操作。通俗一点来说,webpack本身来递归找到各个文件之间的依赖关系,在这个过程中,使用loaders对文件进行解析,最后,在各个不同的事件阶段,插件可以对文件进行一个统一的处理。webpack.config文件会包括以下几部分:1.entry:入口,webpack问此文件入手迭代。2.output: 打包后形成的文件出口。3.module: 模块,在webpack中一个模块对应一个文件。webpack会从entry开始,递归找出所有依赖的模块4.loaders:文件解析的各种转换器5.plugin:拓展插件webpack的配置文件和构建方式比较复杂,这里不再赘述,感兴趣的同学可以参考我列出来的参考文献第三篇文章,或者可以关注我的专栏,后期我会出一篇关于webpack的学习笔记。比较所以,我们可以看出来,虽然Webpack与gulp都是前端工程化的管理工具,但是二者的侧重点不同——gulp更加关注的是自动化的构建工具,你把代码写好了,gulp会帮你编译、压缩、解析。而Webpack关注的是在模块化背景下的打包工作;它侧重的还是如何将依赖的文件合理的组织起来,并且实现按需加载。总结总的来说,虽然webpack以打包起家,但是gulp能够实现的功能,Webpack也能做;那么,是不是我们以后都要唯webpack马首是瞻呢?非也,非也!webpack功能强大,但是它的缺点也来自于此;webpack并非一个轻量级的工具,学习曲线也非gulp那般平缓。曾经,gulp为了弥补js打包方面的不足,也有gulp-webpack插件的出现;但是webpack强大如斯,如果仅仅只是解析es6文件,未免有大马拉小车之感。根据我的项目实践经验,如果你要构建一个复杂的项目,项目使用vue或者react,模块化引领,那么请选择Webpack,Webpack天生模块化,更加适合于SPA的应用场景,而gulp在SPA下明显后力不足。如果你只是开发一个工具,请选择gulp,至于js打包这种工作,有更加专一的rollup。毕竟,如果只是写一个年会抽奖工具活跃气氛,就不需要webpack火种送碳了。总结下来:gulp与Webapck是各有所长,并不存在东风压倒西风,而在前端工程化的大旗下,并非只有Webpack与gulp,我们还能看到rollup与browserify的一席之地。因此,在真正的工作中,还是要结合项目本身特点,切忌人云亦云。参考文献1、JavaScript开发者的工具箱 非常实用2、Gulp官网3、超级详细的Webpack解读—五星推荐4、端构建工具之争——Webpack vs Gulp 谁会被拍死在沙滩上—五星推荐 ...

January 17, 2019 · 1 min · jiezi

Gulp 4: gulp.parallel gulp.series -- 全新的任务执行体系

Gulp 4 在任务执行体系上有一个很重要的改动,下面我们一起来看一下这个新的特性和如何从Gulp 3迁移到新版本Gulp 3中的任务执行链在了解新特性之前,让我们先看看之前是怎么做的。通常Gulp允许给task定义依赖(dependency),这保证了task执行之前它依赖的task已经获得执行。看下面代码:// 默认任务,执行scripts和styles这两个任务gulp.task(‘default’, [‘scripts’, ‘styles’], function() {…});// scripts 和 styles 任务都调用了 clean 任务gulp.task(‘styles’, [‘clean’], function() {…});gulp.task(‘scripts’, [‘clean’], function() {…});// Clean 任务清空了build目录gulp.task(‘clean’, function() {…});这是很典型的Gulpfile代码,你目的是执行scripts任务和styles任务,在此之前把build输出的目录清空以保证每次都都可以获得最新的build结果。这种语法很优雅,跟其他构建工具也类似。当Gulp开始工作,它会创建一个任务依赖树,见下图。它发现clean任务是另外两个task的依赖,从而确保clean只执行一次。有一点需要注意:所有task都以最大并发量执行。它(default task)的执行顺序见下图:首先执行clean任务,然后并行执行scripts和styles任务。这种方式有一些问题:一旦你定义了上面的依赖链,依赖链的执行顺序就被确定了。例如,给其中一个styles任务添加了监听(watcher)当css文件改变时重新执行styles任务,这时候就会出问题。想象一下,你每次改动了css文件就会触发styles任务,gulp会首先执行clean然后执行styles。如此一来,你构建打包的文件会因为clean任务执行被删除。目前没有好的办法来顺序执行前面定义的各个task。“执行某一任务前先执行其依赖的任务” – 这种执行方式导致了前面的问题。有一个Gulp插件用来解决这个问题:run-sequence。它现在已经是Gulp 4的一部分了。Gulp 4中的任务执行函数Gulp 4抛弃了依赖参数(dependency parameter),用执行函数来代替:gulp.series 用于串行(顺序)执行gulp.parallel 用于并行执行上面的两个函数接受两个参数:要执行的任务的名字需要执行的函数如果你想并行执行scripts和styles,你可以这么写:gulp.task(‘default’, gulp.parallel(‘scripts’, ‘styles’));更棒的是,gulp.parallel和gulp.series是函数,可以接受其它函数做参数,所以你可以随意嵌套使用它们,从而创建复杂的执行顺序。上图的执行顺序是:A, 然后 B, 然后 C 和 D 并行执行, 最后 E。从Gulp 3迁移到Gulp 4尽量让任务以最大并发量执行可以提高执行效率,我们可以考虑把依赖的任务数组替换为gulp.parallel函数,最上面的任务代码可以改为像下面这样:gulp.task(‘styles’, gulp.parallel(‘clean’, function() {…}));gulp.task(‘scripts’, gulp.parallel(‘clean’, function() {…}));gulp.task(‘clean’, function() {…});gulp.task(‘default’, gulp.parallel(‘scripts’, ‘styles’));这个方法的第一个问题是,执行scripts任务和styles任务时,clean任务会先执行。在并发的情况下,这意味着,执行styles时,可能把scripts任务的输出删掉。我们不想这样,让我们把上面的代码修改一下,使用gulp.series来创建串行执行的任务。gulp.task(‘styles’, gulp.series(‘clean’, function() {…}));gulp.task(‘scripts’, gulp.series(‘clean’, function() {…}));gulp.task(‘clean’, function() {…});gulp.task(‘default’, gulp.parallel(‘scripts’, ‘styles’));这样好多了,然而还有需要解决的问题。首先,依赖仍然写死在了代码里,我们执行scripts或者styles时,clean任务会先被执行。其次,Gulp 4 不会进行依赖检查,我们的执行树(执行default task)看起来像这样:clean任务被执行两次,这是致命的,因为有可能上一个任务的执行结果被下一个任务的执行删除。为了做一次完美的健壮的迁移,实现最初的执行顺序,并且避免写死代码,我们可以这样做:先来看一下最初的执行顺序:default task的执行顺序是:先clean,然后styles和scripts并行执行。每一个可以并发进行的步骤可以组合在gulp.parallel函数中,其余的任务按顺序放在gulp.series函数中,像这样:对应的代码是:// 去掉了clean任务依赖gulp.task(‘styles’, function() {…});gulp.task(‘scripts’, function() {…});gulp.task(‘clean’, function() {…});// Per default, start scripts and stylesgulp.task(‘default’, gulp.series(‘clean’, gulp.parallel(‘scripts’, ‘styles’), function() {…}));这样一来,default task的任务执行顺序就跟最初一样了。 ...

December 30, 2018 · 1 min · jiezi

如何gulp压缩,丑化代码

为什么使用最近在迭代公司的项目,发现项目有如下缺点:代码没有压缩,js文件,内存大,放在服务器上占空间;源代码没有混淆或者丑化处理,本公司的程序员写出来的代码和高质量逻辑容易被其他公司的程序员盗用;js,css 文件数量多,浏览器加载起来会“手忙脚乱”和“生气”。这个小项目使用gulp构建工具写的,所以很自然用gulp下的一系列插件来完成。其中用到的插件有:gulp-concat整合数量大的文件为一个文件,gulp-uglify丑化代码,不让别人轻易得到你的源码,gulp-uglify重新命名文件名称等等实现运行cnpm i gulp-concat gulp-uglify gulp-rename –save-dev 安装这三个包 –save-dev的意思就是在开发环境;这几个插件使用起来还好,容易,比较曲折一点的就是gulp-uglify: 我一开始是上npm官网安装了一个最新版的uglify可是没有用,我百度,谷歌折腾了一会,同事和我说vue-cli项目就有这个gulp功能,让我去参考如何使用。原来是uglify的版本不一样,我把版本从最新版降级到2.0.0就可以了。“gulp-uglify”: “^2.0.0”,其中使用代码如下:(js部分)//丑化js代码gulp.task(‘compress’, function () { gulp.src(’./src/oldJs/*.js’) //注意路径的写法 .pipe(concat(‘main.js’)) //合并所有js到main.js .pipe(rename({suffix: ‘.min’})) //rename压缩后的文件名 .pipe(uglify({ //丑化js代码,相当加密 sourceMap: false, compress: { warnings: false, drop_console: true, drop_debugger: true, }, mangle: {except: [’$super’, ‘$’, ’exports’, ‘require’,‘avalon’]} //排除关键字 })) .pipe(gulp.dest(’./src/js’)); //注意路径的写法});//????????????????????????其中源文件夹和输出文件夹的路径要看具体项目而言。最后,运用这个知识点,你会发现代码简洁,内存变小,js文件的数量也控制在1了,不是挺好的吗,嘿嘿。

December 19, 2018 · 1 min · jiezi

【项目记录】个人主页设计和实现

思路希望有一个站点可以归并技术文章、产品探索、生活记录和项目代码。技术文章Hexo活跃齐全的生态的确很诱人,但通过Github管理文章、图片资源其实并不是很优雅。再者,存在流通和传播上的问题。现有的专栏平台支持标签和交流功能,也可手动设计标题代替类别目录,够够的,于是选择了segmentfault。 产品探索研究一些好用的应用,个人对产品的思考,记在知乎专栏。生活记录日志、画、书音影,豆瓣再合适不过。项目代码自然是GitHub。个人站点即一个集中入口,简单明了的首页+个人介绍页,完毕。开发流程在iPad上画了个草图,四个明晃晃的入口,要有Logo。各种分辨率的屏上表现不差劲,用SVG。资源请求尽量简单,SVG样式可控,svg-sprite,那得上gulp了。gulp处理完的symbol要插入页面,加上入口项复用,用模板吧,熟悉的是handlebars。既然上了gulp,干脆SCSS,livereload,dev-server都搞一搞。为什么一个简单的页面要搞那么复杂,练手而已。开发记录gulp4 的更新gulp默认装了4.0.0的版本,很久没关注。增加gulp.series和gulp.parallelgulp默认最大化并行执行任务,以往需要顺序执行任务时,需要借助辅助插件run-sequence之类。上述两个方法提供串行和并行选择,同时gulp4中不再支持[task]写法,必须使用上述两个方法代替。gulp.series(‘clean’, ‘build’); // 先执行clean task,再执行build taskgulp.series(‘clean’, function () { // do some things});gulp.parallel(‘watch’, ‘connect’) // 同时执行watch和connectgulp.series(‘clean’, gulp.parallel(‘styles’, ‘scripts’)) // 先执行clean,然后styles + scriptsgulp.watch(‘src/**/*.js’, [‘scripts’]) // error: watch task has to be a function (optionally generated by using gulp.parallel or gulp.series)异步任务需要结束信号当任务中可能有异步代码(比如watch,比如dev-server),需要显示发出异步完成信号在Gulp 3.x中,你可以在不这样做的情况下离开。如果您没有显式地发出异步完成信号,则只会假设您的任务是同步的,并且在任务函数返回后立即完成。 Gulp 4.x在这方面更加严格。您必须明确表示任务完成。支持的写法挺潮的DONE项目仓库:https://github.com/curlywater…线上效果:https://curlywater.github.io/主内容区布局豆瓣卡片动画TODO页脚设计Github卡片动画单位转换移动端动效

December 18, 2018 · 1 min · jiezi

写GULP遇到的ES6问题详解

Gulp.js 是一个自动化构建工具,开发者可以使用它在项目开发过程中自动执行常见任务。最近复习一下gulp一些基本的写法,在写了一些简单的uglify,rename,concat,clean的处理之后,发现都还记得这些基本语法。然后无意间就想在demo中写下export function会变成怎样,结果发现gulp并不支持直接的es6语法,而且提示的错误也让人模棱两可。events.js:182 throw er; // Unhandled ’error’ event ^GulpUglifyError: unable to minify JavaScript这着实让我头疼了一会,百度后才明白这是解析es6语法错误。于是按照网上说的安装了gulp-babel,然后配置一个.babelrc的文件,再根据报错提示安装了@babel/core,结果发现编译是不报错了,但是编辑结果后的文件还是出不来。gulp.task(‘miniJS’, function(){ gulp.src([‘demo.js’, ‘demo2.js’]) .pipe(concat(‘demoFile.js’)) .pipe(babel()) .pipe(gulp.dest(’./finalFile/’))})//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860后来索性直接去了gulp-babel官网看,才明白3个月之前gulp-babel进行了更新,而我更新的是最新的gulp-babel包,而我搜索到的解决方法都是很早之前的,自然无法匹配。官网提示方法:# Babel 7$ npm install –save-dev gulp-babel @babel/core @babel/preset-env//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860 # Babel 6$ npm install –save-dev gulp-babel@7 babel-core babel-preset-env所以gulp-babel版本为8.0.0的只要安装如图的包就好了:"@babel/core": “^7.1.6”, “gulp-babel”: “^8.0.0”,"@babel/preset-env": “^7.1.6”,这个 @babel/preset-env 包就算没有安装也并不会报错确实是坑,安装好需要的包后根据官网给的样例:.pipe(babel({ presets: [’@babel/env’] }))同时需要去除掉创建的.babelrc文件,好像两者会有冲突,.babelrc文件存在的同时导致不会输出编译后的文件。这样一来export关键字就有用武之地了,但是在es6中function demoFunc(){ //something}//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860export demoFunc;这段代码是生效的,但是babel()好像认定是个解析不出的代码,不会解析输出文件,不知道是什么问题,我也处于懵逼中。换成如下的方式是可以的:export function demo(){ console.log(’this is the first gulp demo’);} export var num = {};这样一来uglify就可以对es6进行解析了:.pipe(babel({ presets: [’@babel/env’]}))//欢迎加入前端全栈开发交流圈一起吹水聊天学习交流:864305860.pipe(uglify()).pipe(gulp.dest(‘file’))结语感谢您的观看,如有不足之处,欢迎批评指正。

December 10, 2018 · 1 min · jiezi

前端构建:3类13种热门工具的选型参考

前言在前端项目的规模和复杂性不断提升的情况下,各类构建思想和相应工具层出不穷。本文竭己所能对比了当下13个构建工具,包括Browserify、Webpack、Rollup、Grunt、Gulp和Yeoman6个广为流行的工具,FIS、Athena、WeFlow和Cooking等4个国产工具,以及三大框架:React,Vue和Angular的官方脚手架。希望能在项目初期的构建工具选型上为大家提供些参考。全览构建工具可以分为三类:模块化打包类、任务流构建类和集合型工具类(脚手架)。其中最为突出的,当属用于模块化打包的Webpack和用于任务流构建的Gulp。下面是截至2018年11月28日某时某刻,GitHub上各个工具的Star数目(听说Star数目可以造假?好生无聊的家伙们!)。前端的构建一般包括JS转码(使用Babel转ES6或TypeScript自转等)、CSS转码(Less或Sass转Css)、代码或资源的合并与压缩,基础检查和各类测试等等。这些虽与本文关系密切,但都不在讨论的范围之内。原因有二:一是实现这些功能的都是某些插件,不是工具本身,各类构建工具都是直接或间接(调用以自己的模式封装后的插件)使用它们的;二是本文介绍的是,构建方向上的类别和各类别里不同工具间的差异,与具体的操作无关。模块化打包类现在的前端项目基本是模块化的,原因就不在这多说。而模块化意味着分散,无法直接用于呈现,因此需要进行相应的打包形成一个整体。有些执行环境(Node)能自动打包各个模块,而有些(浏览器)则因为技术或其它考虑需要自行操作。模块化打包工具就是为模块化项目在浏览器上的优化呈现而服务的。模块化打包的核心是:找出依赖,打包成体。各类工具的基本运行思路便是根据已有配置,从某个文件开始,递归的找出所有与其相关的依赖模块,打包成某种类型的可直接在浏览器中运行的一个或多个新文件。这之中还可以优化输出,以实现代码分离、异步加载和长效缓存等高级功能。Browserify官网 | GitHub正如其官网介绍的,Browserify会递归的分析,项目中所有使用require引入的JS模块(包括Node内置模块)并打包,使得Node类项目能在浏览器上运行。不过对于与项目有关的其它资源,比如Css和图片等,依然需要手动管理。虽然网上已有人编写了支持此些功能的插件,但这不仅违背了设计初衷,也使配置变得杂乱。而且对于要求越来越高的单页面应用来说,它能提供的助力着实已显疲惫。Webpack官网 | 中文 | GitHub稳定版已到v4.26.0,本文以此版本为据。另附加官方的对比文档。Webpack的设计思想新颖实用,社区活跃,功能强大全面,已经是针对前端各类资源的、目前最优秀的模块化管理和打包工具。它入门简单,基本的常用功能能很快上手,并用于实际开发。但精通不易,毕竟打包已是web开发中最重要的挑战之一,必然要耗费些许精力。学习尚且不易,介绍就更为困难,得要有一本书的厚度。所幸此节不是详细介绍,只是亮点阐述,善哉善哉。入门已趋简单掌握了构建的基本思路,任意工具的入门都是较为简单的(读者批:废话)。之所以强调Webpack入门简单,是为了减轻有意者学习之前的顾虑。一方面是它刚被推出时,由于自身的概念新颖而且文档不全面,使开发者处于懵懵懂懂的状态,总感觉离真谛还差些距离。另一方面是它的体系着实庞大,仔细想想都不免胆怯。笔者初次接触时便是这些个感受。但现在不一样。吃土的日子已经远去,啃草的梦想还会远吗?大家准备好镰刀!Webpack第四版在入门上的方便性体现在三方面。一是基础功能高度集成和约定优于配置思想:安装好Webpack及其CLI后便可直接打包JS和JSON文件,与Browserify一样简单。二是官方文档详细(而且有基本同步的中文版),无论是概念的解析、实际运用的示例还是接口的展示都十分完备。三是现在使用和介绍Webpack的人已经很多了,因此网上的各路资料和相应问题的解决方案都十分丰富。你还在犹豫?一切皆模块如从官网上截取的图片所示,在Webapck眼中一切文件(.js、.css、.jpg、.woff、.csv和.ts等除了某些用于下载的静态大文件外)都是模块,都能通过与JS相似的方式被打包,并安置于合适浏览器渲染的位置。真是十分优秀的立足点。以此思想便可囊括前端会使用到的几乎所有资源,可以十分方便的统一管理和安置,更为便捷和高效。而且此思想就是为单页面应用而生的。在Webpack的另一层意境中,一个asset(各类资源)是一个模块,一个component是一个模块,一个module也是一个模块。而单页面应用的特点,不就是应用的更新不是整个页面的更新,而是某个module或component或asset的更新吗?十分的契合。有人说Webpack的缺点在服务端渲染(或说多页面应用)上。喂喂,一来别人的目标本就不在此,二是多页面应用也不需要如此复杂的支持体系。高效的构建性能单页面应用或说需要构建才能展示的应用,相比多页面应用,从每次修改到重新呈现要多经历一个构建的阶段。实际操作中,如果项目庞大而构建性能不够优化,一个小小的修改(打印某值)都会消耗5秒以上的时间,对开发者来说真是个地狱!而优化的方法不外乎两点,一是开发者优化项目的构建思路,二是构建工具优化自身的构建性能。Webpack拥有较理想的构建性能。在开发阶段,当开启了Webpack的模块热替换之后(使用webpack-dev-server会自动开启),一旦检测到文件被修改,会在应用程序运行过程中通过冒泡捕获的方式最小化替换、添加或删除模块,而无需重新加载整个页面。类似Dom渲染中的回流:如果子元素发生的大小变化,会影响兄弟元素但不影响父元素,那么父元素及其它是无需重新绘制的。而且即便完全重新构建,也会保留先前的应用程序状态,减少等待时间。活跃的社区活跃的社区可以提升系统的丰富度,降低学习与使用的成本。Webapck社区十分活跃,应用于各种需求的插件都被一一封装而可直接使用(官方也统一展示和说明了一些常用的优秀的Loader和Plugin)。不单单是其它工具的高度协调,开发中的各个阶段:搭建本地服务器、集成测试等,以及与任务流工具(Gulp、Grunt)的集成等等方面的解决或最优方案,都是丰富和全面的。基本上可以想到的需求,在这个社区中,都能直接借鉴他人已有的成果。Rollup官网 | 中文 | GitHubRollup定位为一个JS模块打包器(明指JS),主要用来构建JS库,也可服务于一些无需代码拆分和动态导入的小型应用程序。能在Webpack已稳居打包之首的情况下杀出一条血路,得到Vue、D3、Three和React等著名库的青睐,想必其着手点和性能有过人之处。Rollup本身结构简单,需要的配置项也不多,再加文档全面,所以很容易上手并全部掌握。它使用ES6本身的Module语法作为自己的标准,而不是诸如CommonJS和AMD等以前的解决方案。这意味着按照Module标准编成的代码,不仅现在可以借助Rollup打包运行,未来更能在实现此标准的浏览器上直接运行。通过Module的特性,Rollup开创了Tree-shaking功能——清除没有在项目中使用到的代码。它基于显式的import和export语句的方式,通过静态分析,排除了任何未在实际中使用的代码,能极大的减少构建于已有模块的项目体积。再加上其构建基本不添加自身的控制代码,使打包后的文件真正的达到纯净二字。想想还有点痒痒,我挠挠裆部。与 Webpack 对比Rollup和Webpack因其定位和专注点是可以共同存在并相互支持的。正如Rollup官网所说的,Rollup更适合构建独立的JS库,而Webpack为资源丰富的应用程序。虽然Webpack也增加了自己的Tree-shaking功能,但在编译后的输出代码中,简单地运行自动minifier检测未使用的变量,得到的结果是不如原生的静态分析。更何况Webpack生成的代码一定是经过自己包装后的代码——将每个模块封装在一个函数中,再置于一个包中,通过浏览器能使用的require方式逐一执行这些模块。任务流构建类基于任务的构建行为,是不在乎操作对象是否为模块化的。这类工具的目标是通过配置来解放日常需要重复的工作——转化、合并压缩和单元测试等等。有人说:这些操作Webpack和Rollup不是也能做?是的,基本能做。实际上,在用模块化构建工具的开发中,很少会用到任务流构建工具。但这绝不是说任务流工具会被取代,也不会被取代,至少多页面应用需要。再说任务流工具是十分纯粹的自动化行为,与模块化打包工具立足点就不一样,何谈取代一说。Grunt官网 | 中文 | GitHubGrunt虽是老牌构建工具,但依然被许多知名项目如WordPress、Twitter和Jquery等使用,也拥有持续更新的完整生态圈和中文文档。它是通过配置驱动——通过获取到的JSON配置执行操作,来流水线式执行相应任务。虽然在学习成本和执行效率上不出众,但如果项目原本就是通过它自动化构建的,是没有必要迁移到其它工具的。// Grunt 的配置驱动示例module.exports = function(grunt) { grunt.initConfig({ jshint: { files: [‘Gruntfile.js’, ‘src//*.js’, ’test//.js’], options: { globals: { jQuery: true } } }, watch: { files: [’<%= jshint.files %>’], tasks: [‘jshint’] } }); grunt.loadNpmTasks(‘grunt-contrib-jshint’); grunt.loadNpmTasks(‘grunt-contrib-watch’); grunt.registerTask(‘default’, [‘jshint’]);};Gulp官网 | 中文 | GitHubGulp是新型的构建工具,虽与Grunt的功能相同,但其构建过程却有三大优势。代码驱动代码驱动即通过执行实际代码驱动程序执行,与常见的配置驱动不同(Webpack、Rollup和Grunt等都是配置驱动)。从任务流构建的角度上看,代码驱动相比配置驱动有三点好处:一是高度的灵活;二是没有过多的配置项,减少学习成本;三是更方便错误的断定和异常情况的调试。// Gulp 的代码驱动示例gulp.src(’./client/templates/.jade’) .pipe(jade()) .pipe(gulp.dest(’./build/templates’)) .pipe(minify()) .pipe(gulp.dest(’./build/minified_templates’));Node流Gulp作为后来者,充分利用NodeJS流的思想进行IO操作,极大增加了大型项目的构建速度。比方说转化Scss成Css,Grunt的操作流程是:读取Scss文件、转化成Css、存储到磁盘,读取Css、压缩处理最后存储到磁盘;而Gulp得操作是:读取Scss文件、转化成Css、压缩处理最后存储到磁盘。一步到位,无需多次的IO操作。简单明了Gulp有十分精简的API。你能想到各种类型的任务,基本是通过仅有的五个可链式操作的方法实现的吗?不仅仅是学习和使用方便,编写后的功能也是一目了然。虽然代码驱动相比配置驱动,需要自己写的代码增加,但一是没增加难度只是函数名的多次重写,二是相对代码驱动的好处来说可以忽略。集合型工具类集合型工具类便是常说的脚手架,也可以看作是以模块化或任务流工具为主体的,各类常用工具的高度封装。它是一个开箱即可用的集合体,类似前后端同构时代的后端框架。它会根据你的选择,生成一个完整的、已配置好各类工具的、具有某些特定代码约定的项目框架。这些配置几乎包揽前端开发的整个流程,甚至可以集成自动化部署等后端接口。官方框架React CLI | Vue CLI | Angular CLI集合型工具一般为单页面应用服务,而单页面应用需要使用某个前端框架。无论你是用React、Vue或Angular,还是其它框架,首先得想到它是否有官方脚手架。比如Vue有Vue CLI。一般推荐有官方脚手架的直接使用官方的。因为现代前端框架一般不单独运行,需结合官方提供的其它工具,比如路由、状态管理等。而且各个框架及配件更新不断,每次更新都可能导致与其它插件的兼容问题,新的功能可能需要某些特定插件才能发挥作用。这是一项工程,仅靠个人或某些团体很难照顾周全的。而各个框架又都有意识的通过官方脚手架来充分展示新的特性,降低学习和使用的成本。我们何乐而不为呢?Yeoman官网 | GitHubYeoman是一个专为现代前端而生的、灵活通用的脚手架工具。它的运作方式和其它脚手架不同。在安装好CLI后,需要找到一个符合要求的Generator(一个npm包,相当于脚手架),使用Yeoman运行安装,生成初始化的项目。你也可以自行配置,使用Yeoman封装成符合特定需求的Generator,并发布出去。等到下次,其他人或你自己,需要生成符合此要求的项目时,便可以直接安装并使用Yeoman生成。这样有明显的两点好处:一是节省体力。在开始一个有特定需求的新项目时,如果有老项目可借鉴,一般会直接复制相关文件。但这样的复制文件可能不纯粹,即增加体积又带来安全隐患。二是在社区的支持下,很多有特殊要求的脚手架,早已有人解决并发布成Generator,是没必要自己动手的。国内其它百度 - FIS - 官网 | GitHub 微信 - WeFlow - 官网 | GitHub 京东 - Athena - 官网 | GitHub 饿了么 - Cooking(名字与公司的性质相得益彰) - 官网 | GitHub作为程序员或至各行各业,在与年龄增长速度相当的压力下,工资的高低自然成为日常性的评定标准。但在同行老友的酒桌上或某个太阳异常温煦下的小道上,能使自己为自己而不是其他事骄傲的,也肯定是“老子之前做过些什么”之类的实际付出而不是物质方面的获得。因此能够成为被公司支持的、被众多人使用的、开源框架维护团队中的程序员,多少是更为幸福的一类。这些由国内各个前端团队开发的集合型脚手架,都是基于自用在实践中得到的最为符合本身需求的产品。里面的包含内容十分丰富,不仅仅是这以上提到的前端本职工作,还有与后端的集成方案或自动化部署配置等。且流程简化,开箱即可使用。不过这些笔者都没用过,也没有打算用。不是打趣,原因很现实,有识之士可以在文章下留言。不用却依然写出的原因倒是简单:宣传,宣传即赞许和期盼;凑数,凑到13种好立个多少浮夸的标题。总结个人观点,不喜请喷,但要和蔼可亲。如果是使用某个前端框架开发应用程序,推荐框架官方的脚手架。如果是自己头脑发热想开源个JS库,推荐Rollup打包。如果不是模块化项目,又需要自动化处理一些事情,推荐Gulp作为构建工具。如果项目有特殊要求或作为核心的部件比较稀有,可以先查看Yeoman上是否有符合要求的Generator,没有就只能自食其力。最后如果你处在已有自己脚手架的公司(比如饿了么),可能要按规章制度使用Cooking为自己的仕途烹煮些吃食。肚子真饿,这种宣传饿了么会返优惠券吗?最后,如果是自食其力的搭建前人没有的脚手架,推荐使用Yeoman发布,方便你我他。 ...

November 30, 2018 · 1 min · jiezi