作为从grunt、gulp一路走来的老码农,一开始用webpack的时候我是很抗拒的。但由于核心库使用了vue,而webpack又是vue的最佳拍档(vue作者专门为其写了vue-loader),所以用webpack来构建项目就成了自然而然的事情。经过一段时间的摸索,各个流程都跑通了,「从入门到放弃」的那点事也就都不算事了。

webpack是以模块为中心的打包工具,但由于其日渐丰富的插件,能做的事情已经很多了,从开发环境搭建到上线构建,几乎可以一条龙包办了。事实上我在最近的项目中,连gulp都省了,完全用webpack就完成了所有的工作。下面一一道来。

本地server

在前后端分离的大前提下,前端本地已不需要起后端服务了,那为什么还要起一个本地server呢?这个server主要提供以下支持:

  1. 静态资源访问

  2. 代码热更新(实时刷新浏览器)

  3. 模拟请求数据

  4. 代理http请求

本地server是由webpack插件webpack-dev-middleware提供的,它是基于express的,所以还需要把express也装上。配置代码相当简单:

var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: config.output.publicPath,
stats: {
colors: true,
chunks: false
}
}); app.use(devMiddleware);

通常我们把它保存为dev-server.js,然后配合npm script来启动这个server,在package.json中写好:

"scripts": {
"dev": "node ./build/dev-server.js"
}

然后一行命令就可以启动了:npm run dev

需要注意的一点事,当我们起了本地server之后,webpack打包后的文件并不写入到硬盘上,而是保存在内存中。所以你并不会在目录下看到生成的文件,但是浏览器已经能够按照路径进行访问了,这样开发环境下的编译速度就大大加快。

独立vue组件

用了webpack之后,写vue组件最爽的就是可以写成单独的.vue文件了,在一个文件中写好所有的样式、模板、js逻辑。然后vue-loader就会帮我们编译成标准的vue组件。

令人高兴的是,vue2.0引入了虚拟DOM来提高性能,vue-loader也会将我们的模板编译成虚拟DOM来使用,你也不必费劲再去写render函数了。

编译ES6

之前也说过项目已经完全用ES6了,所以我们在开发环境需要用babel进行编译,我们写ES6代码的地方有两个,一个是js文件,另一个是.vue文件中的。

js文件的在webpack配置文件中配置loader即可:

{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/
}

而.vue文件中的,vue-loader已经天然帮我们做了,所以不需要任何设置。

babel的配置项,写在.babelrc中放在根目录下即可。

编译sass

前端进入编译时代,css当然也是少不了的。项目中使用了sass来编写css代码,所以也需要在开发环境进行编译。需要编译的有两个地方,一个是外链的.scss文件,另一个是.vue文件中的。

对于.scss文件,我们还是用loader来处理,安装sass-loader,然后在webpack配置文件中配好:

{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass')
}

至于.vue文件中的,vue-loader早帮我们做好了工作,只需在<style>标签加上lang属性就可以了,例如编译sass

<style lang="sass">
/*此处可以写sass代码啦*/ </style>

代码检查

在开发阶段进行代码检查也是一项必要工作,检查ES6当然eslint是标配,在配置文件中可以通过preLoaders来配置:

preLoaders: [
{
test: /\.(js|vue)$/,
exclude: /node_modules/,
loader: 'eslint-loader'
}
]

这样在js文件和.vue文件中的代码都会用eslint规则进行检查。eslint的配置同样写在.eslintrc文件中放在根目录下。

代码热更新

编译工作就是以上这些了。当我们开始正式敲代码之后,还有一个功能是梦寐以求的,那就是代码热更新。即编辑器保存代码后,浏览器实时刷新。这个特性在webpack中叫做”模块热替换(hot module repacement)“,使用webpack-hot-middleware这个插件来完成。

这个插件跟我们以前用的live-reload不同,它不会刷新浏览器页面,而是把模块进行热替换。这样的好处是,应用的当前状态还能保持,但是代码已经更新了。比以前爽了不止一点半点。

模拟数据

前后端分离开发中,还有重要的一环,就是前端mock数据。在后端接口开发完成之前,我们可以通过自己模拟的数据完成调试。

事实上mock数据并不需要webpack提供,而是通过我们的本地server,写express中间件的方式。需要以下两步:

第一步,根目录下建一个mock目录,用于放置假数据,每个接口一个js文件,为了便于express使用,文件的格式如下:

module.exports = {
api: '/api/mock/banner',
response: function (req, res) {
res.json({
success: true,
data: {
name: 'test'
}
});
}
}

第二步,在dev-server中把mock的数据挂载到express上,代码如下:

var mockDir = path.resolve(__dirname, '../mock');
fs.readdirSync(mockDir).forEach(function (file) {
var mock = require(path.resolve(mockDir, file));
app.use(mock.api, mock.response);
});

