参考
Webpack傻瓜式指南 第一章:Webpack 缘起和入门
Webpack傻瓜式指南 第二章 Webpack进阶:实战技巧
Webpack傻瓜式指南 github code
webpack 2 打包实战
入门Webpack,看这篇就够了
一、webpack Helloworld
1.安装
npm install webpack -g
这里我安装的时候,版本已经是4.17.2了。使用webpack命令时会出现提示安装cli
PS E:\node\webpack> webpack -v
One CLI for webpack must be installed.
These are recommended choices, delivered as separate packages:
- webpack-cli (https://github.com/webpack/webpack-cli)
The original webpack full-featured CLI.
- webpack-command (https://github.com/webpack-contrib/webpack-command)
A lightweight, opinionated webpack CLI.
We will use "npm" to install the CLI via "npm install -D".
Which one do you like to install (webpack-cli/webpack-command):
以下参考初探webpack4
webpack4将命令行相关的操作抽离到了webpack-cli中,所以,要使用webpack4,必须安装webpack-cli。当然,如果你不想使用webpack-cli,社区也有替代方案webpack-command,虽然它与webpack-cli区别不大,但是还是建议使用官方推荐的webpack-cli。
webpack-cli除了能在命令行接受参数运行webpack外,还具备migrate和init功能。
- migrate用来升级webpack配置,能将webpack1的api升级到webpack2,现在用处不大。
- init可以快速生成一个webpack配置文件的模版,不过用处也不大,毕竟现在的脚手架都集成了webpack的配置。
更详细介绍请查看webpack-cli的文档
注意看,我这个Demo文件夹名字就叫webpack,所以在执行本地安装npm i -D webpack
时,报错了,需要改改名字。参考 局部安装webpack提示无法依赖
说明你执行命令的目录里有一个package.json文件,并且该文件里的name字段就叫webpack。
因为之前的文件夹名字叫webpack,然后使用npm init命令时,又使用了默认配置,所以package.json的名字也叫webpack了。
2.Webpack 天生支持 ES6 import 和 export 的模块语法,可以直接使用。当然你也可以使用 common.js 来写。
本节代码可以参见 /codes/part1/
在同一个文件夹下新建两个文件。
//hello.js
export default function () {
alert('from anohter planet')
}
//index.js
import hello from './hello'
//调用这个方法
hello()
当然现在如果直接在 html 页面里面引用 index.js 是无法执行的,浏览器是无法处理 ES6 模块或者是 common.js 规范的。 那么现在使用 webpack 来处理我们的入口文件。使用 webpack cli 可以传入两个参数,第一个是入口文件,这里就是 index.js, 第二个是输出文件的名字,这里命名为 bundle.js,暂时不管 bundle.js 里面是什么内容,做了哪些工作,但是可以知道就是 webpack 使用一定的魔力,把两个文件的依赖和运行在 bundle.js 完成了。
webpack index.js bundle.js
又报错了,版本问题,参考简单地使用webpack进行打包,改成
webpack index.js -o bundle.js
即可。
现在发现 bundle.js 被创建出来,再创建一个 html 页面来引用它。
<html>
<head>
<title> Our first webpack exmaple </title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
现在用浏览器打开这个 html 页面,发现 alert 出现了,任务完成,庆祝一下!我们可以用 ES6 来完成模块化开发啦。
3.使用配置文件
本节代码可以参见 /codes/part2/
现在每次都要使用 webpack index.js bundle.js 命令来生成文件,这种每次都要加参数的做法是程序员痛恨的,webpack 提供配置文件可以很容易的完成这项工作。在项目文件夹中新建 webpack.config.js 文件
module.exports = {
// 入口文件名称
entry: './index.js',
// 输出文件名称
output: {
filename: 'bundle.js'
}
}
然后在项目文件夹中运行
webpack
然后发现配置文件成功,文件生成成功啦!
4使用 Loader
本节代码可以参见 /codes/part3/
上面的例子帮我们了解了 webpack 最基本的工作方式,下面来介绍一下 webpack 的一个强大功能,在开始 Loader 之前,要先知道另外一个概念 module,上面已经说过了这个 module(模块),上面所说的就是 common.js 或者说是 ES2015格式的import/export 的模块,在 webpack 中这两种类型的文件是天生支持的,但是 webpack 可以引入的 module,远远不止这些,可以是一个样式文件(less/css/sass)或者是一个图片文件(jpg/png/webp等等)或者是 svg文件 还可能是 coffeescript/typescript 类型,你听到这里也许有点震惊,在js文件中引进一个样式文件?应该没有人会这样做吧,那好的,让我们来试试吧。
创建一个新文件 style.css
body {
background: yellow;
}
在 index.js 中直接引入这个文件
//index.js
import hello from './hello'
// 引入样式文件
import './style.css'
hello()
在这里我建议将 webpack 的依赖安装在本地的 package.json 里面。
npm install webpack --save-dev
然后运行 webpack 命令,发现出现了一行错误,看来我们还是太天真了。
ERROR in ./style.css
Module parse failed: /Users/vzhang/Public/webpack-for-fools/codes/part3/style.css Unexpected token (1:5)
You may need an appropriate loader to handle this file type.
| body {
| background:yellow;
| }
@ ./index.js 2:0-20
翻译过来的意思就是需要一个合适的loader来处理这个类型的文件(css文件)。webpack可以自动处理js类型的文件,但是css文件它不知道该如何处理,这里伟大的loader就出现了,其实通俗来说 loader 就是一系列的插件来处理不同类型的文件,并将它们成功的引入你的文件中。 Loaders describe to webpack how to process non-JavaScript modules and include these dependencies into your bundles.
在项目目录下运行,来安装处理css文件需要的两个Loader:
npm install style-loader css-loader --save-dev
添加完这两个loader之后,我们要教会 webpack 用什么Loader处理什么类型的文件。在 webpack.config.js 中修改:
module.exports = {
// 入口文件名称
entry: './index.js',
// 输出文件名称
output: {
filename: 'bundle.js'
},
// 这里是我们新添加的处理不同类型文件需要的 Loader
module: {
rules: [
{ test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' } ]}
]
}
}
仔细分析一下这一句语法:
{ test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' } ]}
前面 test 传入一个正则表达式,代表你要处理什么类型的文件,这里指的是后缀名为.css的文件,后面的 use 传入一个数组,代表着这个文件会被这两个loader所处理,一个文件可以被 多个loader 所处理:
Loaders can be chained. They are applied in a pipeline to the resource. A chain of loaders are compiled chronologically. The first loader in a chain of loaders returns a value to the next. At the end loader, webpack expects JavaScript to be returned.
读者也许会问处理 css 文件一个 css-loader 不就够了吗? 那么 style-loader 是做什么的?这里先卖一个小关子,之后会解释原因。
配置文件改好以后,运行 webpack 命令。这次没有报错,bundle.js 文件生成了,用浏览器打开 index.html ,发现页面的背景变成了黄色,loader 运行成功了!
本节最后再回到之前的问题,为什么需要两个 Loader ? 将 style-loader 删除掉以后,再次运行 webpack,发现并没有报错,说明 css 文件可以成功的解析并且处理,但是打开 index.html 发现 css 并没有生效。可以大胆猜测 style-loader 作用是将样式动态的使用 js 插入到页面中去,如果你看 index.html 源代码也发现我们并没有引入任何的样式文件,这正是 webpack 的特点之一,任何类型的模块(资源文件),理论上都可以通过被转化为 Javascript 代码实现与其他模块的合并与加载。
你可以在官方网站找到各种webpack 的 loaders 列表: Webpack Loader List
官方网站的图完美解释了Webpack在做什么:
二、gulp和webpack究竟有什么区别?
Gulp 的定位是 Task Runner, 就是用来跑一个一个任务的。
放在以前比如我想用sass写css, coffee写js, 我必须手动的用相应的compiler去编译各自的文件,然后各自minify。这时候designer给你了两张新图片,好嘞,接着用自己的小工具手动去压缩图片。后来前端人不能忍了,搞出个自动化这个流程的 Grunt/Gulp, 比如你写完代码后要想发布production版本,用一句 gulp build
就可以
-
rm
掉 dist文件夹中以前的旧文件 - 自动把sass编译成css, coffee编译成js
- 压缩各自的文件,压缩图片,生成图片sprite
- 拷贝minified/uglified 文件到 dist 文件夹
但是它没法解决的是 js module 的问题,是你写代码时候如何组织代码结构的问题.
之前大家可以用 require.js, sea.js 来 require dependency, 后来出了一个 webpack 说 我们能不能把所有的文件(css, image, js) 都用 js 来 生成依赖,最后生成一个bundle呢? 所以webpack 也叫做file bundler.同时 webpack 为了解决可以 require 不同文件的需求引入了loader, 比如面对sass文件有
- sass-loader, 把sass 转换成 css
- css-loader, 让 webpack 能识别处理 css
- style-loader, 把识别后的 css 插入到 html style中
- 类似的识别es6 有babel-loader
本来这就是 webpack 的初衷,require everything, bundle everything. 一开始 webpack 刚出来的时候大家都是把它结合着 gulp 一起用的, gulp 里面有个 gulp-webpack,就是让 webpack 专门去做module dependency的事情, 生成一个bundle.js文件,然后再用 gulp 去做一些其他杂七杂八minify, uglify的事情。 后来人们发现 webpack 有个plugins的选项, 可以用来进一步处理经过loader 生成的bundle.js,于是有人写了对应的插件, 所以minify/uglify, 生成hash的工作也可以转移到webpack本身了,挤掉了gulp这部分的市场份额。 再后来大家有发现 npm/package.json 里面的scripts 原来好好用啊,调用任务的时候就直接写一个简单的命令,因为 gulp 也不就是各种插件命令的组合呀,大部分情况下越来越不需要 gulp/grunt 之类的了 ref. 所以你现在看到的很多新项目都是package.json里面scripts 写了一堆,外部只需要一个webpack就够了。
打个不恰当的比方,webpack就像微信一样,本来就是做聊天(module dependency)的,后来生生搞出一个微信小程序(processing files),大家面对简单的需求发现这个比原生app方便使用啊,于是开发原生的人越来越少一样。
所以 LZ 一开始就模仿其他项目用 npm scripts + webpack 就好了,当你发现有哪些任务你没法用 webpack 或者npm scripts 解决起来麻烦, 这个时候再引入task runner 也不迟