我现在的项目用的是fis+gulp+webpack来构建的项目,要说的是gulp已经足够优秀,我们只是在打包按需加载js文件时,使用了webpack。
因为fis为之前为百度内部构件工具,所以生态圈并不丰富,所以并不推荐全部使用fis来构建项目。
使用webpack配置文件( 主要是exports moudle resolve plugins的配置 )如下:
module.exports = {
devtool: "source-map", //生成sourcemap,便于开发调试
entry: getEntry(), //获取项目入口js文件
output: {
path: path.join(__dirname, "dist/js/"), //文件输出目录
publicPath: "dist/js/", //用于配置文件发布路径,如CDN或本地服务器
filename: "[name].js", //根据入口文件输出的对应多个文件名
},
module: {
//各种加载器,即让各种文件格式可用require引用
loaders: [
// { test: /\.css$/, loader: "style-loader!css-loader"},
// { test: /\.less$/, loader: "style-loader!csss-loader!less-loader"}
]
},
resolve: {
//配置别名,在项目中可缩减引用路径
alias: {
jquery: srcDir + "/js/lib/jquery.min.js",
core: srcDir + "/js/core",
ui: srcDir + "/js/ui"
}
},
plugins: [
//提供全局的变量,在模块中使用无需用require引入
new webpack.ProvidePlugin({
jQuery: "jquery",
$: "jquery",
// nie: "nie"
}),
//将公共代码抽离出来合并为一个文件
new CommonsChunkPlugin('common.js'),
//js文件的压缩
new uglifyJsPlugin({
compress: {
warnings: false
}
})
]
};复制代码
webpack的配置思路是每个页面一个入口文件,文件中可以通过require引入其他模块,而这些模块webpack会自动跟入口文件合并为一个文件。
在module.exports中的 entry: getEntry()来获取入口文件getEntry()方法可以生成文件的绝对路径 map 如:
entry:{
news-detail: /../Document/project/.../news-detail.js
}复制代码
之后再通过output就会在output.path路径下生成[name].js,即news-detail.js,文件名保持相同。
module 的作用是添加loaders, 那loaders有什么作用呢?
如果我们想要在js文件中通过require引入模块,比如css或image,那么就需要在这里配置加载器,这一点对于React来说相当方便,因为可以在组件中使用模块化CSS。而一般的项目中可以不用到这个加载器。
resolve 中的alias可以用于定义别名,用过seajs等模块工具的都知道alias的作用,比如我们在这里定义了ui这个别名,那么在模块中想引用ui目录下的文件,就可以直接这样写:
require('ui/dialog.js'); //前面不需要加上更长的文件名
plugin 用于引入一些插件
我们这里使用了CommonsChunkPlugin用于生成公用代码,不只可以生成一个,还能根据不同页面的文件关系,自由生成多个,例如:
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
p1: "./page1",
p2: "./page2",
p3: "./page3",
ap1: "./admin/page1",
ap2: "./admin/page2"
},
output: {
filename: "[name].js"
},
plugins: [
new CommonsChunkPlugin("admin-commons.js", ["ap1", "ap2"]),
new CommonsChunkPlugin("commons.js", ["p1", "p2", "admin-commons.js"])
]
};复制代码
在不同页面用script标签引入如下js:
page1.html: commons.js, p1.js
page2.html: commons.js, p2.js
page3.html: p3.js
admin-page1.html: commons.js, admin-commons.js, ap1.js
admin-page2.html: commons.js, admin-commons.js, ap2.js复制代码
这种用法有点像gulp或grunt中手动将多个js合并为common, 但是在webpack里,这个过程是全自动生成的,不用我们自己分析代码的依赖关系。但是这种按需加载的弊端也十分明显,需要人工配置需要提取的文件。
另外一个插件是uglifyJsPlugin,用于压缩js代码。
使用webpack 加载第三方库:(分两种情况第三方库在CDN或者在本地)
方法一 是在html中用script标签引入js文件,如
<script src="https://code.jquery.com/jquery-git2.min.js"></script>复制代码
然后再配置文件中添加externals
externals: { jquery: "jQuery" }复制代码
该字段的作用是将加jQuery全局变量变为模块可引入。然后在各个模块中,就可以如下使用:
var $ = require("jquery");复制代码
我个人觉得既然已经将加jQuery通过script引入了,那么就直接使用$标签就行了。不必再将其转化为模块。
方法二 是将jQuery代码保存到本地,在配置文件中添加:
resolve: { alias: { jquery: "/path/to/jquery-git2.min.js" } }复制代码
即为jquery添加了别名,然后在模块中也是这样使用:
var $ = require("jquery");复制代码
还可以配合使用ProvidePlugin,其作用是提供全局变量给每个模块,这样就不需要在模块中通过require引入,例如:
使用前:
var _ = require("underscore");
_.size(...);
使用后:
plugins: [
new webpack.ProvidePlugin({
"_": "underscore"
})
]
// If you use "_", underscore is automatically required
_.size(...)复制代码
总的来说,如果文件来自CDN,那么使用方法一,如果文件在本地,则用方法二。
gulp足够优秀
目前来说,我们只利用webpack进行了js方面的打包,其他功能用gulp就足够了。gulp主要做了下面几个工作:
- css转化合并压缩
- 图片的雪碧图合并和base64
- 文件md5计算与替换
- 热启动,浏览器自动刷新
下列是依赖的npm模块:
支持雪碧图合并和base64"devDependencies": { "gulp": "^3.8.10", "gulp-clean": "0.3.1", "gulp-concat": "2.6.0", "gulp-connect": "2.2.0", "gulp-css-base64": "^1.3.2", "gulp-css-spriter": "^0.3.3", "gulp-cssmin": "0.1.7", "gulp-file-include": "0.13.7", "gulp-less": "3.0.3", "gulp-md5-plus": "0.1.8", "gulp-open": "1.0.0", "gulp-uglify": "1.4.2", "gulp-util": "~2.2.9", "gulp-watch": "4.1.0", "webpack": "~1.0.0-beta6" },复制代码
我对gulp-css-spriter和gulp-css-base64的源码做了一点修改,使其支持下面的语法:
如果在url的后面加上__sprite后缀,则插件将会把该图片合并到雪碧图里。可以支持一个css文件合并为一个雪碧图,也可以整站合并。.icon_corner_new{ background-image: url(../images/new-ico.png?__sprite); }复制代码
如果加上后缀__inline,则会将图片转化为base64,直接添加到css文件中,对于几k的小文件可以直接使用inline操作。具体配置代码如下:.icon_corner_new{ background-image: url(../images/new-ico.png?__inline); }复制代码
src为需要处理的css文件,spriteSheet为雪碧图生成的目标文件夹,pathToSpriteSheetFromCSS为css文件中url的替换字符串,spritesmithOptions是生成雪碧图的间隙。gulp.task('sprite', function (done) { var timestamp = +new Date(); gulp.src('dist/css/style.min.css') .pipe(spriter({ spriteSheet: 'dist/images/spritesheet' + timestamp + '.png', pathToSpriteSheetFromCSS: '../images/spritesheet' + timestamp + '.png', spritesmithOptions: { padding: 10 } })) .pipe(base64()) // .pipe(cssmin()) .pipe(gulp.dest('dist/css')) .on('end', done); });复制代码
文件加md5, 实现发布更新
发版本的时候为了避免浏览器读取了旧的缓存文件,需要为其添加md5戳。
这里采用了gulp-md5-plus
该代码会将dist/js下面所有的js计算md5戳,并将dist/app/下的html中script中的src引用文件名替换为加了md5的文件名,再将md5文件替换到目标目录dist/js。css的md5操作跟js无异。gulp.task('md5:js', function (done) { gulp.src('dist/js/*.js') .pipe(md5(10, 'dist/app/*.html')) .pipe(gulp.dest('dist/js')) .on('end', done); });复制代码