这样当我们请求的路径中含有/api/mock字样时,就会返回我们mock的数据啦。当后端的接口开发完成时,我们就可以把路径中的mock去掉,从而去请求后端的接口。

代理请求

由于我们起了本地server,ajax路径是相对的,所以请求会打到本地的这个server上。当我们需要调试后端接口时,就得把请求转发到后端服务器。为了避免跨域的麻烦,通常需要配置http代理。

我使用了http-proxy-middleware这个中间件,这也是和webpack无关的,它也是一个express中间件。配置方法如下:

app.use(proxy('/api', {
target: {
host: 'localhost',
protocol: 'http:',
port: 5050
},
logLevel: 'debug'
}));

我们和后端协商好,所有异步请求都带"/api"前缀,这样我就把请求转发到后端服务器了。此处我把host填了localhost,意味着我本地起了一个后端服务,事实上可以指向任何一台可以提供接口的服务器。

这个proxy中间件有一个小坑,就是路径必须向我这样分开写。如果拼在一起不会生效,我目前没找到原因。

移动端远程调试

出于平台兼容性的考虑,移动端调试我选择了weinre。用过weinre的同学应该知道,我们需要在页面上嵌一个<script>标签才能使用weinre。不熟悉的同学可以参考我之前写的这篇:http://www.cnblogs.com/lvdabao/p/3436620.html

所以,我们需要对当前运行的环境进行判断,如果是开发环境才嵌入这个标签。我用了一个叫做DefinePlugin的插件来在通过webpack在页面全局定义变量,用法如下:

new webpack.DefinePlugin({
LOCAL_IP: JSON.stringify(localIP),
__ENV__: JSON.stringify('dev'),
WEINRE_RUN: JSON.stringify(process.argv[2]=='weinre')
})

这样,在页面初始化的时候,我们就可以根据当前的环境来决定是否嵌入这个<script>啦,如下:

if(__ENV__ == 'dev' && WEINRE_RUN){
document.write('<script src="http://'+LOCAL_IP+':8080/target/target-script-min.js#anonymous"></script>');
}

插入<script>标签

我们的js打包好后,下一步就是把它引入到html文件了。由于我们通常会用md5作为文件名来控制js版本,所以html中的文件地址就需要每次构建后进行更新。

webpack中是通过HtmlWebpackPlugin这个插件来实现的,它的特点在于,每次构建基于一个html模板来生成新的html文件,所以并不是替换js路径。在webpack的plugins选项中如下配置:

new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../static/dist/index.html'),
chunks: ['vendor', 'components', 'app'],
template: path.resolve(__dirname, '../static/src/index.html'),
inject: true
})

代码压缩

在gulp时代,我们是通过配置gulp任务来完成js的压缩。在webpack中,是通过插件来完成的,相同的道理,在plugins中进行如下配置:

new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})

另外,webpack可以进行sourcemap配置,用于帮助映射文件,开启代码如下:devtool: 'source-map'

打包结果分析

在打包完成之后,我们经常会有这个心理:生成的文件完全不可读,打包的结果到底对不对,有没有重复打包,有没有冗余的东西。

这个时候就需要一个分析工具了,webpack有这样一个插件,能以可视化的方式展示打包结果,为你提供分析需求。它就是BundleAnalyzerPlugin,相当好用,我上一张我的截图:

上线构建

以上大部分是开发环境需要的配置,当我们本地测试完毕需要上线时,就需要真正生成文件了。

我们一般会准备两个或者多个(如何有多个环境,如test环境)webpack配置文件,用于不同的环境。在线上服务器跑的配置文件我们一般会修改输出地址,如果需要配cdn的话,把output中的publicPath填成cdn地址即可。然后直接运行webpack编译命令,而不是像本地server那样起。

同样我们也会写一个npm script,像这样:

"scripts": {
"dev": "node ./build/dev-server.js",
"build": "webpack --config ./build/prod.webpack.config.js"
}

我对webpack的应用大概就是这么多了,本想大致介绍,没想到一贴就是这么多代码~~其实webpack的精髓我本篇并未提及,那就是打包策略的选择,不同的项目架构需要不同的打包方式,而这个过程,则充满了挑战,你懂的。

(本文始发于我的微信公众号(doctor-programmer),整理重新编辑后发于博客,有兴趣的同学欢迎关注我的公众号,右边扫码去吧~)

