在GitHub上发现的学习webpack和react的很好的文章,原文链接
从Webpack的方展史上来看,它是强大的.早些时候对脚本文件的处理还只是压缩和合并,但随着时代的发展,现在怎样部署我们的JavaScript代码已经是一个繁杂的工作了.
这个问题随着单页面应用(SPAs)的不断发展而升级,往往这样的应用需要依靠许多重量级的库,最后作为产品时需要把它们一次性的加载到页面中,而Webpack在许多时候都是一个不错的解决安案.
使用npm,现在是很流行的,它是Node.js的包管理工具,有丰富的资源.并且随着前端的发展,npm逐步成熟了起来,并使用它来管理我们工程的依赖.
从历史上讲,有许多构建系统,如Grunt和Gulp,它们现在也还是一个不错的选择,并且可以通过npm来安装它们.
当我们需要拼接各种资源并且打包产品时,这时构建工具是一个好帮手,它允许我们跨平台的执行操作,我们有打包工具,如Browserify或者Webpack.
更进一步的,JSPM推进包管理可以直接在浏览器中.它依赖于System.js,一个动态的模块加载库. JSPM不像Browserify和Webpack,我们可以在开发过程中完全不关心最后要怎么打包,把这个任务由它来完成.
历史悠久的构建工具. 比我还要老.
在Gulp之前Grunt是主力,它的插件体系很受欢迎,但你可能会不得不保持300行的配置文件.下面是一个示例:
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']);
};
在上面的例子里我们定义了两个基本任务, jshint是一个检查你JavaScript代码中可能出现的问题点的工具,还有一个watch任务,时实监视我们代码的改动.
实际中,我们将有各种类型的任务,如工程构建,例子显示了怎样构建,它很强大,但是却隐藏了太多细节,让我们很难理解到底发生了什么.
grunt-webpack插件可以让我们在Grunt环境中件使用Webpack.
Gulp采取了不同的方式,写配置时,不是靠每个插件单独配置.Gulp构建在管道概念之上.如果你熟悉 Unix,这一点上是相同的. 包含了.sources, filters, 和sinks.
sources对应于文件,filters执行操作(例如转换JavaScript),最终,结果将传递给sinks(例如,我们的构建目录),下面是一段Gulpfile
var gulp = require('gulp');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var del = require('del');
var paths = {
scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee']
};
// Not all tasks need to use streams
// A gulpfile is just another node program and you can use all packages available on npm
gulp.task('clean', function(cb) {
// You can use multiple globbing patterns as you would with `gulp.src`
del(['build'], cb);
});
gulp.task('scripts', ['clean'], function() {
// Minify and copy all JavaScript (except vendor scripts)
// with sourcemaps all the way down
return gulp.src(paths.scripts)
.pipe(sourcemaps.init())
.pipe(coffee())
.pipe(uglify())
.pipe(concat('all.min.js'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('build/js'));
});
// Rerun the task when a file changes
gulp.task('watch', function() {
gulp.watch(paths.scripts, ['scripts']);
});
// The default task (called when you run `gulp` from CLI)
gulp.task('default', ['watch', 'scripts']);
配置文件是JS代码写的,你可以hack它,你可以用现有的Node.js包作为Gulp的插件,诸如此类.相比Grunt,你对任务的流转会有一个清晰的概念,最终我们会为各种任务写大量样板代码.
gulp-webpack插件可以让我们在Gulp环境中件使用Webpack.
使用JavaScript处理模块一直有些问题,这个语言本身并没有模块的概念直到ES6的出现,因此,我们提出了各种解决方案,例如AMD.
实践中,它只服务于CommonJS(Node.js 格式), 优点是,你经常可以hook到npm, 避免重造轮子.
Browserify是一个模块问题解决方案, 它提供给我们打包CommonJS模块到一起的方法, 你可以在hook它对于Gulp.
Browserify 生态系统是由很多小的模块组成。这种方式,Browserify 坚持 Unix 哲学。Browserify 比 Webpack容易一点,是一个不错的选择.
你可以说Webpack是Browserify的一个整体的解决方案, Browserify是由许多小工具组成的, 而Webpack提供了大量的开箱即用的核心功能,可以使用指定的loaders 和plugins进行扩展。
Webpack将会通过require
语句来遍历你的工程,生成定义的包,你甚至可以动态的载入你自已的依赖使用require.ensure
语句, 这个加载机制对于CSS和@import是友好支持的.也有处理如压缩,本地化,热加载等插件。
例如,require('style!css!./main.css')
加载这个main.css通过CSS和style从内到外的顺序. 下面是一个示例:
webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: './entry.js',
output: {
path: __dirname,
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.css$/,
loaders: ['style', 'css']
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
};
这个配置模式可能让Webpack有点儿不透明,很难理解它作了什么,在更富杂的情况下尤其如此. 作者有相关的书可以学习.
对比早期的工作它是完全不同的,它有一个小的CLI工具,用于安装新包和发布打包等. 它支持SystemJS插件,使我们可以加载各种格式到工程中.
JSPM还很年轻,可能会有些问题,但是觉对不容小觑.
Webpack可以处理打包构建的问题,但选择它是因为它支持模块的热插拔,接下来将说如何设置它.
你可以有相似的工具如 LiveReload 或者Browsersync , 这些工具会在你改变代码时自动刷新你的浏览器, HMR则做到了更进一步,在React中,它允许应用管理自已的状态, 这听起来很简单,但在实际中有很大的区别.
抛开HMR. Webpack的打包能力是广范的,它允许你用另种方式拆分包,你甚至可以在程序持行时动态的加载.这种延时加载对于大型应用非常好用,你可以在你需要它时加载它们.
使用Webpack,可以方便的注于一个hash值到每个打包文件的名字 (例如,app.d587bbd6e38337f5accd.js).允许我们更改一个包.包拆分后当发生改变时,客户端只重新加载发生改变的这部分数据即可.
这些小的功能加起来,我们可以方便的干很多事情,Webpack有一定的学习曲线,但即便始此,它仍是一个好的工具,特别是在以后会为我们节省许多保贵的时间.