通过Gulp解析主要的Bower文件(js、css、scss、图像)到发布目录

4
最近我们从使用PHP资产管理器切换到了Gulp。我们使用bower来拉取前端包及其依赖项。 对于仅在“main”中列出JS文件的简单Bower包,处理起来非常简单,容易完成。 使用“main-bower-files”,我们可以获取所需的js文件并将它们合并为一个脚本文件,然后发送到我们的site/script文件夹。 我们可以收集字体并将它们移动到我们站点的fonts/文件夹中。 接下来,我们遇到了麻烦...应该如何处理图片及其在相应的css/scss文件中的路径呢? 为了更进一步复杂化事情,我们希望图片保留其原始文件夹布局,以便它们不会被覆盖。 我们希望获取css和scss(我们使用libsass)文件,并将它们与我们自己的样式合并为一个.css文件。 但是,我们如何确保它们仍然具有与之相关联的工作路径,以便携带它们的图像正常显示。

所需文件夹布局如下:

bower.json
gulpfile.js
package.json
bower_components/
site/
  - css/styles.css
  - fonts/
  - images/
    - bower-package-a/
      - arrow.png
      - gradient.png
      - themea-a/
        - arrow.png
      - theme-b/
        - arrow.png
    - bower-package-b/
      - arrow.png
      - gradient.png
  - script/

以下是我们目前的Gulpfile:

// Include gulp
var gulp = require('gulp');

// Include Plugins
var bower           = require('gulp-bower');
var browserSync     = require('browser-sync').create();
var concat          = require('gulp-concat');
var del             = require('del');
var filter          = require('gulp-filter');
var gutil           = require('gulp-util');
var imagemin        = require('gulp-imagemin');
var jshint          = require('gulp-jshint');
var mainBowerFiles  = require('main-bower-files');
var merge           = require('merge-stream');
var newer           = require('gulp-newer');
var plumber         = require('gulp-plumber');
var pngquant        = require('imagemin-pngquant');
var rename          = require('gulp-rename');
var sass            = require('gulp-sass');
var sourcemaps      = require('gulp-sourcemaps');
var changed         = require('gulp-changed');
var parallel        = require("concurrent-transform");
var os              = require("os");
var imageResize     = require('gulp-image-resize');
var spritesmith     = require('gulp.spritesmith');
var uglify          = require('gulp-uglify');

// Paden
var bowerDest       = 'site/script/lib/bower';
var imgSrc          = 'src/images/**';
var imgDest         = 'site/images';
var spriteImgDest   = './src/images/sprite/';
var scriptSrc       = 'src/script/**/*.js';
var scriptDest      = 'site/script';
var stylesSrc       = 'src/styles/styles.scss';
var stylesDest      = 'site/css';

// Helpers
var onSassError = function(error) {
    gutil.log('Sass Error', gutil.colors.red('123'));
    gutil.beep();
    console.log(error);
    this.emit('end');
}

// Clean images Task
gulp.task('clean:images', function () {
    return del([imgDest]);
});

// Clean script Task
gulp.task('clean:script', function () {
    return del([scriptDest]);
});

// Clean image Task
gulp.task('clean:styles', function () {
    return del([stylesDest]);
});

// Lint Task
gulp.task('lint', function() {
    return gulp.src(scriptSrc)
        .pipe(jshint())
        .pipe(jshint.reporter('jshint-stylish'))
    ;
});

// Sass Task
gulp.task('sass', ['sprite'], function() {
     return gulp.src(stylesSrc)
        .pipe(plumber({
            errorHandler: onSassError
        }))
        .pipe(sourcemaps.init())
        .pipe(sass({
            includePaths: [
              'bower_components/compass-mixins/lib',
              'bower_components/foundation/scss'
            ],
            outputStyle: 'compressed'
        }))
        .pipe(sourcemaps.write('./map'))
        .pipe(gulp.dest(stylesDest))
        .pipe(browserSync.stream())
    ;
});

