项目背景:一个综合网站,开发模式为后端嵌套数据,前端开发静态页面和部分组件。

问题:gulp任务处理自动刷新、sass编译等都是极好的。但是对于js的处理并不是很好,尤其是项目需要开发组件时候,如评论组件,需要有模版、css、js[各个模块]。这时候选择用gulp感觉并不合适,当然可以选择require.js or seajs等AMD/CMD规范来开发,但是想想项目中的组件应该是独立于项目之外的,不依赖于任何第三方js,因此选择去折腾webpack+gulp来搞。几番折腾、百度之后,配置如下:

package.js

{
"name": "work",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^6.3.6",
"autoprefixer-core": "^6.0.1",
"babel-core": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-preset-es2015": "^6.24.1",
"browser-sync": "^2.13.0",
"cssgrace": "^3.0.0",
"cssnext": "^1.8.4",
"del": "^2.2.1",
"extract-text-webpack-plugin": "^2.1.0",
"fs": "^0.0.2",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-concat": "^2.6.0",
"gulp-htmlmin": "^2.0.0",
"gulp-imagemin": "^3.0.1",
"gulp-jshint": "^2.0.1",
"gulp-less": "^3.1.0",
"gulp-livereload": "^3.8.1",
"gulp-minify-css": "^1.2.4",
"gulp-notify": "^2.2.0",
"gulp-plumber": "^1.1.0",
"gulp-postcss": "^6.1.1",
"gulp-rename": "^1.2.2",
"gulp-sass": "^2.3.2",
"gulp-uglify": "^1.5.3",
"gulp-util": "^3.0.7",
"gulp-watch": "^4.3.8",
"gulp-webpack": "^1.5.0",
"imagemin-jpegtran": "^5.0.2",
"imagemin-pngcrush": "^5.0.0",
"jshint": "^2.9.2",
"json-loader": "^0.5.4",
"node-sass": "^4.5.2",
"path": "^0.12.7",
"run-sequence": "^1.2.1",
"through2": "^2.0.1",
"webpack": "^2.4.1"
}
}

package中有部分插件并未使用,自行选择安装。

gulp配置[gulpfile.js],关于gulp使用请参考这篇文章

 var gulp = require("gulp")
