WebGIS开发教程(六) 再识 Webpack

0
分享 2018-05-08
作者:liuyl
关于作者:GIS从业者,主要在ArcGIS平台下做WebGIS开发,最后有作者的联系方式
版权所有:转载请保留作者名和原始链接
这是一个系列教程,内容有一定连续性,可移步 目录篇 查看所有教程
教程示例代码下载

一点前言

本篇教程将在 上一篇 WebGIS开发教程(五) 初识 Webpack 基础上,在 webpack 配置中增加对 CSS 样式的编译。我们还会尝试一下用 Sass 来写 CSS 样式。

下面是正文


准备试验代码

我们先准备好用于试验的示例代码,代码以上一篇中最后的结果的为基础增加一些标签,并新建一个 CSS 文件,还会引用一个图片文件。
目录文件组织结构如下
目录文件组织结构
bootstrap.html
文件中代码如下
<!DOCTYPE html>
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>2_Webpack/2_Second</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="https://cdn.bootcss.com/bootst ... gt%3B
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
</head>
<body>
<!-- Add your site or application content here -->
<div style="margin-top: 50px" class="container">
<div class="jumbotron">
<h1>Hello World</h1>
<p>这是WebGIS开发教程的示例页面</p>
<button id="my-btn" class="btn btn-primary btn-lg">点击</button>
<div class="author">
<a class="logo" href="https://www.jianshu.com/p/e9d23726063a" target="_blank"></a>
<div class="info">
<span class="name">
<a href="https://www.jianshu.com/p/e9d23726063a" target="_blank">
教程目录篇
</a>
</span>
<div class="meta"><span>请点击前往本系列教程的目录篇</span>





<script src="https://cdn.bootcss.com/jquery ... gt%3B
<script src="https://cdn.bootcss.com/bootst ... gt%3B

<script src="dist/app.js"></script>
</body>
</html>

可以看到代码中主要的变化是引用了css/main.css文件,并增加了一组用于跳转到教程目录篇的html标签。其中引用的css类均在css/main.css
文件之中,文件中的样式定义如下
.app {
margin-top: 50px;
}

.author {
margin: 30px 0 40px;
}

.author .logo {
width: 48px;
height: 48px;
vertical-align: middle;
display: inline-block;
background-image: url(../img/logo.png);
background-size: contain;
}

.author .info {
vertical-align: middle;
display: inline-block;
margin-left: 8px;
}

.author .info .name {
margin-right: 3px;
font-size: 16px;
vertical-align: middle;
}

.author .info .meta {
margin-top: 5px;
font-size: 12px;
color: #969696;
}



此外增加了一个图片文件img/logo.png,被当作背景图片引用webpack.config.js文件和上一篇最后一样,没有变化
const path = require('path')
module.exports = {
entry: {
app: [path.resolve(__dirname, 'js/main.js')],
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
},
}

在命令行窗口执行如下命令
webpack --config lesson\2_Webpack\2_Second\webpack.config.js

启动 nginx,浏览器访问http://localhost/lesson/2_Webpack/2_Second/bootstrap.html,我们将看到如下页面
教程示例页面效果
如果读者对以上过程感到困惑,请回顾一下系列教程的前面几篇。下面来进入本篇教程的正题

用 webpack 打包 CSS 样式
一切皆模块

webpack 有一个不可不说的优点,它把所有的文件都都当做模块处理
JS,CSS 和 FONTS 以及图片等等通过合适的 loader 都可以被处理

webpack 提供两个工具处理样式表, css-loader 和 style-loader
二者处理的任务不同, css-loader 使你能够使用类似 @import 和 url(...) 的方法实现 require() 的功能
style-loader 将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入 webpack 打包后的 js 文件中。



上面这段描述引用自 入门Webpack,看这篇就够了 ,更深入的也不好描述了,读者在使用 webpack 过程中慢慢理解就好
现在我们来更改 webpack 配置,增加 module 配置段,这个配置段与之前的entryoutput配置段是同级的
module: {
rules: [{
test: /\.css$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}],
}, {
test: /\.(png|gif|jpg)$/,
use: [{
loader: "url-loader",
options: {
limit: 10000
},
}],
}]
}

