Files
knowledge-kit/Chapter2 - Web FrontEnd/2.19.md
2020-02-25 17:46:51 +08:00

1080 lines
33 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# webpack 从入门到精通
## 小实验
我们一步步打包一个小项目看看 webpack 是如何工作的。
1. 先写一个 hello.js
```javascript
function hello(messgae){
alert(messgae);
}
```
2. 然后对其打包,发现终端报错。解决后知道在 webpack 2.0 的时候,我们打包一个 js 文件可能是这样的,比如将 hello.js 打包为 hello.bundle.js 。
```powershell
webpack hello.js hello.bundle.js
```
但是在现在 webpack 4.5.0 的时候就需要指定 mode 和输出路径
```powershell
webpack --mode=development hello.js --output-file hello.bundle.js
```
mode 有指定的3种值 development、production、none。区别在于 development 打包出来的东西是没压缩的、可读的production 打包出来的是压缩的、不可读的。
3. 然后编写一个 world.js 和 一个 style.css ,然后进行打包
```javascript
require('./world.js');
require('./style.css');
function hello(messgae){
alert(messgae);
}
hello("hello webpack");
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/WX20180802-095124@2x.png)
通过报错信息知道, webpack 对于 css 文件并不是默认支持的,需要指定相应的 loader 对其打包。
4. 所以我们继续安装 css-loader、style-loader。然后指定 css 文件的 loader 为 css-loader
```javascript
require('./world.js');
require('css-loader!./style.css');
function hello(messgae){
alert(messgae);
}
hello("hello webpack");
```
5. 接下来设置页面的背景颜色,发现网页并没有生效。这是因为 webpack 并不知道我们的样式如何作用到 html 中,所以我们需要指定 style-loader
```css
//style.css
body,html{
margin: 0;
padding: 0;
}
body{
font-size: 17px;
background: burlywood;
}
```
```javascript
//hello.js
require('./world.js');
require('style-loader!css-loader!./style.css');
function hello(messgae){
alert(messgae);
}
hello("hello webpack");
```
6. 查看网页效果。发现函数确实执行了,背景颜色也生效了,我们写的 css 代码新建了一个 **style标签** 被直接写入到 html 中了。
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/WX20180802-100727@2x.png)
7. 说说2个 loader 的作用。
* css-loader 就是 webpack 可以处理 css 文件。
* style-loader 的作用就是将 css-loader 处理完的文件新建一个 style 标签插入到 html 中
8. 很多人会想 **require\('style-loader!css-loader!./style.css'\);** 我每次写一个 css 文件,那么都需要在前面加入 **style-loader、css-loader** 吗显然不是webpack 还为我们提供了简单写法
```javascript
require('./world.js');
// require('style-loader!css-loader!./style.css');
require('./style.css');
function hello(messgae){
alert(messgae);
}
hello("hello webpack");
```
webpack-cli 写法为
```powershell
webpack --mode=development hello.js --output-file hello.bundle.js --module-bind 'css=style-loader!css-loader'
```
9. 之前的做法还存在一个弊端,就是每次修改了代码,我们都需要在终端重新运行打包命令,十分繁琐。这里强大的 webpack 为我们提供了一个 option可以监听代码改变然后自动打包。如下
```powershell
webpack --mode=development hello.js --output-file hello.bundle.js --module-bind 'css=style-loader!css-loader' --watch
```
这样我们在源代码每次一修改webpack 会自动打包
10. 如果你想看到打包过程,那么可以使用 **pregress** 参数。这样在打包的时候可以看到左下角有构件的进度
```powershell
webpack --mode=development hello.js --output-file hello.bundle.js --module-bind 'css=style-loader!css-loader' --progress
```
11. 如果像看到打包的模块,可以使用 **--display-modules**
```powershell
webpack --mode=development hello.js --output-file hello.bundle.js --module-bind 'css=style-loader!css-loader' --progress --display-modules
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/WX20180802-103343@2x.png)
12. 如果想知道打包某个模块的原因,可以使用 **--display-reasons**
```powershell
webpack --mode=development hello.js --output-file hello.bundle.js --module-bind 'css=style-loader!css-loader' --progress --display-modules --display-reasons
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/WX20180802-103717@2x.png)
## 用 webpack.config.js 完成上述步骤
1. 初始化项目,编辑 webpack.config.js
```powershell
var path = require('path');
module.exports = {
entry: './src/script/main.js',
output:{
path: path.resolve(__dirname,'./dist/js'),
filename: 'bundle.js'
}
}
```
2. 有了 webpack.config.js 文件,就不需要和上面的方式一样,指定对应的 configuration option。在终端运行 **webpack --mode=development **
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QQ20180802-110653@2x.png)
3. 注意:如果我们将 webpack.config.js 改名为 webpack.dev.config.js ,然后在命令行打包,会发现没效果。
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QQ20180802-110938@2x.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QQ20180802-111011@2x.png)
要将 webpack.dev.config.js 同样生效,我们需要在命令行使用下面命令。
```powershell
webpack --mode=development --config webpack.dev.config.js
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QQ20180802-111143@2x.png)
4. 如果想像上个实验一样,看到打包时候的一些信息,怎么办呢?
可以配合 npm 的 package.json 文件中的 scripts 标签,在下面添加 key 为 webpack 的项,然后将命令写到后边。然后在命令行运行 **npm run webpack**
```
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack --config webpack.config.js --mode=development --progress --display-modules --display-reasons --colors"
},
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QQ20180802-113022@2x.png)
5. 对于 webpack 的 entrt 主要有3种写法每种写法都有不同区别。
* 如果 webpack 只有单一入口,那么就可以是字符串。
```json
entry: './src/script/main.js',
```
* 如果 webpack 有多个入口,那么就可以是数组。
```json
entry: ['./src/script/main.js','./src/script/a.js'],
```
* 如果 webpack 有多个入口,那么可以用对象。
```json
entry: {
main: './src/script/main.js',
a : './src/script/a.js'
},
```
6. 如果指定了多个入口,那么执行打包会报错,因为 webpack 文档说如果多个 entry且只有一个 output 的 filename那么打包的结果会覆盖。所以我们需要设置如下
> When combining with the [`output.library`](https://webpack.js.org/configuration/output#output-library) option: If an array is passed only the last item is exported.
```json
var path = require('path');
module.exports = {
entry: {
main: './src/script/main.js',
a : './src/script/a.js'
},
output:{
path: path.resolve(__dirname,'./dist/js'),
filename: '[name]-[hash].js'
}
}
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QQ20180802-120033@2x.png)
将文件修改为 **filename: '\[name\]-\[chunkhash\].js'**
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QQ20180802-120113@2x.png)
会发现 hash 和 chunkhash 的输出的文件名并不一样
说明: chunkhash 是根据文件的内容生成的唯一标示类似于md5生成的唯一标示、文件版本号。如果一个资源在打包前后文本没有变过的话二次打包的生成的 chunkhash 是一致的。
## 生成项目中 html 页面文件
对于生成的的 js我们 html 如何使用呢难道每次一打包html 中的 script 需要修改 src 吗不是的webpack 提供了 html-webpack-plugin
1. 安装
```powershell
npm install html-webpack-plugin --save-dev
```
2. 然后运行命令,将现有的 js 打包引入到 html 文件中
```json
var htmlWebpackPlugin = require('html-webpack-plugin');
//...
plugins: [
new htmlWebpackPlugin()
]
```
然后生成的文件是 webpack 帮我们生成的 html 文件。当然我们可以新建一个自己的 html 作为模版。
```json
plugins: [
new htmlWebpackPlugin({
template: 'index.html'
})
]
```
```html
//模版
<html>
<head>
<titile>webpack demo</titile>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
</body>
<script type="text/javascript" src="./dist/js/bundle.js" ></script>
</html>
//打包生成的
<html>
<head>
<titile>webpack demo</titile>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<script type="text/javascript" src="main-4166ec84d15023f1cd10.js"></script><script type="text/javascript" src="a-c13b6c7a7bfe7bd0293e.js"></script></body>
<script type="text/javascript" src="./dist/js/bundle.js" ></script>
</html>
```
说明:上面选中的 template 写了 index.html 就会找到合适的文件是因为 webpack 有个上下文参数 context会根据上下文找到对应的 html这里就是根目录
3. 上述的缺点是生成的 html 也会放在 dist/js 目录下。
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/WX20180802-151750@2x.png)
需要做到的效果就是 html 放在根目录, js 放在 dist 目录下的 js 目录下。需要对 webpack.config.js 的 output 属性做修改
4. ```js
output:{
path: path.resolve(__dirname,'./dist'),
filename: 'js/[name]-[chunkhash].js'
},
```
5. plugins 的参数很多可以自定义
```json
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'index-[hash].html',
inject: 'head'
})
]
```
* template: 指定生成 html 的模版
* filename指定生成 html 的命名规则
* inject :指定生成 js 的 script 插入的位置。head、body
6. 如果想通过 plugins 传值到 生成的 html怎么办
* htmlWebpackPlugin.options 对象就可以拿到传递过来的值
* &lt;%= htmlWebpackPlugin.options.title %&gt; 模版语法来拿值
```json
//webpack.config.js
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'index.html',
inject: 'head',
title: 'Webpack is awesome',
date : new Date()
})
]
```
```html
// 模版 html
<html>
<head>
<titile><%= htmlWebpackPlugin.options.title %></titile>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<h3>时间:<%= htmlWebpackPlugin.options.date %></h3>
</body>
</html>
//生成的html
<html>
<head>
<titile>Webpack is awesome</titile>
<script type="text/javascript" src="js/main-82c7521f0a4a776cc00b.js"></script><script type="text/javascript" src="js/a-273641522fd044fc27c7.js"></script></head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<h3>时间Thu Aug 02 2018 15:40:50 GMT+0800 (CST)</h3>
</body>
</html>
```
7. 我们很好奇 html-webpack-plugin 可以传递什么参数?或者这个对象包含什么信息。做个测试就知道了
```html
//模版 html
<% for (var key in htmlWebpackPlugin){ %>
<%= key %>
<% } %>
//生成的 html
files
options
```
看到最外层的节点就2个files、options。那么我们分别对这2个节点遍历输出。因为遍历出的 value **htmlWebpackPlugin.files\[key\] **)可能是对象、数组。所以用 **JSON.Stringfy\(htmlWebpackPlugin.files\[key\]\)** 打印
```html
<html>
<head>
<titile><%= htmlWebpackPlugin.options.title %></titile>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<h3>时间:<%= htmlWebpackPlugin.options.date %></h3>
<% for (var key in htmlWebpackPlugin.files){ %>
<%= key %> <%= JSON.stringify(htmlWebpackPlugin.files[key]) %>
<% } %>
<hr>
<% for (var key in htmlWebpackPlugin.options){ %>
<%= key %> <%= JSON.stringify(htmlWebpackPlugin.options[key]) %>
<% } %>
</body>
</html>
//生成的 html
<html>
<head>
<titile>Webpack is awesome</titile>
<script type="text/javascript" src="js/main-82c7521f0a4a776cc00b.js"></script><script type="text/javascript" src="js/a-273641522fd044fc27c7.js"></script></head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<h3>时间Thu Aug 02 2018 15:51:27 GMT+0800 (CST)</h3>
publicPath ""
chunks {"main":{"size":28,"entry":"js/main-82c7521f0a4a776cc00b.js","hash":"82c7521f0a4a776cc00b","css":[]},"a":{"size":18,"entry":"js/a-273641522fd044fc27c7.js","hash":"273641522fd044fc27c7","css":[]} }
js ["js/main-82c7521f0a4a776cc00b.js","js/a-273641522fd044fc27c7.js"]
css []
manifest
<hr>
template "/Users/liubinpeng/Desktop/webpackdemo/Demo2/node_modules/html-webpack-plugin/lib/loader.js!/Users/liubinpeng/Desktop/webpackdemo/Demo2/index.html"
templateParameters
filename "index.html"
hash false
inject "head"
compile true
favicon false
minify false
cache true
showErrors true
chunks "all"
excludeChunks []
chunksSortMode "auto"
meta {}
title "Webpack is awesome"
xhtml false
date "2018-08-02T07:51:27.110Z"
</body>
</html>
```
8. 有时候我们想把部分 js 放到 head ,部分 js 放到 body 中。单独通过 webpack.config.js 是没办法实现这个目的,结合上面的成果,我们可以拿到 **htmlWebpackPlugin.files.chunks** 属性,比如将 a.js 放到 head 标签main.js 放到 body 标签。
```json
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'index.html',
inject: false,
title: 'Webpack is awesome',
date : new Date()
})
]
```
```html
//模版 html
<html>
<head>
<titile><%= htmlWebpackPlugin.options.title %></titile>
<script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks.a.entry %>"></script>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<h3>时间:<%= htmlWebpackPlugin.options.date %></h3>
<script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks.a.entry %>"></script>
</body>
</html>
```
```html
//生成 html
<html>
<head>
<titile>Webpack is awesome</titile>
<script type="text/javascript" src="js/a-273641522fd044fc27c7.js"></script>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<h3>时间Thu Aug 02 2018 15:58:56 GMT+0800 (CST)</h3>
<script type="text/javascript" src="js/a-273641522fd044fc27c7.js"></script>
</body>
</html>
```
需要注意的是当自定义 js 文件的位置的时候,需要将 webpack.config.js 中 plugins 下的 inject 设置为 false
9. 接下来看到的这种需求绝对很有料。前面我们看到的都是相对路径,但是我们的产品需要上线,所以我们的 js 文件资源路径需要改变。如下:
```json
//webpack.config.js
output:{
path: path.resolve(__dirname,'./dist'),
filename: 'js/[name]-[chunkhash].js',
publicPath: 'http://test.lbp.com'
},
```
```html
//生成的 html
<html>
<head>
<titile>Webpack is awesome</titile>
<script type="text/javascript" src="http://test.lbp.com/js/a-502c14d352874172253c.js"></script>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<h3>时间Thu Aug 02 2018 16:25:12 GMT+0800 (CST)</h3>
<script type="text/javascript" src="http://test.lbp.com/js/a-502c14d352874172253c.js"></script>
</body>
</html>
```
10. 利用 webpack 我们还可以打包好的 html 做一些优化,比如删除注释、去掉空格.
修改 webpack.config.js 中 plugins 节点下的 htmlWebpackPlugin 的 minify 属性
```json
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'index.html',
inject: false,
title: 'Webpack is awesome',
date : new Date(),
minify:{
removeComments: true,
collapseWhitespace: true
}
})
],
```
我们对 模版 html 写一些注释,运行 npm run webpack 后看到生成的页面中注释、空格都被去掉了。
11. 如果想打包生成多个 html 怎么办?可能使用 plugins 下的 new htmlWebpackPlugin\(\) 多来几组配置项
```json
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'a.html',
title: 'this is a.html',
chunks: ['main','a'],
inject: 'body'
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'b.html',
title: 'this is b.html',
chunks: ['main','b'],
inject: 'body'
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'c.html',
title: 'this is c.html',
chunks: ['main','c'],
inject: 'body'
})
]
```
注意:这里我们可以指定每个生成的 filename 以及 title。实现上述需求关键点在于 **chunks** 这个属性。用一个数组的形式来指定需要引用的 chunk。
12. 上面只是实现了 a、b、c 3个页面如果多了的话按照上面的写法要烦死人的。 webpack 为我们提供了 **excludeChunks** 这个属性它指定了不需要包含的chunk。上面写法的另一种写法
```json
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'a.html',
title: 'this is a.html',
// chunks: ['main','a'],
inject: 'body',
excludeChunks: ['b','c']
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'b.html',
title: 'this is b.html',
//chunks: ['main','b'],
inject: 'body',
excludeChunks: ['a','c']
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'c.html',
title: 'this is c.html',
// chunks: ['main','c'],
inject: 'body',
excludeChunks: ['a','b']
})
],
```
13. 有种需求是:当我们需要减小首页 HTTP 请求(提高首页的渲染速度),也就是将一些首页必须用到的 JS 文件用内联的方式写在首页 html 的 script 标签里面,不重要的 js 文件通过 script 的 src 引入。要怎么做呢webpack 在设计之初没想到这种需求,很多人在 github 提了很多 issue ,官方认识到这种需求,所以在后期更新的 demo 中看到了解决方案。
* htmlWebpackPlugin.files.chunks 对象拿到的是我们在 webpack.config.js 设置过 publicPath 生成的完整路径
* 通过截取字符串子串的方式拿到文件地址。 **htmlWebpackPlugin.files.chunks.main.entry.substr\(htmlWebpackPlugin.files.publicPath.length\) **
* [官方的解决方案](https://github.com/jantimon/html-webpack-plugin/blob/master/examples/inline/template.jade)
```jade
compilation.assets[jsFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()
```
在我们的项目中加以改造,为生成的每个页面的 header 里面加入 main.js。在 body 部分加入除了 main.js 之外的其他 js。
```html
//模版html
<html>
<head>
<title><%= htmlWebpackPlugin.options.title %></title>
<script type="text/javascript">
<%= compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
</script>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<% for(var key in htmlWebpackPlugin.files.chunks){ %>
<% if( key !== 'main'){ %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks[key].entry %>"></script>
<% } %>
<% } %>
</body>
</html>
```
```js
//webpack.config.js
var htmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
// entry: './src/script/main.js',
// entry: ['./src/script/main.js','./src/script/a.js'],
entry: {
main: './src/script/main.js',
a : './src/script/a.js',
b : './src/script/b.js',
c : './src/script/c.js'
},
output:{
path: path.resolve(__dirname,'./dist'),
filename: 'js/[name]-[hash].js',
publicPath: 'http://test.lbp.com'
},
plugins: [
new htmlWebpackPlugin({
template: 'index.html',
filename: 'a.html',
title: 'this is a.html',
inject: false,
excludeChunks: ['b','c']
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'b.html',
title: 'this is b.html',
inject: false,
excludeChunks: ['a','c']
}),
new htmlWebpackPlugin({
template: 'index.html',
filename: 'c.html',
title: 'this is c.html',
inject: false,
excludeChunks: ['a','b']
})
],
}
```
为了验证生效,我将 main.js 加入了 alert
```js
//main.js
function helloworld(msg){
alert(msg);
}
helloworld("hello webpack");
```
看看打包后生成的 a.html
```html
<html>
<head>
<title>this is a.html</title>
<script type="text/javascript">
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "http://test.lbp.com";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./src/script/main.js");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./src/script/main.js":
/*!****************************!*\
!*** ./src/script/main.js ***!
\****************************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("function helloworld(msg){\n alert(msg);\n}\n\n\nhelloworld(\"hello webpack\");\n\n//# sourceURL=webpack:///./src/script/main.js?");
/***/ })
/******/ });
</script>
</head>
<body>
<h2>我是 webpack 生成 html 的模版</h2>
<script type="text/javascript" src="http://test.lbp.com/js/a-4caa8a542ab497f63bf8.js"></script>
</body>
</html>
```
在浏览器调试后发现页面是可以正常弹出“hello webpack”
## loader
新建项目,一步步认识 loader
1. Js loader
我们写的项目中会用 es6但是并不是所有的浏览器都支持 es6虽然各个浏览器厂商每年在不断新增对 es6 的支持),所以我们需要使用 babel 将 es6 转换为浏览器都支持的 es2015 。所以使用 babel-loader 的时候需要指定 babel 转换的模式。loader 官方给出了2种方式
* 可以直接像 url 的 get 形式一样,将参数传递在后面。
```js
//方式1
require("babel-loader?presets=latest");
//方式2
{
test: /\.png$/,
loader: 'url-loader?presets=latest'
}
```
* 写在 query 参数里面
```js
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['latest']
}
}
```
* 其实还有一种方式:在 package.json 文件里面添加一个 key 为 babel。
```json
"babel": {
presets: ['latest']
}
```
注意webpack 现在已经是4.5.0了。以前的版本的写法是
```js
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['latest']
}
}
]
},
```
现在的写法为
```js
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
presets: ['latest']
}
}
]
},
```
注意我们工程如果安装的依赖非常多node\_modules 文件非常多babel 转换会很慢这时候需要指定2个参数可以显著提高速度
```js
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
presets: ['latest']
},
exclude: path.resolve(__dirname,'./node_modules/'),
include: path.resolve(__dirname,'./src')
}
]
},
```
2. css loader
打包 css 经常会用到 css-loader、style-loader。我们经常写 flex 的时候很多浏览器兼容性不一致,所以我们需要加前缀,这时候需要使用 postcss-loader、autoprefixer
官网给出2种写法
* loader
```js
{
test: /\.css$/,
loader: 'style-loader!css-loader!postcss-loader'
}
```
* loaders
```js
{
test: /\.css$/,
loaders: ['style-loader','css-loader','postcss-loader']
}
```
如果项目中不只是使用了 css 的话,比如还使用了 less 和 sass 的话,我们需要将 css 加额外的设置
```js
{
test: /\.css$/,
use:[
'style-loader',
{loader: 'css-loader', options: {importLoaders: 1} },
{
loader: 'postcss-loader',
options:{
plugins:function(){
return [
require('postcss-import')(),
require('autoprefixer')({browsers:['last 5 versions']})
]
}
}
}
]
},
{
test: /\.less$/,
use:[
'style-loader',
{loader: 'css-loader', options: {importLoaders: 1} },
{
loader: 'postcss-loader',
options:{
plugins:function(){
return [
require('postcss-import')(),
require('autoprefixer')({browsers:['last 5 versions']})
]
}
}
},
'less-loader'
]
},
```
3. 处理模版
在 webpack 经常打包处理的时候会遇到模版。有普通的 html 模版,也会有 ejs 模式下的 tpl 模版
- html 模版
```html
<html>
<head>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app">
</div>
</body>
</html>
```
```js
//layer.js
import './layer.less'
import tpl from './layer.html'
function layer(){
return {
name: 'layer',
tpl: tpl
}
}
export default layer;
//app.js
import Layer from './components/layer/layer.js';
import './css/common.css';
const App = function(){
var dom = document.getElementById("app");
var layer = new Layer();
dom.innerHTML = layer.tpl;
}
new App()
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/WX20180803-152208@2x.png)
- ejs 模版
```js
//layer.tpl
<div class="layer">
<div>this is <%= name %> layr</div>
<% for(var i=0;i < arr.length; i++){ %>
<%= arr[i] %>
<% } %>
</div>
//layer.js
import './layer.less'
import tpl from './layer.tpl'
function layer(){
return {
name: 'layer',
tpl: tpl
}
}
export default layer;
//app.js
import Layer from './components/layer/layer.js';
import './css/common.css';
const App = function(){
var dom = document.getElementById("app");
var layer = new Layer();
dom.innerHTML = layer.tpl({
name: 'john',
arr: ['swift','Objective-C','JS','python']
});
}
new App()
```
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/WX20180803-152612@2x.png)