背景
一直对webpack的打包流程很感兴趣,但是无奈官网文档实在太多,搜出来的大部分文章要么偏理论要么纯粹讲过程不讲原理,最近终于找到一篇入门文章,文章对于初学者讲的很清晰,但是由于是英文的,而且我没有找到这篇文章对应的中文翻译版,所以本文主要是对那篇文章进行翻译,介绍一下webpack2的入门知识。
webpack2入门手册(译文)
Webpack是一个模块打包机
Webpack已然成为当前web开发最重要的工具之一。首先它是一个Javascript的打包工具,但同时他也能打包包括HTML,CSS,甚至是图片等形式的资源。它能更好的控制你正在编写的App的HTTP请求,并且允许你去使用更多的资源(如Jade,Sass以及ES6)。Webpack同时允许你更容易的从npm获取安装包。
这篇文章主要面向那些对于webpack完全陌生的同学,内容将包括初始安装和配置,模块,模块加载器,插件,代码拆分以及模块热替换(HMR,hot module replacement)。如果你觉得入门视频比较有用的话,我推荐Glen Maddern的Webpack初体验作为开始学习的起点,会让你理解为什么webpack如此特殊。
为了更加后续的阅读,请确保先安装了Node.js,安装可以参考Node.js安装教程。你也在Github上下载到对应的Demo。
安装
让我们用npm和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
编辑以下文件:
Hello webpack
// src/app.js
const root = document.querySelector('#root')
root.innerHTML = `Hello webpack.
`
// 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文件都将通过Bable从ES2015转换为ES5。
为了让这个项目能运行起来,我们需要安装三个安装包,bable-core,webpack的加载器bable-loader以及预处理模块babel-preset-es2015,这些模块都是为了支持Javascript的编写。{ modules: false }可以确保使用Tree Shaking去去除掉不必要的模块,同时会降低文件大小。
npm install babel-core babel-loader babel-preset-es2015 --save-dev
最后使用下面代码更新package.json:
"scripts": {
"start": "webpack --watch",
"build": "webpack -p"
},
运行npm start将会以观察模式启动webpack,在这种模式下,会持续监听我们src文件夹下的.js文件。控制台的输出结果显示了生成的打包后的文件,我们应该持续关注生成的文件的大小和数量。
现在你可以在浏览器中访问index.html,将会看到“Hello webpack.”
open index.html
打开dist/bundle.js看看webpack到底做了什么事,在文件的顶部是bootstrapping模块的代码,在它下面是我们自己的模块。你可能目前还没有什么感觉webpack好处,但是你现在可以编写ES6代码并且webpack将会把各个模块打成生产所需要的包,这样所有浏览器都能访问。
使用Ctrl + C停止webpack的服务,运行npm run build,编译成生成环境所需要的包。
注意:包的大小从2.61 kB降到了585 bytes 重新看看dist/bundle.js,你会发现代码变得一团糟,UglifyJS对打包后的代码进行了压缩,运行起来是没有差别的,但同时字符数是相当少的。
模块
对于外部模块,webpack有多种方式去引入,其中比较重要的两种是:
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 = `${JSON.stringify(managerGroups, null, 2)}
`
运行npm start重启webpack并刷新index.html,你会在页面上看到一个按照manager分好组人名的数组。 接下来让我们把这个数组部分单独放在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 = `${JSON.stringify(managerGroups, null, 2)}
`
注意:导入像'lodash/collection这种不使用相对路径的,是那些通过npm安装的,从/node_modules中引入,你自定义的模块则需要像'./people'相对路径的方式引入,通过这种方式可以对两种模块进行区分。
加载器
我们已经介绍了babel-loader,它是众多loader中的一种,能够告诉webpack当遇到不同的文件时如何处理。比较好的方式是将loader进行串联,加载到一个加载器中,我们通过从Javascript中引入Sass包来看看loader是如何进行工作的。
Sass
这个转换器包括了三个单独的加载器和node-sass库:
npm install css-loader style-loader sass-loader node-sass --save-dev
在配置文件中为.scss引入新的规则:
// webpack.config.js
rules: [{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}, {
// ...
}]
注意:不管什么时候你改变了webpack.config.js中的加载规则,你都需要通过Ctrl + C然后npm start的方式重启webpack。
loader以倒序的方式运行:
sass-loader转换Sass成CSS
css-loader将CSS解析Javascript并解决依赖包问题
style-loader将CSS导出成便签放在document下
你可以将上述过程想象成函数的调用关系,一个函数运行的结果作为另一个函数的输入:
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);
}
现在你可以在你的app.js中直接引入Sass文件:
// src/app.js
import './style.scss'
// ...
刷新index.html你会看到样式发生了变化。
Javascript中的CSS
我们刚刚把Sass作为一个模块引入到我们的入口文件中。
打开dist/bundle.js,搜索pre {。事实上,Sass已经被编译成一段CSS的字符串,并以模块的形式存在。当我们在我们的Javascript文件中导入这个模块时,style-loader就会将其编译输出成内嵌的