然后将对css/main.css的引用从bootstrap.html文件中注释掉
<!--<link rel="stylesheet" href="css/main.css">-->

并用import语句在js/main.js文件中引用css/main.css文件
import './plugins'                           //本行为文件中已有代码
import { message }from './msg' //本行为文件中已有代码
import '../css/main.css'



在执行 webpack 命令之前,我们还需要安装这段配置中涉及到的 loader ,在教程示例代码根目录执行下面的命令
npm install --save-dev style-loader css-loader url-loader file-loader



然后重新编译,执行
webpack --config lesson\2_Webpack\2_Second\webpack.config.js
命令。刷新页面,这时页面效果应该和之前没有区别,说明 CSS 样式已经被打包到了dist/app.js文件中了

看看发生了什么

我们先看一下样式是怎么生效的,通过浏览器的调试工具查看 DOM 树,<head>标签最后面多了一段<style>标签,查看里面的样式,正是我们定义在css/main.css文件中的样式
被注入的样式
下面就在 webpack 编译生成的dist/app.js文件中查找线索,揭开这段 css 样式是如何被加到<head>标签中的
首先,由这句
return __webpack_require__(__webpack_require__.s = 0);
知道入口模块仍然0号模块,0号模块直接返回1号模块,1号模块就是我们的js/main.js文件对照文件中
import './plugins'
import { message }from './msg'
import '../css/main.css'

被编译成
var __WEBPACK_IMPORTED_MODULE_0__plugins__ = __webpack_require__(2); 
var __WEBPACK_IMPORTED_MODULE_0__plugins___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__plugins__);
var __WEBPACK_IMPORTED_MODULE_1__msg__ = __webpack_require__(3);
var __WEBPACK_IMPORTED_MODULE_2__css_main_css__ = __webpack_require__(4);
var __WEBPACK_IMPORTED_MODULE_2__css_main_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2__css_main_css__);