, gutil = require("gulp-util") , del = require("del")
, sass = require("gulp-sass")
, uglify = require('gulp-uglify')
, rename = require("gulp-rename") , browserSync = require("browser-sync").create()
, reload = browserSync.reload , sequence = require("run-sequence")
, plumber = require("gulp-plumber")
, watch = require("gulp-watch") , through2 = require("through2")
, path = require("path")
, fs = require("fs")
, minifycss = require('gulp-minify-css')
, postcss = require('gulp-postcss')
, autoprefixer = require('autoprefixer') // Autoprefixer 为CSS补全浏览器前缀
, cssnext = require('cssnext') // CSSNext 用下一代CSS书写方式兼容现在浏览器
, cssgrace = require('cssgrace') // CSS Grace 让CSS兼容旧版IE
, webpack = require('webpack'); // #############################################
// # init params
// 收集参数
var cwd = process.cwd();
var cmdargs = process.argv.slice(2);
var cmdname = cmdargs.shift();
var cmdopts = {};
var srcpath = "./src";
var distpath = "./dist"; while (cmdargs.length) {
var key = cmdargs.shift().slice(2);
var val = cmdargs.shift();
cmdopts[key] = key === "src" || key === "dist" ? normalizePath(val) : val;
} // 参数配置
var release = cmdname === "release";
var reloadTimer = null;
var devport = 5678;
var paths = {
src: path.join(__dirname, srcpath),
dist: path.join(__dirname, distpath)
} function normalizePath(url) {
if (url.charAt(0) === "/" || url.indexOf(":") > -1) {
return path.normalize(url);
}
return path.normalize(path.join(cwd, url));
} function setOptions(cmd, cmdopts) {
if (cmd === "start") {
paths.src = cmdopts.src ? path.join(cmdopts.src, srcpath) : paths.src;
} else if (cmd === "release") {
paths.src = cmdopts.src ? path.join(cmdopts.src, srcpath) : paths.src;
paths.dist = cmdopts.dist ? cmdopts.dist : path.normalize(paths.src + "/../" + distpath);
}
} function showUsage() {
console.log("Usage:\n");
console.log(" gulp 显示帮助");
console.log(" gulp help 显示帮助");
console.log(" gulp start --src src 在--src目录下自动化开发调试环境");
console.log(" gulp release --src src --dist dist 构建--src线上版本到--dist目录\n");
console.log(" gulp start --src src --proxy localhost 使用gulp代理localhost请求,并且实时监听src文件修改");
} // #############################################
// # default tasks // # clean path
gulp.task("clean:dist", function() {
return del([paths.dist], {
force: true
});
}); // # 编译css
gulp.task("sass", function() {
var base = paths.src;
var dest = base;
var processors = [
autoprefixer({
browsers: ['last 3 version', '> 5%', 'Android >= 4.0', 'iOS >= 7'],
cascade: false, //是否美化属性值 默认:true 像这样:
remove: true //是否去掉不必要的前缀 默认:true
}),
// cssnext(),
// cssgrace
];
return gulp.src(base + "/**/*.scss", {
base: base
})
.pipe(plumber())
.pipe(sass({
precision: 2,
outputStyle: release ? "compressed" : "expanded"
//sourceComments: release ? false : true
})
.on("error", sass.logError))
.pipe(postcss(processors))
.pipe(gulp.dest(dest));
});
// 编译单个css
function parseSingleFile(file) {
var base = paths.src;
var dest = base;
var processors = [
autoprefixer({
browsers: ['last 3 version', '> 5%', 'Android >= 4.0', 'iOS >= 7'],
cascade: false, //是否美化属性值 默认:true 像这样:
remove: true //是否去掉不必要的前缀 默认:true
}),
// cssnext(),
// cssgrace
];
return gulp.src(file, {
base: base
})
.pipe(plumber())
.pipe(sass({
precision: 2,
outputStyle: release ? "compressed" : "expanded"
//sourceComments: release ? false : true
})
.on("error", sass.logError))
.pipe(postcss(processors))
.pipe(gulp.dest(dest));
} // # 压缩js
gulp.task("uglify", function() {
var base = paths.src;
var dest = paths.dist;
return gulp.src([
base + "/**/*.js",
"!" + base +"/**/*-component/**",
"!" + base + "/**/*min.js" // 排除压缩min.js文件
], {
base: base
})
.pipe(plumber())
.pipe(uglify())
.pipe(gulp.dest(dest));
}); // # 调用webpack处理component
function parseComponentToWebpack(path){
var webpackConfig = require('./webpack.config.js');
// 灵活处理output位置,将js文件生成在component同级目录
// 将**/*-component/xx.js路径替换为**
// var outputPath = path.replace(/\/[^\/]+\/[^\/]+$/,'');
var outputPath = path.replace(/\/([^\/]+)-component\/[^\/]+$/,'');
var filename = RegExp.$1;
webpackConfig.entry = {};
webpackConfig.entry[filename] = path+'/../index.js';
// windows上webpack不认识D:/xxx路径,替换为D:\\xxx路径
outputPath = outputPath.replace('/','\\\\');
webpackConfig.output.path = outputPath;
return webpack(webpackConfig, function(err, stats) {
console.log(stats.toString());
});
} // # 压缩css
gulp.task("mincss", function() {
var base = paths.src;
var dest = paths.dist;
gulp.src(dest + '/**/*.css')
.pipe(minifycss())
.on('error', function(e) {
console.log(e)
})
.pipe(gulp.dest(dest));
}); // # 复制静态资源
gulp.task("copy:dist", function() {
var base = paths.src;
var dest = paths.dist;
// 复制min.js文件
gulp.src([
base + "/**/*min.js"
], {
base: base
})
.pipe(gulp.dest(dest));
return gulp.src([
base + "/**/*",
"!" + base +"/**/*-component",
"!" + base +"/**/*-component/**",
"!" + base + "/**/*.js",
"!" + base + "/**/*.scss"
], {
base: base
})
.pipe(gulp.dest(dest));
}); // # serv & watch
gulp.task("server", function() {
// start server
browserSync.init({
ui: false,
notify: false,
port: devport,
// 设置代理请求
proxy: cmdopts.proxy,
server: !cmdopts.proxy ? {
baseDir: paths.src
} : false
}); // # watch src资源, 调用相关任务预处理
// # 刷新浏览器
// # 限制浏览器刷新频率
watch(paths.src + "/**/*", function(obj) {
var url = obj.path.replace(/\\/g, "/");
var absurl = url;
url = path.relative(paths.src, url).replace(/\\/g, "/");
console.log("[KS] " + absurl); // skip scss & css
if (!/\.scss$/.test(url) && !/\.css$/.test(url)) {
if (/.+-component\/.+\.js$/.test(url)) {
// 评论组件,调用webpack
console.log("[webpack] "+absurl);
parseComponentToWebpack(absurl);
return;
}
if (reloadTimer) {
clearTimeout(reloadTimer);
}
reloadTimer = setTimeout(reload, 1000);
}else if(/\.scss$/.test(url)){
// sass任务
parseSingleFile(absurl)
// 无刷新加载css
.pipe(reload({
stream: true
}));
// sequence("sass");
}
});
}); // #############################################
// # public task gulp.task("default", showUsage);
gulp.task("help", showUsage); gulp.task("start", function(cb) {
release = false;
setOptions("start", cmdopts);
sequence("sass", "server", cb);
}); gulp.task("release", function(cb) {
release = true;
setOptions("release", cmdopts);
sequence("clean:dist", "copy:dist", ["mincss", "uglify"], cb);
});

