Webpack是目前基于React和Redux开发的应用的主要打包工具。我想使用Angular 2或其余框架开发的应用也有不少在使用Webpack。css
当我第一次看到Webpack的配置文件时,它看起来很是的陌生,我很是的疑惑。通过一段时间的尝试以后我认为这是由于Webpack只是使用了比较特别的语法和引入了新的原理,所以会让使用者感到疑惑。这些也是致使Webpack不被人熟悉的缘由。html
由于刚开始使用Webpack很让人疑惑,我以为有必要写几篇介绍Webpack的功能和特性的文章以帮助初学者快速理解。此文是最开始的一篇。node
正如js文件能够是一个“模块(module)”同样,其余的(如css、image或html)文件也可视做模 块。所以,你能够require('myJSfile.js')亦能够require('myCSSfile.css')。这意味着咱们能够将事物(业务)分割成更小的易于管理的片断,从而达到重复利用等的目的。react
传统的模块打包工具(module bundlers)最终将全部的模块编译生成一个庞大的bundle.js文件。可是在真实的app里边,“bundle.js”文件可能有10M到15M之大可能会致使应用一直处于加载中状态。所以Webpack使用许多特性来分割代码而后生成多个“bundle”文件,并且异步加载部分代码以实现按需加载。webpack
好了,下面来看看那些使人困惑的部分吧。web
首先要知道的是Webpack有许许多多的特性,一些是”开发模式“下才有的,一些是”生产模式“下才有的,还有一些是两种模式下都有的。npm
一般使用到Webpack如此多特性的项目都会有两个比较大的Webpack配置文件
复制代码
为了生成bundles文件你可能在package.json文件加入以下的scripts项:json
"scripts": {
// 运行npm run build 来编译生成生产模式下的bundles
"build": "webpack --config webpack.config.prod.js",
// 运行npm run dev来生成开发模式下的bundles以及启动本地server
"dev": "webpack-dev-server"
}
复制代码
值得注意的是,Webpack做为模块打包工具,提供两种用户交互接口:segmentfault
Webpack CLI tool:默认的交互方式(已随Webpack自己安装到本地)数组
webpack-dev-server:一个Node.js服务器(须要开发者从npm自行安装)
Webpack CLI(有利于生产模式下打包)
这种方式能够从命令行获取参数也能够从配置文件(默认叫webpack.config.js)获取,将获取到的参数传入Webpack来打包
固然你也能够从命令行(CLI)开始学习Webpack,之后你可能主要在生产模式下使用到它。
复制代码
用法:
方式1:
// 全局模式安装webpack
npm install webpack --g
// 在终端输入
$ webpack // <--使用webpack.config.js生成bundle
方式 2 :
// 费全局模式安装webpack而后添加到package.json依赖里边
npm install webpack --save
// 添加build命令到package.json的scripts配置项
"scripts": {
"build": "webpack --config webpack.config.prod.js -p",
...
}
// 用法:
"npm run build"
复制代码
webpack-dev-server(有利于在开发模式下编译)
这是一个基于Express.js框架开发的web server,默认监听8080端口。server内部调用Webpack,这样作的好处是提供了额外的功能如热更新“Live Reload”以及热替换“Hot Module Replacement”(即HMR) 用法:
方式 1:
// 全局安装
npm install webpack-dev-server --save
// 终端输入
$ webpack-dev-server --inline --hot
用法 2:
// 添加到package.json scripts
"scripts": {
"start": "webpack-dev-server --inline --hot",
...
}
// 运行:
$ npm start
// 浏览器预览:
http://localhost:8080
复制代码
注意像inline和hot这些选项是Webpack-dev-server特有的,而另外的如hide-modules则是CLI模式特有的选项。
另外值得注意的是你能够经过如下两种方式向webpack-dev-server传入参数:
经过webpack.config.js文件的"devServer"对象
经过CLI选项
// 经过CLI传参
webpack-dev-server --hot --inline
// 经过webpack.config.js传参
devServer: {
inline: true,
hot:true
}
复制代码
我发现有时devServer配置项(hot: true 和inline: true)不生效,我更偏向使用以下的方式向CLI传递参数
// package.json
{
"scripts": "webpack-dev-server --hot --inline"
}
注意:肯定你没有同时传入hot:true和-hot
复制代码
“inline”选项会为入口页面添加“热加载”功能,“hot”选项则开启“热替换(Hot Module Reloading)”,即尝试从新加载组件改变的部分(而不是从新加载整个页面)。若是两个参数都传入,当资源改变时,webpack-dev-server将会先尝试HRM(即热替换),若是失败则从新加载整个入口页面。
// 当资源发生改变,如下三种方式都会生成新的bundle,可是又有区别:
// 1. 不会刷新浏览器
$ webpack-dev-server
//2. 刷新浏览器
$ webpack-dev-server --inline
//3. 从新加载改变的部分,HRM失败则刷新页面
$ webpack-dev-server --inline --hot
复制代码
Enter配置项告诉Webpack应用的根模块或起始点在哪里,它的值能够是字符串、数组或对象。这看起来可能使人困惑,由于不一样类型的值有着不一样的目的。
像绝大多数app同样,假若你的应用只有一个单一的入口,enter项的值你可使用任意类型,最终输出的结果都是同样的。
可是,若是你想添加多个彼此不互相依赖的文件,你可使用数组格式的值。
例如,你可能在html文件里引用了“googleAnalytics.js”文件,能够告诉Webpack将其加到bundle.js的最后。
//profile.html
<script src=”dist/profileEntry.js”></script>
//index.html
<script src=”dist/indexEntry.js”></script>
复制代码
注意:文件名取自“entry”对象的键名。
enter:混合类型
你也能够在enter对象里使用数组类型,例以下面的配置将会生成3个文件:vender.js(包含三个文件),index.js和profile.js文件。
output项告诉webpack怎样存储输出结果以及存储到哪里。output的两个配置项“path”和“publicPath”可能会形成困惑。
“path”仅仅告诉Webpack结果存储在哪里,然而“publicPath”项则被许多Webpack的插件用于在生产模式下更新内嵌到css、html文件里的url值。
然而你也可使用Webpack的“publicPath”选项和一些插件来在生产模式下编译输出文件时自动更新这些url。
模块加载器是可自由添加的Node模块,用于将不一样类型的文件“load”或“import”并转换成浏览器能够识别的类型,如js、Stylesheet等。更高级的模块加载器甚至能够支持使用ES6里边的“require”或“import”引入模块。
例如,你可使用babel-loader来将使用ES6语法写成的文件转换成ES5:
module: {
loaders: [{
test: /\.js$/, // 匹配.js文件,若是经过则使用下面的loader
exclude: /node_modules/, // 排除node_modules文件夹
loader: 'babel' // 使用babel(babel-loader的简写)做为loader
}]
复制代码
链式(管道式)的加载器(从右往左执行)
多个loader能够用在同一个文件上而且被链式调用。链式调用时从右到左执行且loader之间用“!”来分割。
例如,假设咱们有一个名为“myCssFile.css”的css文件,而后咱们想将它的内容使用style标签内联到最终输出的html里边。咱们可使用css-loader和style-loader两个loader来达到目的。
module: {
loaders: [{
test: /\.css$/,
loader: 'style!css' //(short for style-loader!css-loader)
}]
复制代码
这里展现它是如何工做的:
模块加载器(loader)自身能够根据传入不一样的参数进行配置。
在下面的例子中,咱们能够配置url-loader来将小于1024字节的图片使用DataUrl替换而大于1024字节的图片使用url,咱们能够用以下两种方式经过传入“limit“参数来实现这一目的
babal-loader使用”presets“配置项来标识如何将ES6语法转成ES5以及如何转换React的JSX成js文件。咱们能够用以下的方式使用”query“参数传入配置:
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
}
]
}
复制代码
插件通常都是用于输出bundle的node模块。
例如,uglifyJSPlugin获取bundle.js而后压缩和混淆内容以减少文件体积。
相似的extract-text-webpack-plugin内部使用css-loader和style-loader来收集全部的css到一个地方最终将结果提取结果到一个独立的”styles.css“文件,而且在html里边引用style.css文件。
//webpack.config.js
// 获取全部的.css文件,合并它们的内容而后提取css内容到一个独立的”styles.css“里
var ETP = require("extract-text-webpack-plugin");
module: {
loaders: [
{test: /\.css$/, loader:ETP.extract("style-loader","css-loader") }
]
},
plugins: [
new ExtractTextPlugin("styles.css") //Extract to styles.css file
]
}
复制代码
注意:若是你只是想把css使用style标签内联到html里,你没必要使用extract-text-webpack-plugin,仅仅使用css loader和style loader便可
你可能已经意识到了,Loader处理单独的文件级别而且一般做用于包生成以前或生成的过程当中。
而插件则是处理包(bundle)或者chunk级别,且一般是bundle生成的最后阶段。一些插件如commonschunkplugin甚至更直接修改bundle的生成方式。
不少Webpack的配置文件都有一个resolve属性,而后就像下面代码所示有一个空字符串的值。空字符串在此是为了resolve一些在import文件时不带文件扩展名的表达式,如require('./myJSFile')或者import myJSFile from './myJSFile'(译者注:实际就是自动添加后缀,默认是当成js文件来查找路径)
{
resolve: {
extensions: ['', '.js', '.jsx']
}
}
复制代码
就这么多。
转载自:https://segmentfault.com/a/1190000005089993?utm_source=tuicool&utm_medium=referral