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

问题: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. SpringBootSecurity学习(07)网页版登录整合JDBC

    数据库中定义用户 前面我们定义用户是在配置文件和代码中定义死的默认用户,一般在开发中是不会这样做的,我们的用户都是来自我们的用户表,存储在数据库中.操作数据库的技术有很多,spring securit ...

  2. java之mybatis之使用mybatis实现crud操作

    目录结构: 1.封装 mybatis 的工具类: MybatisUtil.java public class MybatisUtil { private static SqlSessionFactor ...

  3. Mars Sample 使用说明

    Mars Sample 使用说明  https://github.com/Tencent/mars/wiki/Mars-sample-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98 ...

  4. ServiceStack JWT 准备

    ServiceStack JWT设置 ServcieStack 自带的验证授权模块使用 sql server存储,所以我们第一步需要配置数据库的一些选项 container.Register<I ...

  5. Java之路---Day03

    2019-10-17-21:18:33 方法 定义格式: public static void 方法名称() { 方法体 } 完整格式: 修饰符  返回值类型  方法名称(参数类型  参数名称,... ...

  6. Jboss部署SpringBoot2 JPA

    Jboss部署SpringBoot2 JPA 目录结构 . └── webapp └── META-INF ├── jboss-deployment-structure.xml └── jboss-w ...

  7. 【开发笔记】- Java中关于HashMap的元素遍历的顺序问题

    今天在使用如下的方式遍历HashMap里面的元素时 for (Entry<String, String> entry : hashMap.entrySet()) { MessageForm ...

  8. 【转载】C#中double.TryParse方法和double.Parse方法的异同之处

    在C#编程过程中,double.TryParse方法和double.Parse方法都可以将字符串string转换为double类型,但两者还是有区别,最重要的区别在于double.TryParse方法 ...

  9. Guava Cache用法介绍

    背景 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用.在日长开发有很多场合,有一些数据量不是很大,不会经常改动,并且访问非常频繁.但是由于受限于硬盘IO的性能或者远程网络 ...

  10. Java 递归方法

    递归:在一个方法体内,调用自身,一般要有出口. 实例:已知一个数列,f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n),其中n为大于等于0的整数,求f(10)的值. package ...