webpack配置(webpack.config.js),webpack配置参考

 var webpack = require('webpack');

 module.exports = {
// devtool: 'eval-source-map',
devtool: false,
entry: {
"component-comment": __dirname + "/src/assets/comment/component/index.js"
},
output: {
// path: __dirname + "/src/assets/comment",
path: __dirname + "/dist/component",
filename: "[name].js"
}, module: {
rules: [{
test: /\.json$/,
loader: "json-loader"
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader', //在webpack的module部分的loaders里进行配置即可
/*query: {
presets: ['es2015']
}*/
query: {
presets: [
['es2015', {
'modules': false //babel不编译es6的模块加载,让webpack支持Tree-shaking
}]
]
}
},
]
}, }

以上配置webpack将单独处理component目录中的js文件,并在component同级目录生成文件夹相同名字的js文件(如:'./component-comment-component/' 文件夹对应的js文件为 './component-comment.js')。

以下是我的文件结构

 src
app
*.html //html目录
assets //静态资源目录
component-comment-component //评论组件
images //评论组件所用图片
component //组件模块
common.js //公用方法,如ajax、jsonp、extend等方法
defaultConfig.js //默认配置
emoticon.js //表情模块,如获取服务端表情资源,渲染表情等
index.js //主模块,如获取评论、发表评论、点赞、回复、举报等
selector.js //选择器方法,模拟jQuery封装
template.js //模版
component-comment.js //webpack编译component目录的js
component-comment.scss //评论样式表
component-comment.css //编译的sass文件
css //项目其他sass|css资源
images //项目图片文件
js //项目的其他js

以上只是一个简单的使用案例,针对不同结构需要作出不同调整。