webpack搭建前端一条龙服务的更多相关文章

  1. [坑况]——webpack搭建前端环境踩过的坑啊

    前言 嘿哈,webpack搭建前端环境踩过的坑啊! 第一个:完全不知所措 webpack4 下面用不了HtmlWebpackPlugin 和 ExtractTextPlugin 解决方案: html- ...

  2. 快速搞定用Vue+Webpack搭建前端项目(学习好久了,该写点东西了......)

    现在开始安装环境 一.安装node.js 首先要安装node.js,去nodejs官网下载即可,地址:http://nodejs.cn/中文网. 安装完成后,打开终端(windows键+R)搜索cmd ...

  3. webpack搭建前端开发环境

    webpack的版本已经是来到了4.0,口号是无配置就可以使用webpack,当然是使用一些基本的功能 1.安装以下webpack的一些必须npm包 npm install webpack npm i ...

  4. webpack搭建vue项目开发环境【文档向学习】

    为何有这篇文章 各个社区已经有无数篇帖子介绍如何使用webpack搭建前端项目,但无论是出于学习webpack的目的还是为了解决工作实际需要都面临着一个现实问题,那就是版本更新.别人的帖子可能刚写好版 ...

  5. webpack 4.x之搭建前端开发环境

    webpack是一个现代JavaScript应用程序的静态模块打包器,借用官网的一张图,它能够将一些预处理语言,js的最新语法转换成浏览器识别的内容.现在一般的前端框架都有比较成熟的脚手架,大多数对w ...

  6. 26、前端知识点--利用webpack搭建脚手架一套完整流程

    前言 我们的目标是利用webpack搭建一个基于react + react-router +dva + es6 + less + antd用于中后台开发的脚手架,同学们可能会说社区里那么多优秀的脚手架 ...

  7. 前端微服务-面向web平台级应用的设计

    从去年开始,前端领域就出现了一个‘微应用’的名词,说的是前端架构的一种设计思路,业内都把它和后端的微服务进行类比,当时忙于公司的项目.没有静下心来好好了解,现在项目结束,再加上最近看的几篇关于前端微服 ...

  8. 使用AWS亚马逊云搭建Gmail转发服务(三)

    title: 使用AWS亚马逊云搭建Gmail转发服务(三) author:青南 date: 2015-01-02 15:42:22 categories: [Python] tags: [log,G ...

  9. Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

随机推荐

  1. SQL Server2014 SP2新增的数据库克隆功能

    SQL Server2014 SP2新增的数据库克隆功能 创建测试库 --创建测试数据库 create database testtest use testtest go --创建表 )) --插入数 ...

  2. .NetCore中的日志(2)集成第三方日志工具

    .NetCore中的日志(2)集成第三方日志工具 0x00 在.NetCore的Logging组件中集成NLog 上一篇讨论了.NetCore中日志框架的结构,这一篇讨论一下.NetCore的Logg ...

  3. macOS 我的装机

    最近多次配置 Mac 的开发环境,稍微记录一下 1 创建无付费信息的Apple ID 2 Xcode ​ gem 源更改 3 Alfred 4 微信 5 SourceTree 6 Sublime Te ...

  4. 10个最好用的HTML/CSS 工具、插件和资料库

    大家在使用HTML/CSS开发项目的过程中,有使用过哪些工具,插件和库?下面介绍的10种HTML/CSS工具,插件和资料库,是国外程序员经常用到的. Firebug Lite FirebugLite ...

  5. 路由的Resolve机制(需要了解promise)

    angular的resovle机制,实际上是应用了promise,在进入特定的路由之前给我们一个做预处理的机会 1.在进入这个路由之前先懒加载对应的 .js $stateProvider .state ...

  6. Python的单元测试(一)

    title: Python的单元测试(一) author: 青南 date: 2015-02-27 22:50:47 categories: Python tags: [Python,单元测试] -- ...

  7. ElasticSearch 5学习(9)——映射和分析(string类型废弃)

    在ElasticSearch中,存入文档的内容类似于传统数据每个字段一样,都会有一个指定的属性,为了能够把日期字段处理成日期,把数字字段处理成数字,把字符串字段处理成字符串值,Elasticsearc ...

  8. .NET Core采用的全新配置系统[10]: 配置的同步机制是如何实现的?

    配置的同步涉及到两个方面:第一,对原始的配置文件实施监控并在其发生变化之后从新加载配置:第二,配置重新加载之后及时通知应用程序进而使后者能够使用最新的配置.要了解配置同步机制的实现原理,先得从认识一个 ...

  9. [原] 利用 OVS 建立 VxLAN 虚拟网络实验

    OVS 配置 VxLAN HOST A ------------------------------------------ | zh-veth0(10.1.1.1) VM A | | ---|--- ...

  10. Java多态性——分派

    一.基本概念 Java是一门面向对象的程序设计语言,因为Java具备面向对象的三个基本特征:封装.继承和多态.这三个特征并不是各自独立的,从一定角度上看,封装和继承几乎都是为多态而准备的.多态性主要体 ...