Webpack入门教程
写在前面
阅读本文之前,先看下面这个webpack的配置文件,如果每一项你都懂,那本文能带给你的收获也许就比较有限,你可以快速浏览或直接跳过;如果你和十天前的我一样,对很多选项存在着疑惑,那花一段时间慢慢阅读本文,你的疑惑一定一个一个都会消失;如果你以前没怎么接触过webpack,而你又对webpack感兴趣,那么动手跟着本文中那个贯穿始终的例子写一次,写完以后你会发现你已明明白白的走进了webpack的大门。
1 //一个常见的Webpack配置文件 2 var webpack = require('webpack'); 3 var HtmlWebpackPlugin = require('html-webpack-plugin'); 4 var ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 6 module.exports = { 7 entry: __dirname + "/app/main.js", 8 output: { 9 path: __dirname + "/build", 10 filename: "[name]-[hash].js" 11 }, 12 13 module: { 14 loaders: [ 15 { 16 test: /\.json$/, 17 loader: "json" 18 }, 19 { 20 test: /\.js$/, 21 exclude: /node_modules/, 22 loader: 'babel' 23 }, 24 { 25 test: /\.css$/, 26 loader: ExtractTextPlugin.extract('style', 'css?modules!postcss') 27 } 28 ] 29 }, 30 postcss: [ 31 require('autoprefixer') 32 ], 33 34 plugins: [ 35 new HtmlWebpackPlugin({ 36 template: __dirname + "/app/index.tmpl.html" 37 }), 38 new webpack.optimize.OccurenceOrderPlugin(), 39 new webpack.optimize.UglifyJsPlugin(), 40 new ExtractTextPlugin("[name]-[hash].css") 41 ] 42 }
Webpack介绍
一、为什么使用webpack?
现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法:
- 模块化,让我们可以把复杂的程序细化为小的文件;
- 类似于TypeScript这种在JavaScript基础上拓展的开发语言:使我们能够实现目前版本的JavaScript不能直接使用的特性,并且之后还能转换为JavaScript文件使浏览器可以识别;
- Scss,less等CSS预处理器;
- ...
这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就为webpack等工具的出现提供了需求。
二、什么是webpack?
如果说它是一个打包工具那真的是有点大材小用了。我个人认为webpack是一个集前端自动化、模块化、组件化于一体的可拓展系统,你可以根据自己的需要来进行一系列的配置和安装,最终实现你需要的功能并进行打包输出。
webpack的工作方式是:把我们的项目当做一个整体,通过一个给定的主文件(如:index.js),webpack将从这个文件开始找到项目的所有依赖文件,使用loaders处理它们,最后打包为一个或多个浏览器可识别的JavaScript文件。
这么解释对于新手来讲,可能还是没有什么概念,不过不要着急,继续往后看,当你学会了该如何使用它时,再回来研究它的概念,相信会有不一样的理解。
三、安装webpack
安装webpack之前,需要确保电脑已经配置了node.js环境,如果没有,可以点击这里安装node.js。
webpack的安装分两种方式:全局安装和安装到项目目录中,至于这两种方式有什么区别,我还没有研究。
1 // 全局安装 2 nam install -g webpack 3 // 安装到项目目录 4 npm install --save-dev webpack
使用Webpack
一、简单使用
1.开始使用之前,我们需要准备好我们的示例程序。首先初始化项目,并且安装webpack到项目目录中。
1 mkdir demo && cd demo // 新建项目名称为demo的文件夹 2 nam init // 初始化package.json 3 npm install --save-dev webpack // 安装webpack到项目目录中
其中package.json是一个标准的npm说明文件,里面蕴含了丰富的信息,包括当前项目的依赖模块,自定义的脚本任务等等。在终端中使用npm init命令可以自动创建这个package.json文件,输入这个命令后,终端会问你一系列诸如项目名称,项目描述,作者等信息,不过不用担心,如果你不准备在npm中发布你的模块,这些问题的答案都不重要,回车默认即可。或者可以直接输入命令npm init -y来跳过这些询问。
2.回到demo文件夹中,并在里面创建两个文件夹,app文件夹和public文件夹,app文件夹用来存放原始数据和我们将写的JavaScript模块,public文件夹用来存放准备给浏览器读取的数据(包括使用webpack生成的打包后的js文件以及一个index.html文件)。在这里还需要创建三个文件,index.html文件放在public文件夹中,两个js文件(Greeter.js和main.js)放在app文件夹中。此时项目结构如下图所示(其中node_modules用来存放项目所依赖的模块包,刚才的webpack其实也就是安装到了这里,无需手动创建):
index.html文件只有最基础的html代码,它唯一的目的就是加载打包后的js文件(bundle.js)。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>Webpack Sample Project</title> 6 </head> 7 <body> 8 <div id="root"></div> 9 <script type="text/javascript" src="bundle.js"></script> 10 </body> 11 </html>
Greeter.js只包括一个用来返回包含问候信息的html元素的函数。
1 // Greeter.js 2 module.exports = function() { 3 var greet = document.createElement('div'); 4 greet.textContent = "Hi there and greetings!"; 5 return greet; 6 };
main.js用来把Greeter模块返回的节点插入页面。
1 //main.js 2 var greeter = require('./Greeter.js'); 3 document.getElementById('root').appendChild(greeter());
3.示例程序已经准备好了,下面就是利用webpack将Greeter.js和main.js进行打包了。
webpack可以在终端中使用,其最基础的命令是:
1 webpack {entry file/入口文件} {destination for bundled file/存放bundle.js的地方}
只需要指定一个入口文件,webpack将自动识别项目所依赖的其它文件,不过需要注意的是如果你的webpack没有进行全局安装,那么当你在终端中使用此命令时,需要额外指定其在node_modules中的地址。继续上面的例子,在终端中属于如下命令:
1 //webpack非全局安装的情况 2 node_modules/.bin/webpack app/main.js public/bundle.js
如果看到如下结果,则说明打包成功了:
可以看出webpack同时将main.js和Greeter.js打包到一个文件bundle.js中了。现在就可以访问index.html,你的浏览器肯定能够显示出Hi there and greetings!了。
有没有很激动,现在我们已经成功的使用webpack打包了一个文件了。不过如果在终端中进行复杂的操作,还是不太方便且容易出错的,接下来看看webpack的另一种使用方法。
二、通过配置文件使用webpack
webpack拥有很多其它的比较高级的功能(比如说loaders和plugins),这些功能其实都可以通过命令行模式实现,但是正如已经提到的,这样不太方便且容易出错,一个更好的办法是定义一个配置文件,这个配置文件其实也是一个简单的JavaScript模块,可以把所有的与构建相关的信息放在里面。
还是继续上面的例子来说明如何写这个配置文件,在demo文件夹的根目录下新建一个名为webpack.config.js的文件,并在其中进行最简单的配置,如下所示,它包含入口文件路径和打包后的文件路径。
1 module.exports = { 2 entry: __dirname + "/app/main.js", // 入口文件 3 output: { 4 path: __dirname + "/public", // 打包后文件的存放路径 5 filename: "bundle.js" // 打包后文件的文件名 6 } 7 }
注:“__dirname”是Node.js中的一个全局变量,它指向当前执行脚本所在的目录。
现在如果你需要打包文件,只需要在终端里运行webpack(非全局安装需使用node_modules/.bin/webpack)命令就可以了,这条命令会自动参考webpack.config.js文件中的配置选项打包你的项目。
这里需要对入口文件的配置做一个特别说明。
Entry的作用是告诉webpack的根模块,或者说起点在哪。值可以是String,Array或者Object。这里可能会让你困惑,但是不同的类型有各自的用武之地。
如果只有一个entry(大部分APP都是),可以选择任何格式,结果都是一样的。
1 // String 2 module.exports = { 3 entry: __dirname + "/app/main.js", 4 output: { 5 path: __dirname + "/public", 6 filename: "bundle.js" 7 } 8 } 9 10 // Array 11 module.exports = { 12 entry: [__dirname + "/app/main.js"], 13 output: { 14 path: __dirname + "/public", 15 filename: "bundle.js" 16 } 17 } 18 19 // Object 20 module.exports = { 21 entry: { 22 index: __dirname + "/app/main.js" 23 }, 24 output: { 25 path: __dirname + "/public", 26 filename: "bundle.js" 27 } 28 }
如果你想添加多个文件并且这些文件之间没有相互依赖的话,可以使用Array格式。这个时候main.js以及main.js所依赖的所有模块和test.js会一起被打包到bundle.js中,只不过test.js中的内容会放到bundle.js的最后。
1 module.exports = { 2 entry: [__dirname + "/app/main.js", __dirname + "/app/test.js"], 3 output: { 4 path: __dirname + "/public", 5 filename: "bundle.js" 6 } 7 }
另外,假设你有一个真正的多页应用,而不是一个多页面的SPA。有多个html文件(index.html和profile.html)。然后可以通过对象形式的entry来让webpack一次性生成多个包。这个时候entry对象的key将会作为打包生成的文件名。然后我们在需要的html页面中嵌入需要的打包文件就好了。
1 module.exports = { 2 entry: { 3 index: __dirname + "/app/main.js", 4 profile: __dirname + "/app/test.js" 5 }, 6 output: { 7 path: __dirname + "/public", 8 filename: "[name].js" 9 } 10 }
当然,它们三者也是可以组合使用的。
1 module.exports = { 2 entry: { 3 index: __dirname + "/app/main.js", 4 profile: __dirname + "/app/test.js", 5 page: [__dirname + "/app/page1.js", __dirname + "/app/page2.js"] 6 }, 7 output: { 8 path: __dirname + "/public", 9 filename: "[name].js" 10 } 11 }
好了,关于webpack的基础使用,就先整理到这里,后续再补充一些比较强大的功能。