gulp+webpack多页应用开发,webpack仅处理打包js的更多相关文章

  1. 做一个gulp+webpack+vue的单页应用开发架子

    1.目标 最近项目上的事情不多,根据我自己的开发习惯,决定开发一些简单的开发架子,方便以后事情多的时候直接套用.本文讲的一个gulp+webpack+vue的单页应用架子,想要达到的目的: 可以通过命 ...

  2. webpack+express多页站点开发

    学习了webpack门级的教程后,觉得可能是专门为单页应用而量身打造的,比如webpack+react.webpack+vue等,都可以解决各种资源的依赖加载.打包的问题.甚至css都是打包在js里去 ...

  3. 利用免费cdn加速webpack单页应用

    回顾现状 在之前的学习过程中,react单页应用经过webpack打包之后会输出大概如下的目录结构,它就是站点的所有前端组成了:   1 2 3 4 5 6 MacBook-Pro:output ba ...

  4. 基于webpack的前端工程化开发解决方案探索(一):动态生成HTML(转)

    1.什么是工程化开发 软件工程的工程化开发概念由来已久,但对于前端开发来说,我们没有像VS或者eclipse这样量身打造的IDE,因为在大多数人眼中,前端代码无需编译,因此只要一个浏览器来运行调试就行 ...

  5. vue(9)—— 组件化开发 - webpack(3)

    前面两个终于把webpack相关配置解析完了.现在终于进入vue的开发了 vue组件化开发预热 前期准备 创建如下项目: app.js: footer.js: main.js: webpack.con ...

  6. 微服务项目开发学成在线_Vue.js与Webpack

    Vue.js 1.Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.自底向上逐层应用:作为渐进式框架要实现的目标就是方便项目增量开发. 渐进式框架:Progress ...

  7. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  8. [webpack] 配置react+es6开发环境

    写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...

  9. webpack 教程 那些事儿06-gulp+webpack多页

    本篇主要讲述用gulp+webpack构建多页应用 折腾到现在,项目还必须要进行,.vue文件必须要加载,也就是webpack必须引入.时间不多了,抛弃上个方案之后,只能牺牲热加载性能,用gulp+w ...

随机推荐

  1. windows 10 如何设定计划任务自动执行 python 脚本?

    我用 python 写了一些脚本,有一些是爬虫脚本,比如爬取知乎特定话题的热门问题,有一些是定期的统计分析脚本,输出统计结果到文档中.之前我都是手动执行这些脚本,现在我希望如何这些脚本能自动定时执行. ...

  2. WPF 程序的编译过程

    原文:WPF 程序的编译过程 基于 Sdk 的项目进行编译的时候,会使用 Sdk 中附带的 props 文件和 targets 文件对项目进行编译.Microsoft.NET.Sdk.WindowsD ...

  3. IQueryable,IEnumerable,IList区别

    IQueryable和IEnumerable都是延时执行(Deferred Execution)的,而IList是即时执行(Eager Execution)IQueryable和IEnumerable ...

  4. 使用NODEJS实现JSONP的实例

    JSONP与JSON只有一字之差,我们在使用Jquery的Ajax调用的时候也是使用相同的方法来调用,两者的区别几乎只在于使用的dataType这个属性的不同.但是实际上JSON和JSONP是完全不同 ...

  5. 16 doc values 【正排索引】

    搜索的时候,要依靠倒排索引:排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序,所谓的正排索引,其实就是doc values 在建立索引的时候,一方面会建立倒排索引, ...

  6. 易百教程人工智能python修正-人工智能NLTK性别发现器

    在这个问题陈述中,将通过提供名字来训练分类器以找到性别(男性或女性). 我们需要使用启发式构造特征向量并训练分类器.这里使用scikit-learn软件包中的标签数据. 以下是构建性别查找器的Pyth ...

  7. Jquery 跨Dom窗口操作

    . 子窗口给父窗口元素赋值 function modifyTheme(id){ $("#parent_dom",window.parent.document).attr(" ...

  8. 【转载】 C#中使用int.TryParse方法将字符串转换为整型Int类型

    在C#编程过程中,将字符串string转换为整型int过程中,时常使用的转换方法为int.Parse方法,但int.Parse在无法转换的时候,会抛出程序异常,其实还有个int.TryParse方法可 ...

  9. FFmpeg--如何同步音视频的解决方案

    如何同步视频 PTS和DTS 幸运的是,音频和视频流都有一些关于以多快速度和什么时间来播放它们的信息在里面.音频流有采样,视频流有每秒的帧率.然而,如果我们只是简单的通过数帧和乘以帧率的方式来同步视频 ...

  10. http请求的几种content-type

    1. 2.二进制文件 3.form-data 数据:a=1 总结: 1.对于我自己的写的服务来说,只要是raw,接收到的都是二进制字符: 2.如果是urlencode,接收到的是拼接的字符串(和使用p ...