// Concatenate & Minify JS
gulp.task('script', function() {
    return gulp.src(scriptSrc)
        .pipe(concat('script.js'))
        .pipe(gulp.dest(scriptDest))
        .pipe(rename('script.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest(scriptDest))
    ;
});

// Voeg de JS bestanden die gebruikt worden vanuit bower samen. Let op: modernizr volgt niet de standaard
// en wordt daarom niet meegenomen in mainBowerFiles(). Deze voegen we dus los toe.
gulp.task('bower:js', function() {
    var modernizr = gulp.src('bower_components/modernizr/modernizr.js')
        .pipe(rename('modernizr.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest(scriptDest))
    ;

    var frontend = gulp.src(mainBowerFiles())
        .pipe(sourcemaps.init())
        .pipe(filter('*.js'))
        .pipe(concat('frontend.min.js'))
        .pipe(uglify())
        .pipe(sourcemaps.write('maps'))
        .pipe(gulp.dest(scriptDest))
    ;

    return merge(modernizr, frontend);
});

// Imagemin Task (compress images)
gulp.task('imagemin', function () {
    return gulp.src([imgSrc, '!src/images/sprite{,/**}'])
        .pipe(newer(imgDest))
        .pipe(imagemin({
            use: [pngquant()]
        }))
        .pipe(gulp.dest(imgDest))
        .pipe(browserSync.stream())
    ;
});

// Compile sass into CSS & auto-inject into browsers
gulp.task('browser-sync', function() {
    // Serve files from the root of this project
    browserSync.init({
        proxy: "localhost/insyde/website_v6_devtools/site"
    });

    // add browserSync.reload to the tasks array to make
    // all browsers reload after tasks are complete.
    gulp.watch("./src/script/**/*.js", ['scripts-watch']);
});

// generate the x1 images from the big ones
gulp.task('generate-small-sprite-images', function () {
    return gulp.src('./src/images/sprite/*-2x.png')
        .pipe(newer(rename(function(path) {
              path.basename = path.basename.slice(0, -3);  //remove @2x label
        })))
        .pipe(parallel(
            imageResize({
                width: '50%',
                height: '50%'
            }), os.cpus().length
        ))
        .pipe(rename(function(path) {
              path.basename = path.basename.slice(0, -3);  //remove @2x label
        }))
        .pipe(gulp.dest(spriteImgDest))
;});

gulp.task('sprite', ['generate-small-sprite-images'], function () {
    var spriteData = gulp.src('./src/images/sprite/**/*.png').pipe(spritesmith({
        imgName: 'sprite.png',
        retinaImgName: 'sprite-2x.png',
        cssName: 'sprite.scss',
        imgPath: '../images/sprite.png', 
        retinaImgPath : '../images/sprite-2x.png', 
        retinaSrcFilter: '**/*-2x.png'
    }));
    // Pipe image stream through image optimizer and onto disk
    var imgStream = spriteData.img
        .pipe(imagemin())
        .pipe(gulp.dest(imgDest));

    // Pipe CSS stream through CSS optimizer and onto disk
    var cssStream = spriteData.css
        .pipe(gulp.dest('./src/styles/'));

    // Return a merged stream to handle both `end` events
    return merge(imgStream, cssStream);
});

// Watch Files For Changes
gulp.task('watch', function() {
    gulp.watch('./src/script/**/*.js', ['lint', 'script']);
    gulp.watch('./src/styles/**/*.scss', ['sass']);
    gulp.watch('./src/images/**', ['imagemin']);
    gulp.watch('./templates/**/*.html').on('change', browserSync.reload);
});

// Default Tasks
gulp.task('default', ['lint', 'sass', 'bower:js', 'script', 'imagemin', 'watch']);
gulp.task('frontend', ['lint', 'sprite', 'sass', 'bower:js', 'script', 'imagemin', 'browser-sync', 'watch']);
gulp.task('clean', ['clean:images', 'clean:script', 'clean:styles']);

// create a task that ensures the `scripts` task is complete before
// reloading browsers
gulp.task('scripts-watch', ['script'], browserSync.reload);   
2个回答

5

搞定了!

我使用了这个作为例子:https://github.com/jonkemp/gulp-useref/issues/60#issuecomment-77535822

这些任务的作用是:

bower:assets 将所有在 bower 包‘main’属性中定义的资源文件(图片和字体),使用 main-bower-files 找到它们,并将其复制到 site/dist/,同时保留包自身的原始文件夹布局。

bower:styles 解析 main-bower-files 中的每个样式表(不包括两个包:foundation 和 compass-mixins),并重新处理指向我们之前复制的图片和字体的 URL。这与示例不同之处在于,我的情况下文件并没有先复制到 .tmp 目录,而是直接处理并写入 site/css 文件夹。我使用 sourcemaps 来更方便地进行调试,同时合并和压缩 css 文件。

//copy bower assets that need copying
gulp.task('bower:assets', function() {
    return gulp.src(mainBowerFiles(), {
        base: './bower_components'
    })
    .pipe(filter([
        '**/*.{png,gif,svg,jpeg,jpg,woff,eot,ttf}',
        '!foundation/**/*',
        '!compass-mixins/**/*'
    ]))
    .pipe(gulp.dest('./site/dist'));
});

//generate bower stylesheets with correct asset paths
gulp.task('bower:styles', function() {
    return gulp.src(mainBowerFiles(), {
        base: './bower_components'
    })
    .pipe(filter([
        '**/*.{css,scss}',
        '!foundation/**/*',
        '!compass-mixins/**/*'
    ]))
    .pipe(foreach(function(stream, file) {
        var dirName = path.dirname(file.path);
        return stream
            .pipe(rework(reworkUrl(function(url) {
                var fullUrl = path.join(dirName, url);
                if (fs.existsSync(fullUrl)) {
                    bowerCopyFiles.push(fullUrl);
                    console.log(path.relative('css', fullUrl).replace(/bower_components/, 'dist'));
                    return path.relative('css', fullUrl).replace(/bower_components/, 'dist');
                }
                return url;
            })));
    }))
    .pipe(sourcemaps.init())
    .pipe(concat('bower.css'))
    .pipe(minifyCss())
    .pipe(sourcemaps.write('./map'))
    .pipe(gulp.dest(stylesDest));
});

这导致了以下目录结构:
  • bower_components
  • site
    • css
      • bower.css
    • dist
      • bower-component-a
        • images
          • arrow.png
          • gradient.png
      • bower-component-b
        • images
          • arrow.png
          • gradient.png

1
另一个选择是使用 gulp-bower-normalize 包,该包将接收来自 main-bower-files 的管道输出,然后根据软件包和文件扩展名将它们拆分开。例如:
gulp.src(mainBowerFiles(), { base: 'bower_components' })
    .pipe(bowerNormalize({ bowerJson: './bower.json'  }))
    .pipe(gulp.dest('assets/vendor'));

您可能需要微调bower.js中的主文件,但它的效果非常好。如果您正在使用Bootstrap...

bower.json:

{
    ...
    "dependencies": {
        "bootstrap": "^3.3.6",
        ...
    },
    "overrides": {
        "bootstrap": {
            "main": [
                "dist/css/bootstrap.min.css",
                "dist/js/bootstrap.min.js",
                "fonts/glyphicons-halflings-regular.eot",
                "fonts/glyphicons-halflings-regular.svg",
                "fonts/glyphicons-halflings-regular.ttf",
                "fonts/glyphicons-halflings-regular.woff",
                "fonts/glyphicons-halflings-regular.woff2"
            ],
            "normalize": {
                "fonts": ["*.eot", "*.svg", "*.ttf", "*.woff", "*.woff2"]
            }
        }
    } 
}

"...它将生成以下结构:

"
assets/
|-- vendor/
    |-- bootstrap/
        |-- css/
        |   |-- bootstrap.min.css
        |
        |-- fonts/
        |   |-- glyphicons-halflings-regular.eot
        |   |-- glyphicons-halflings-regular.svg
        |   |-- glyphicons-halflings-regular.ttf
        |   |-- glyphicons-halflings-regular.woff
        |   |-- glyphicons-halflings-regular.woff2
        |
        |-- js/
            |-- bootstrap.min.js

另一个不错的选项是扁平化结构,在打包供应商文件时可能更有用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接