var __WEBPACK_IMPORTED_MODULE_2__css_main_css__ = __webpack_require__(4);
这句得知对css/main.css文件中定义的样式的引用是在4号模块中开始执行的,4号模块第一句如下
var content = __webpack_require__(5);
引入了5号模块,这个模块又做了什么呢
var escape = __webpack_require__(6);
exports = module.exports = __webpack_require__(7)(false);
// module
exports.push([module.i, ".app {\r\n margin-top: 50px;\r\n}\r\n\r\n.author {\r\n ... ]);

发现了css/main.css文件中定义的样式!只是被转换成了字符串,然后通过exports返回给了4号模块
回去看4号模块, 在var content = __webpack_require__(5);
这一句后面不远处有下面这句
var update = __webpack_require__(9)(content, options);

5号模块中拿到的样式字符串通过变量content传入了9号模块定义的函数中9号模块是style-loader
生成的向页面中动态插入样式的一组功能函数,在执行了
addStylesToDom(styles, options);
这一句之后,样式被插入到<head>标签的最后面。具体函数如何执行就不详细看了,有兴趣的读者可以自己调试看看

那个 logo.png 图片怎么了

细心的读者可能在上面浏览器调试工具的截图中发现,.author .logobackground-image
后面的url和我们在文件中定义的不一样了,变成了很长的一串乱码
变成乱码的 url
这就是 webpack 配置中,下面这段的作用了
{
test: /\.(png|gif|jpg)$/,
use: [{
loader: "url-loader",
options: {
limit: 20000
},
}],
}
这段告诉 webpack 在编译过程中,遇到样式中用url()引用的本地图片,如果大小没有超过limit:20000定义的 20000B ,就将图片转为base64编码,并直接输出到打包后的js文件中。这样可以有效减少页面因频繁网络请求小图片导致的额外开销。我们在8号模块中可以找到图片被转换后的base64编码module.exports = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGA ...
5
号模块样式字符串中可以看到对8号模块的引用
background-image: url(" + escape(__webpack_require__(8)) + ");
如果我们将limit:20000改为limit:10000重新编译,图片文件因为大小超过了 10000B ,就不会被转码了,而是会被复制到dist目录里,同时文件名也会被改为一个 Hash 码。
这个工作是url-loader调用file-loader完成的,所以如果前面没有安装file-loader,在这里编译就会报错。
我想大家能够猜到这种情况下编译出的代码是什么样的,感兴趣的话可以去看一下。

用 Sass 写样式
Sass的学名叫“CSS预处理器”,就是在CSS的基础上,
引入了变量、嵌套、mixin(混合)、运算以及函数等功能,
增加了代码的灵活性,可以让我们以更少的代码实现同样的效果,
而且代码的整洁度、可读性更强。
以上引用自 Sass 简单入门、快速上手
Sass的介绍我就不自己编了,下面直接说怎么做在css目录中新建一个名为main.scss
的文件,然后文件中输入如下代码
.app {
margin-top: 50px;
}

@mixin vertical-align-inline-block {
vertical-align: middle;
display: inline-block;
}

.author {
margin: 30px 0 40px;
.logo {
width: 48px;
height: 48px;
@include vertical-align-inline-block;
background-image: url(../img/logo.png);
background-size: contain;
}
.info {
@include vertical-align-inline-block;
margin-left: 8px;
.name {
margin-right: 3px;
font-size: 16px;
vertical-align: middle;
}
.meta {
margin-top: 5px;
font-size: 12px;
color: #969696;
}
}
}
这段样式就是用Sass语法编写的一段样式,和main.css文件中的样式效果完全相同。这段样式可能并不适合用来展示用Sass编写样式的益处,但我还是希望这种嵌套写法和我强行放入的mixin可以引起读者的注意。
大家可以简要浏览一下 Sass 中文网--快速入门 了解一下Sass的各种特性和语法。本系列教材后续都将使用Sass来编写样式文件。scss文件需要配置sass-loader才能在 webpack 中被打包编译在 webpack 的配置中, 在module配置段 的rules项的数组里加入如下配置
{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader"
}]
}
js/main.js文件中对css/main.css文件的引用更改为css/main.scss
// import '../css/main.css'
import '../css/main.scss'
npm安装node-sasssass-loader,这里注意一下,使用npm安装node-sass有很大的概率会因为网络问题导致安装失败,可以尝试使用cnpm进行安装。在教程示例代码根目录执行下面的命令
npm install sass-loader node-sass webpack --save-dev
重新进行 webpack 编译,刷新页面,页面效果应该与之前完全一致

这里是结尾

上一篇教程我们一起详细分析了 webpack 对 JS 文件的打包,这篇则主要针对 CSS 样式。这两部分也是 webpack 打包编译中最核心的部分,这两篇教程一起带大家从最基础的层面上来理解 webpack。
本篇中使用了很多个loader,与loader有关的配置是 webpack 配置中占比相对较大的部分,后续我们还会接触到一些其他loader。每个loader
其实都有一系列参数可以选用和配置,在对应项目的 github 主页会有介绍,了解一下有哪些参数还是很有必要的。
下一篇中我们将尝试使用一下HtmlWebpackPlugin这个插件,并学习使用 Gulp 来接管 Webpack。

本教程是一个系列教程,可以到目录章查看所有教程



联系作者
  • 简书主页 请优先关注我的简书账号,并在简书对应文章下留言,有APP通知推送所以能及时看到,简书也是我的文章首发平台
  • Github主页 教程和相关代码在我的Github里都能够找到
  • ArcGIS知乎主页 文章会被同步到ArcGIS知乎中,ArcGIS知乎是面向广大GISer的知识分享和问答平台,推荐大家经常去看看
  • 微信公众号 搜索 幻想GIS 或扫描二维码,文章会通过公众号进行推送
    请扫码关注微信公众号 幻想GIS
  • QQMail liuyl89@qq.com
  • GMail liuyl.gisuni@gmail.com 不太稳定,建议邮件后在简书里留言告诉我一下


文章来源:http://www.jianshu.com/p/a5a9fab73dda

0 个评论

要回复文章请先登录注册