Webpack自动化工程

近几年,前端各种框架工具层出不穷,从两三年前还是一个jQuery搞定全站,到之后 requirejs/seajsnodegulp/webpackAngular/React/VueRN/weex的不断涌现,完全颠覆了原来的前端开发模式。

那么这些框架和工具给我们到底带来了什么好处呢?其实我认为最核心莫过于这两点:模块化开发自动化工程。而本次前端重构所围绕的核心问题就是自动化工程,将原有的 gulp版本的项目利用webpack彻底改造,顺利消灭了既繁琐又易错的人工操作。

gulp 版本的痛点

我们先来看下奇货商城之前的开发流程:

从上图可以看出,我们奇货前端开发之前存在的一些痛点:

  1. 前端在后端项目里面修改 vm文件联调;

  2. 开发联调需要上传静态资源到测试域名 CDN

  3. 不同目录下的资源还需要在 CDN上传网站上一级一级目录的点开再上传;

  4. 上线前需要人工去替换 vm 文件里的 CDN路径;

  5. 上线前还需要人工去上传静态资源到正式域名 CDN

  6. 开发模式不支持 es6 转义,导致低端安卓机无法在本地进行前端调试;

  7. gulp-babel不完全支持es6es5,导致部分低端安卓机出现各种莫名其妙的问题;

以上这些痛点,造成的重复性无用功,既浪费精力又着实让人蛋疼,而经过这次的框架重构,只需一键操作,就可完成联调和发布的部署。省心省力还不会出错。

如何利用 webpack 做自动化

先看一下改版后,奇货商城的开发流程:


从上图可以看到,我们经过改版后做到了:

  1. **vm **文件自动生成

  2. 开发联调直接读取本地静态资源

  3. 打包后所有资源在同一级目录,一次性拖拽上传(下个版本将实现前静态资源自动上传)

  4. 只需一行配置项,自动生成对应的线上 **CDN **路径

  5. 完美的 babel-loader,**es6 **语法也可在低端安卓机上轻松本地调试;

下面我们看看如何实现。

项目结构

下面是部分主要目录结构:

├── build   (所有的webpack配置项)
│   ├── build.js
│   ├── dev-client.js
│   ├── dev-server.js
│   ├── utils.js    (★入口配置,生成文件配置,vm生成都靠这个文件)
│   ├── webpack.base.conf.js    (基础配置)
│   ├── webpack.dev.conf.js     (开发模式配置)
│   └── webpack.prod.conf.js    (生成环境配置)
├── config  (node环境变量,入口文件的配置)
│   ├── dev.env.js
│   ├── entry.js    (页面文件列表)
│   ├── index.js    (★主配置文件)
│   ├── prod.env.js
│   └── skinEntry.js    (皮肤文件列表)
├── dist    (打包后生成的文件夹,已全部转成vm)
│   ├── goods
│   │   ├── detail.vm
│   ├── index.vm
│   └── static  (打包后-静态资源文件)
│       ├── css
│       ├── js
│       └── skins   (打包后皮肤文件夹)
│           ├── default
│           │   ├── default.1184b4d7.js
│           │   ├── default.f07ae9df.css
│           │   └── default.html
│           ├── huotu
│           └── pay
├── mock
├── package.json
├── routes
├── src (源文件)
│   ├── js
│   │   ├── components
│   │   ├── goods
│   │   │   ├── detail.js
│   │   │   └── skins
│   │   │       ├── default.js
│   │   │       ├── huotu.js
│   │   ├── index.js
│   ├── less
│   │   ├── components
│   │   ├── goods
│   │   │   ├── detail.less
│   │   │   └── skins
│   │   │       ├── default.less
│   │   │       ├── huotu.less
│       ├── index.less
│   └── pages
│       ├── components
│       ├── goods
│       │   ├── detail.html
│       │   └── skins
│       │       ├── default.html
│       │       ├── huotu.html
│       └── index.html
├── static
│   └── images
└── unit    (公共库)
    ├── common  (业务组件)
    │   ├── js
    │   └── less
    ├── layout  (公共页面)
    │   ├── footer.html
    │   └── header.html
    └── lib     (第三方组件)

以上是我们奇商城的前端目录结构。

webpack的一些必用的loaderplugin

例如

less-loader, style-loader, file-loader, html-loader, 还有UglifyJsPlugin, ExtractTextPlugin, OptimizeCSSPlugin

等等,在这里就不详细展开了。

我们重点说说以下几点核心:

node 脚本调用 webpack

通过node脚本来调用webpack,而不是直接在命令行启动webpack,会有这么几个用处:

  • 通过nodeexpress做本地mock数据;

  • 开发环境和生产环境的公共配置项,通过webpack-merge模块做抽离,方便维护;

  • 可以设置node环境变量,以区分不同环境中的打包配置,这点在后面还有一个大招;这货可以说是整个构建过程里,核心中的核心了。

自动生成 vm、开发环境调用本地资源,以及皮肤文件的管理都有这个插件的功。部分代码:

new HtmlWebpackPlugin({
  filename: process.env.NODE_ENV === 'production' ? path + name + '.vm' : path + name + '.html',
  template: template,
  inject: false,
  chunks: [pathBuild + name, 'vendor', 'manifest']
})

通过判断node环境变量,决定生成vm还是本地html;通过这个插件实现了 js 模块打包,公共模块提取,客户端缓存&增量发布,皮肤文件生成。部分代码:

for (let i = 0; i < entry.length; i++) {
  let item = entry[i]
  let path = item.path
  let name = item.name
  let pathBuild = path.replace(/\//g, '-');
  result[pathBuild + name] = './src/js/' + path + name + '.js'
}

for (let i = 0; i < skinEntry.length; i++) {
  let item = skinEntry[i]
  let path = item.path
  let name = item.name
  if (process.env.NODE_ENV === 'production') {
    result['../skins/' + path + name] = './src/js/goods/skins/' + name + '.js'
  } else {
    result['skins/' + path + name] = './src/js/goods/skins/' + name + '.js'
  }
}

Object.assign(result, {
  vendor: ['@unit/common/js/base', '@unit/common/js/util']
})

// 公共文件提取
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor', // 注意不要.js后缀
  chunks: utils.computeChunks(entryConfig, '')
})

// 避免修改业务代码导致vendor的md5改变,保留文件缓存
new webpack.optimize.CommonsChunkPlugin({
  name: 'manifest',
  chunks: ['vendor']
})

自动化部署

自动化部署是在打包服务器通过脚本实现的,先通过npm命令打包前端工程,然后将代码copy到后端工程中,最后打包后端项目,再发布。

遇到的困难

公共文件的引入

webpack官方文档并没有如何引入公共html文件的说明,这一点是在翻了
N多资料后才发现的,最终的方案是:
去掉 webpack.config.js 文件中配置的全局html-loader,这样html模版文件就不会被html-loader解析,我们可以使用ejs 语法嵌入其他 html 页面和图片资源。因为没了全局的html-loader解析html文件,使用ejs语法嵌入的资源返回的是 ejs 代码,还需要使用html-loader来解析成html代码。

html-loader!)表示引用html-loader这个加载器来解析

<%= require('html-loader!../layout/header.html') %>

但是这样将全局html-loader去掉后,又碰到了下面的问题。

jsp 变量的引入

vm中有时需要直接引用后端的变量,如${cssUrl},就像这样:

这时候webpack打包居然就报错了,报错了:

原因排查

出现这个问题的原因应该是由于HtmlWebpackPlugin这个插件引用的模版默认是 ejs,当不使用全局html-loader的时候,模板文件其实是以 ejs 解析的,而${cssUrl}ejs 中也识别为一个变量,当然就报错了。

解决方法

这过程中,整个周末都在想这个问题,甚至已经开始考虑用gulp+webpack的方案了。。又翻了很多资料,突然想到既然是ejs模板,可以尝试了一些 ejs 去写,而不是非要把这个模板以html的方式 loader 进来,然后就有了如下方法:

<link href="<%= '${cssUrl}' %>" rel="stylesheet">

这时候就被识别为一个字符串了!成功解决。

进一步探索,巧用 node 环境变量
上面的方法解决的其实也是挺丑的,因为本地开发的时候需要引用本地文件的,上线的时候又得傻乎乎地去一个个地方去替换:

<!-- <link href="<%= skinCss %>" rel="stylesheet">   -->
<link href="/skins/pay/pay.css" rel="stylesheet">

然后马上试了下,在模板文件中用 ejs 去读node 环境变量
process.env.NODE_ENV,果然能取到值,就有了下面这个相对完美的方案:

<% 
if (process.env.NODE_ENV === 'production') { 
  skinCss = '${cssUrl}';
} else { 
  skinCss = '/skins/pay/pay.css'; 
} 
%>

<link href="<%= skinCss %>" rel="stylesheet">

其中production就是利用 **node **启动 **webpack **时配置的,在这里派上了大用场。

End

到这里,我们奇货商城已经实现了前端工程自动化,再也不用一遍又一遍地去 vm 里修改路径,人工去记着改了哪些文件,要上传哪些静态资源。更加不用担心漏传什么资源文件而导致线上bug辣。

作者:Woodk
出处:http://www.cnblogs.com/woodk/p/7459467.html

技术交流QQ群 :238757010

关注微信公众号Reboot51后台回复 python、自动化即可获得相应课程的试听资料


运维自动化班 6 期报名开始

12月17日(周日)

课程大纲 http://51reboot.com/course/devops

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,671评论 7 110
  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 8,140评论 7 35
  • 在现在的前端开发中,前后端分离、模块化开发、版本控制、文件合并与压缩、mock数据等等一些原本后端的思想开始...
    Charlot阅读 5,428评论 1 32
  • 写在开头 先说说为什么要写这篇文章, 最初的原因是组里的小朋友们看了webpack文档后, 表情都是这样的: (摘...
    Lefter阅读 5,270评论 4 31
  • ​今年3月,商务部就美国铝箔生产商提出的申诉,对中国制造商涉嫌在美国市场倾销展开调查,并于8月初初步裁定对从中国进...
    贸立方阅读 129评论 0 0