[翻译]Webpack解惑
本文译自Webpack — The Confusing Parts,原文需翻墙。
Webpack现在是React应用程序标配的模块打包器,我估计Angular2和其他框架的用户也在大规模使用。我第一次看到Webpack配置文件的时候,感觉实在太陌生,太混乱了。在玩了一段时间后,我现在觉得是Webpack独特的语法和新的理念导致了初学阶段的复杂度。顺便说一下,也正是因为这些理念,才让Webpack如此受欢迎。
正因为Webpack入门容易让人困惑,所以我写了这篇文章,希望能够帮助其他人更轻松的入门,用起来更顺手。这是第一部分。
Webpack的核心理念
Webpack的两个核心理念是:
- 万物皆模块:就像JS文件可以当做模块,那么其他所有的文件(CSS,图片,HTML)都可以当做模块。这样,就可以require(“myJSfile.js”)或者require(“myCSSfile.css”)。这意味着,我们可以对模块再进行细分,分割成更小更容易管理的粒度,实现复用等等。
- 按需加载,异步加载:一般的模块打包器会打包所有的模块然后生成一个巨大的输出文件bundle.js。但是在许多实际应用的APP中,这个bundle.js可能会有10MB-15MB那么大,并且总是会加载!而Webpack有一些功能可以分割代码然后生成多个"bundle"文件并且可以在你需要的时候异步加载。
1.开发模式 VS 生产模式
首先要注意的事情是Webpack有太多的功能,有些只有开发模式下可以用,有些只有生产模式下可以用,还有一些开发模式和生产模式下都可以用。

一般情况下,大部分项目都会用到许多功能,所以通常有两个大型的Webpack配置文件。
执行打包的话可以像下面这样在package.json中写脚本:
“scripts”: {
//npm run build 生产模式打包
“build”: “webpack --config webpack.config.prod.js”,
//npm run dev 开发模式打包并且运行dev-server
“dev”: “webpack-dev-server”
}
2.Webpack CLI VS webpack-dev-server
需要强调的一点是Webpack这个模块打包器提供了两个接口:
- Webpack CLI工具-默认接口(作为Webpack的一部分自动安装)。
- webpack-dev-server工具-一个Node.js服务器(需要单独安装)。
Webpack CLI(适用于生产模式的构建)
此工具可以通过CLI或者配置文件(默认值:webpack.config.js)获取配置并传递给Webpack进行打包。
初学Webpack的时候可以使用CLI,大部分可能只会用来进行生产模式的构建。
用法:
//用法1: //全局安装
npm install webpack-dev-server --g //在终端中运行
$ webpack-dev-server --inline --hot //用法2: //写到package.json的脚本里
“scripts”: {
“start”: “webpack-dev-server --inline --hot”,
...
} //运行脚本
$ npm start //打开浏览器
http://localhost:8080
Webpack VS webpack-dev-server 选项
值得注意的是,有些选项,例如"inline"和"hot"是webpack-dev-server独有的选项,还有一些选项像是"hide-modules"是CLI独有的选项。
webpack-dev-server CLI 选项 VS config 选项
还有一点要注意的是,有两种方式向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)不起作用,所以最好还是把命令写到package.json里,通过CLI传递选项。
//package.json
{
scripts:
{“start”: “webpack-dev-server --hot --inline”}
}
注意:确保没有同时传递hot: true和--hot。
“hot” VS “inline” webpack-dev-server 选项
"inline"选项为整个页面添加了"Live Reloading"功能,而"hot"选项开启了"Hot Module Reloading"功能,这样就会尝试着重载发生变化的组件,而不是整个页面。
//当源码改变时,下面三种命令都会导致重新打包,但是 //1. 不会重载浏览器中的页面
$ webpack-dev-server //2. 会重载整个页面
$ webpack-dev-server --inline //3. reloads just the module(HMR), or the entire page if HMR fails
//3. 重载改变的模块(HMR),如果HMR失败的话就重载整个页面
$ webpack-dev-server --inline --hot
3."entry"-String VS Array VS Object
Entry的作用是告诉Webpack根模块,或者说起点在哪。值可以是String,Array或者Object。这里可能会让你困惑,但是不同的类型有各自的用武之地。
如果只有一个entry(大部分APP都是),可以选择任何格式,结果都是一样的。

entry-Array
如果你想添加多个文件并且这些文件不会互相依赖的话,可以使用Array格式。 例如:你可能想在HTML中放入"googleAnalytics.js",可以像下图这样把它添加到到bundle.js的结尾

entry-Object
现在,假设你有一个真正的多页应用,而不是一个多页面的SPA。有多个HTML文件(index.html和profile.html)。然后可以通过对象形式的entry来让Webpack一次性生成多个包。
下面的配置会生成两个JS文件,indexEntry.js和profileEntry.js,可以分别在indexEntry.html和profileEntry.html中使用。

