Webpack是模块打包工具。css
Webpack已成为现代Web开发最重要的工具之一。首先,它是一个JavaScript模板打包工具,他能转换全部的前端资源,如HTML和CSS,甚至图片。它可让你更好地控制你应用程序的HTTP请求数量,并容许你使用其余的风格资源(如Jade,Sass和ES6)。Webpack还容许你轻松地从npm上使用软件包。html
本文面向刚刚接触Webpack的初学者,主要介绍Webpack的初始设置和配置、模板、加载程序、插件、代码拆分和热模块替换。若是你发现视频教程对你更有帮助,我强烈推荐Glen Maddern’s的Webpack from First Principles做为一个起点,了解是什么使得Webpack那么特别。前端
接下来,你须要有Node.js installed环境,你也能够 download the demo app from our Github reponode
让咱们用npm
新建一个项目并初始化,安装Webpack
:webpack
mkdir webpack-demo cd webpack-demo npm init -y npm install webpack@beta --save-dev mkdir src touch index.html src/app.js webpack.config.js
编辑这些文件:git
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello webpack</title> </head> <body> <div id="root"></div> <script src="dist/bundle.js"></script> </body> </html>
// src/app.js const root = document.querySelector('#root') root.innerHTML = `<p>Hello webpack.</p>`
// webpack.config.js const webpack = require('webpack') const path = require('path') const config = { context: path.resolve(__dirname, 'src'), entry: './app.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [{ test: /\.js$/, include: path.resolve(__dirname, 'src'), use: [{ loader: 'babel-loader', options: { presets: [ ['es2015', { modules: false }] ] } }] }] } } module.exports = config
上面的配置是一个常见的起点,它指示webpack
将咱们的入口点src/app.js
编译输出到/dist/bundle.js
中,全部的.js
文件将经过Babel
从ES2015
转换到ES5
。github
为了让它运行,咱们须要安装三个包:babel-core
,Webpack
模块和资源转换器——babel-loader
和预设的babel-preset-es2015
。{ modules: false }
启用Tree Shaking把咱们包中不被使用的输出删除,从而下降文件大小。web
npm install babel-core babel-loader babel-preset-es2015 --save-dev
最后,将package.json
文件中的script
部分替换为:npm
"scripts": { "start": "webpack --watch", "build": "webpack -p" },
在命令行中运行npm start
来监视模式启动webpack
——每当咱们src
目录中的.js
文件更改时,都会从新编译输出到bundle
中。控制台中的输出会告诉咱们正在建立的包,重要的是要注意包的数量和大小。
如今你应该能够在浏览器中加载index.html
,并使用“Hello webpack”。json
open index.html
打开dist/bundle.js
查看webpack
作了什么,顶部是webpack
的模板引导代码,底部是咱们的模板。也许你对这不会有很深入的印象,但若是你跟着进度学到了这里,你能够运用ES6 module
和webpack
生产一个能在全部浏览器中运行的用于生产的包。
输入命令行Ctrl + C
中止webpack
,并运行npm run build
用于在生产模式下编译咱们的包。
请注意,此时包的大小已经从2.16kB降低到585字节。
再查看一下dist/bundle.js
,你会看到一个丑恶的代码,咱们的包已经压缩或丑化(uglify/minify),代码运行效果是同样的,但它并不符合最少字符须要。
开箱即用的webpack
知道如何使用各类格式的JavaScript模块,最显著的两种是:
ES2015的import
语句
CommonJS的require()
语句
咱们能够经过安装lodash并从app.js
导入它来测试一下:
npm install lodash --save
// src/app.js import {groupBy} from 'lodash/collection' const people = [{ manager: 'Jen', name: 'Bob' }, { manager: 'Jen', name: 'Sue' }, { manager: 'Bob', name: 'Shirley' }, { manager: 'Bob', name: 'Terrence' }] const managerGroups = groupBy(people, 'manager') const root = document.querySelector('#root') root.innerHTML = `<pre>${JSON.stringify(managerGroups, null, 2)}</pre>`
运行npm start
启动webpack
,刷新一下index.html
页面,你能够看到按manager
排序的人数组。
让咱们来把people
数组移动到本身的people.js
文件中:
// src/people.js const people = [{ manager: 'Jen', name: 'Bob' }, { manager: 'Jen', name: 'Sue' }, { manager: 'Bob', name: 'Shirley' }, { manager: 'Bob', name: 'Terrence' }] export default people
咱们可使用相对路径简单地从app.js
导入它。
// src/app.js import {groupBy} from 'lodash/collection' import people from './people' const managerGroups = groupBy(people, 'manager') const root = document.querySelector('#root') root.innerHTML = `<pre>${JSON.stringify(managerGroups, null, 2)}</pre>`
注意:没有相对路径的导入,如lodash/collection
是从npm
安装到node_modules
的模块,本身写的模块是须要加一个相对路径,如./people
来告诉webpack
区分好各个模块。
咱们已经介绍了babel-loader
——不少loders之一,经过配置用于告诉webpack
当遇到不一样文件类型的import
时要怎么作。你能够把过个loader
整合在一块儿,咱们能够经过从JavaScript
中导入Sass
来很好地了解这是如何工做的。
这种转换涉及到三个独立的loader
和node-sass
库:
npm install css-loader style-loader sass-loader node-sass --save-dev
在webpack.config.js
中给咱们的.scss
文件添加新的配置规则:
// webpack.config.js rules: [{ test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] }, { // ... }]
注意:每次更改
webpack.config.js
中的任何规则时,都须要使用Ctrl+C
和npm start
命令从新启动项目。
loader
数组会以相反的顺序执行:
sass-loader
把Sass转换成CSS
css-loader
把CSS解析到JavaScript中,并分解全部的依赖关系
style-loader
把咱们的CSS输出到文档中的<style>标签中
你能够把它当作函数调用,一个loader
的输出会做为input
输入下一个。
styleLoader(cssLoader(sassLoader('source')))
让咱们来添加一个Sass源文件:
/* src/style.scss */ $bluegrey: #2B3A42; pre { padding: 20px; background: $bluegrey; color: #dedede; text-shadow: 0 1px 1px rgba(#000, .5); }
你如今能够从JavaScript中直接请求Sass,从app.js
的头部引入:
// src/app.js import './style.scss' // ...
刷新一下index.html
你就会看到刚添加的样式了。
咱们刚刚从JavaScript中导入了Sass文件,做为一个模块。
打开dist/bundle.js
文件并搜索“pre {
。事实上,咱们的Sass已经被编译成一个CSS字符串,并保存为咱们的bundle
中的一个模板。当咱们在JavaScript中导入此模板时,style-loader
会将该字符串输出到嵌入的<style>
标签中。
我知道你确定是在想,为何会这样?
我不会在这里深刻讨论这个话题,可是你能够从如下几个方面考虑:
你可能但愿包含在项目中的JavaScript组件依赖于其余资源(HTML、CSS、Images、SVG)来正常运行,若是这些资源能够整合在一块儿,那么导入和使用就会容易不少。
消除死代码:当JS代码不须要导入JS组件时,将再也不导入CSS,生成的bundle
只会包含执行某些操做的代码。
CSS模块:CSS的全局命名空间使得开发者很难确信CSS的一个更改不会产生任何的反作用。CSS modules经过在默认状况下使CSS local和暴露在JavaScript下使用的惟一类名来改变这一问题。
经过巧妙的方法打包/拆分代码,来较少HTTP请求数量。
咱们可以看到的最后一个关于loader
的例子是使用url-loader
处理图片。
在标准的HTML文档中,当浏览器遇到一个<img>
标签或background-image
属性时会抓取图片。使用webpack,当遇到小图片的时候,你能够经过将图片源做为字符串存储在JavaScript中来优化小图片,这样,你预加载它们,浏览器就不用为了提取它们而发起单独的请求了。
npm install file-loader url-loader --save-dev
添加一个加载图片的规则:
// webpack.config.js rules: [{ test: /\.(png|jpg)$/, use: [{ loader: 'url-loader', options: { limit: 10000 } // Convert images < 10k to base64 strings }] }, { // ... }]
从新运行项目:Ctrl + C
和npm start
使用下面命令下载test image
curl https://raw.githubusercontent.com/sitepoint-editors/webpack-demo/master/src/code.png --output src/code.png
你如今能够在app.js
的头部导入图片源:
// src/app.js import codeURL from './code.png' const img = document.createElement('img') img.src = codeURL img.style.backgroundColor = "#2B3A42" img.style.padding = "20px" img.width = 32 document.body.appendChild(img) // ...
这将包括一张图片,其中src
属性包含图片自己的data URL
:
<img src="data:image/png;base64,iVBO..." style="background: #2B3A42; padding: 20px" width="32">
此外,因为使用url()
引用的css-loader
图片也经过url-loader
运行,这就好像直接在CSS中嵌入它们。
/* src/style.scss */ pre { background: $bluegrey url('code.png') no-repeat center center / 32px 32px; }
编译成为:
pre { background: #2b3a42 url("data:image/png;base64,iVBO...") no-repeat scroll center center / 32px 32px; }
你如今应该能够看到loders
是如何帮助在资源间创建一个依赖关系树的,这是webpack首页上的图片展现:
尽管JavaScript是入口点,但webpack注意到你的其余资源(如HTML、CSS和SVG)都具备各自的依赖关系——这些依赖关系是应该视为构建过程的一部分的。
做者:Mark Brown
原文连接:A Beginner’s Guide to Webpack 2 and Module Bundling