//profile.html
<script src=”dist/profileEntry.js”></script>
//index.html
<script src=”dist/indexEntry.js”></script>
注意:文件名来自"entry"对象的键名。
entry-组合
可以在entry对象中使用数组形式的entry,举个例子,下面的配置会生成三个文件:一个包含有三个库文件的vendoe.js,一个index.js和一个profile.js。

4.output — "path" Vs "publicPath"
output的作用是告诉Webpack如何存储生成的结果文件,其中path和publicPath这两个属性可能会让人困惑。
path仅仅用来告诉Webpack在哪里存放结果文件,而publicPath被一些Webpack插件用来处理CSS,HTML文件中的URL,一般用于生产模式。

例如,CSS里,可能会用./test.png这样的url来加载本地图片,但是在生产模式中,"test.png"这种图片可能是放在CDN上的,服务器是跑在云平台上的。这就意味着,生产模式中,你不得不手动处理文件里的URL保证它们指向的是CDN地址。
现在,你可以用Webpack的publicPath和一些具有publicPath检测功能的插件来自动处理文件中的URL。

// 开发模式:服务器和图片都在本地
.image {
background-image: url(‘./test.png’);
} // 生产模式:服务器跑在云平台上,图片在CDN上
.image {
background-image: url(‘https://someCDN/test.png’);
}
Loader 和 Loader链
Loader是用来加载(load)或输入(import)文件的Node模块,不同的loader可以将各种类型的文件转换为浏览器能够接受的格式如JS,Stylesheets等等。更进一步来说,loader允许通过require或ES6的import语句在JS文件中引入各种文件。
例如,可以用babel-loader把ES6语法写的JS转换成浏览器能够兼容的ES5形式:
module: {
loaders: [{
test: /\.js$/, ←检测".js"文件, 通过的话,则使用对应loader
exclude: /node_modules/, ←排除 node_modules 文件夹
loader: ‘babel’ ←使用 babel (‘babel-loader’的简写形式)
}]
Loader链(从右向左工作)
多个loader可以链式调用,作用于同一种文件类型。工作链的调用顺序是从右向左,各个loader之间使用"!"分开。
例如,有一个CSS文件myCSSFile.css,我们想把文件里的内容放到HTML文件的标签中。想实现这一点,需要用到两个loader:css-loader和style-loader。
工作流程如下图:
- Webpack搜索模块内依赖的CSS文件,通过检查JS文件中是否有require(myCSSFile.css)语句。如果找到了这个依赖文件,Webpack首先把文件传给css-loader。
- css-loader载入所有的CSS语句,和CSS文件内的依赖(例如@import otherCSS),处理为JSON,接着Webpack会把这个JSON传给style-loader。
- style-loader拿到这个JSON之后会把它放到一个style标签中-,然后把这个style插入index.html文件中。
6.Loader本身也是可以配置的
Loader本身也是可以配置的,传入不同的参数可以实现不同的功能。
在下面的例子中,我们配置url-loader使小于1024字节的图片使用DataURL,大于1024字节的图片使用URL。如下图,有两种方式传入limit参数来实现此功能。

7. .babelrc文件
babel-loader用presets配置将ES6转换为ES5,把React JSX解析为JS。我们可以像下面这样传入query参数来配置:
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
}
]
}
然而许多项目中babel的配置会很复杂,所以最好把所有的babel-loader配置写在.babelrc文件里。babel-loader会自动加载.babelrc文件如果该文件存在的话。 所以在许多例子中,你会看到下面这种写法:
//webpack.config.js
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel'
}
]
} //.bablerc
{
“presets”: [“react”, “es2015”]
}
8.插件
插件是用来处理打包结果的额外模块。
例如,uglifyJSPlugin会对bundle.js进行压缩和混淆处理,可以压缩文件体积。
还有extract-text-webpack-plugin会在内部调用css-loader和style-loader把所有的CSS收集在一起,最后把结果抽取到一个单独的外部styles.css文件并且在index.html中链接styles.css。
//webpack.config.js
//收集所有的.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放到HTML的style标签中,可以不使用extract-text-webpack-plugin,只要用css-loader和style-loader就可以了。就像下面这样:
loaders: [{
test: /\.css$/,
loader: ‘style!css’ <--(style-loader!css-loader的简写形式)
}]
9.Loader VS 插件
你可能会意识到,Loader是在打包前或打包的过程中作用于单个文件。插件通常在打包过程结束后,作用于包或者chunk级别。还有一些插件例如commonChunksPlugins,更进一步,会修改如何创建包。
10.解析文件扩展名
许多Webpack配置文件都有一个resolve extensions属性,其中包含一个像那面那样的空字符串。这个空字符串是用来帮助解析没有扩展名的文件输入,例如:require('./myJSFile')或者import myJSFile from './myJSFile'。
{
resolve: {
extensions: [‘’, ‘.js’, ‘.jsx’]
}
}
链接:https://zhuanlan.zhihu.com/p/24744677 来自知乎的分享
[翻译]Webpack解惑的更多相关文章
- webpack解惑:require的五种用法
我之前在 <前端搭环境之从入门到放弃>这篇文章中吐槽过,webpack中可以写commonjs格式的require同步语法,可以写AMD格式的require回调语法,还有一个require ...
- webpack解惑:多入口文件打包策略
本文是我用webpack进行项目构建的实践心得,场景是这样的,项目是大型类cms型,技术选型是vue,只支持chrome,有诸多子功能模块,全部打包在一起的话会有好几MB,所以最佳方式是进行多入口打包 ...
- webpack解惑:require的五种用法 (转)
我之前在 <前端搭环境之从入门到放弃>这篇文章中吐槽过,webpack中可以写commonjs格式的require同步语法,可以写AMD格式的require回调语法,还有一个require ...
- 前端笔记之Vue(五)TodoList实战&拆分store&跨域&练习代理跨域
一.TodoList 1.1安装依赖 安装相关依赖: npm install --save-dev webpack npm install --save-dev babel-loader babel- ...
- 翻译 | 关键CSS和Webpack: 减少阻塞渲染的CSS的自动化解决方案
原文地址: Critical CSS and Webpack: Automatically Minimize Render-Blocking CSS 原文作者: Anthony Gore 译者: 蜗牛 ...
- 【翻译】Webpack 4 从0配置到生产模式
查看原文 webpack 4 发布了! webpack 4 作为一个零配置的模块打包器 webpack 是强大的并且有许多独一无二的特点但是有一个痛点就是配置文件. 在中型到大型项目中为webpack ...
- 翻译 | 上手 Webpack ? 这篇就够了!
译者:小 boy (沪江前端开发工程师) 本文原创,转载请注明作者及出处. 原文地址:https://www.smashingmagazine.com/2017/02/a-detailed-intro ...
- webpack+react+redux+es6开发模式
一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...
- vue+ vue-router + webpack 踩坑之旅
说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案 老司机可以忽略下面的内容了 1)起因 考虑到数据分离的问题 因为server是express搭的 自然少 ...
随机推荐
- hdu2899 Strange fuction
在区间(0,100).在恒大二阶导数0.f(x)有极小值.用的最低要求的一阶导数值点: #include<math.h> #include<stdio.h> #include& ...
- OpenSUSE 13.2使用VPN(PPTP)
新年开始,有时查询个资料或是下个软件包并不是那么愉快,决定使用付费VPN,他们使用的是用户名及密码的验证方式 在网上找到了一个教程,挺详尽的,如果想按照步骤能使用即可的原则,跟着我一起设置,想了解更多 ...
- Java集合之ArrayList源码分析
1.简介 List在数据结构中表现为是线性表的方式,其元素以线性方式存储,集合中允许存放重复的对象,List接口主要的实现类有ArrayList和LinkedList.Java中分别提供了这两种结构的 ...
- QtNetwork说明(两)使用QT实现360的ctrl+ctrl特征
头文字说明: <span style="font-size:18px;">#ifndef GOOGLESUGGEST_H #define GOOGLESUGGEST_H ...
- C#快速随机按行读取大型文本文件
原文:C#快速随机按行读取大型文本文件 下面是我实现的一个数据文件随机读取类,可以随机读取大型文本文件的某一行.在我机器上对一个130MB的文本文件,读取第200000的速度从传统做法的400ms提高 ...
- hibernate在持久对象的生命周期(三州:自由状态,持久状态,自由状态 之间的转换)
三种状态的基本概念: 1. 临时身份(Transient):也被称为自由状态,它只存在于内存中,并且在数据库中没有相应的数据. 使用new创建的对象,久化,没有处于Session中,处于此状态的对象 ...
- js模版引擎handlebars.js实用教程
js模版引擎handlebars.js实用教程 阅读本文需要了解基本的Handlebars.js概念,本文并不是Handlebars.js基础教程,而是注重于实际应用,为读者阐述使用过程中可能会遇到的 ...
- 用Python复习离散数学(一)
最近要复习离散数学,不想挂啊,但是又想编程,大家知道啦,程序员离不开代码啊,所用想边复习边写代码,所以就自己用代码去实现一下离散的知识点,当做复习,自知自己的Python很渣,也想借此巩固一下基础,哈 ...
- 发挥jQuery的威力
发挥jQuery的威力 由于当前jQuery如此的如雷贯耳,相信不用介绍什么是jQuery了,公司代码中广泛应用了jQuery,但我在看一些小朋友的代码时发现一个问题,小朋友们使用的仅仅是jQuery ...
- 对中级 Linux 用户有用的 20 个命令
也许你已经发现第一篇文章非常的有用,这篇文章是继对初级Linux用户非常有用的20个命令的一个延伸. 第一篇文章的目的是为新手准备的而这篇文章则是为了Linux的中高级用户.在这里你将学会如何进行自定 ...