使用webpack前端重构感受

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

重构起点

在一个老项目中用webpack对前端代码进行重构,重构的重心在于JS部分。这个老项目呢,有2年以上的历史了。

JS部分从底数起:

  1. Mootools - core/more 1.5.0
  2. jQuery - 1.11.1
  3. underscore,我也不记得什么版本了
  4. uikit + uikit部分components
  5. 用户开发的底层JS:mootools-extends扩展,uikit-extends - 基于uikit写的一套ui部分交互的东西,mobile-detect - 适配个版本安卓用的东西,custom-functions - 各种常用方法。
  6. jQuery插件:jquery-address、jquery-mobile-event、owl-carousel、tablesaw、jquery.transit、jquery.event.drop等
  7. requirejs
  8. 各种开源的工具:ckeditor、jsoneditor、plupload、DateTimePicker(Mootools版)、highcharts等
  9. 用户开发的上层JS:ui - 更具体的ui控制代码,shopping - 与购物车、交易相关的代码

上述这些是这次重构中,明确在前台能够找得到、有明确使用的类库,其实很多都是擦边球了,但怎么说还是有用到。

重构基础JS并合并打包

这次重构有一些目的,就是起码开源部分的类库,能更新的,应该尽可能的更新,能不用的类库,尽量去掉。

  1. Mootools 更新 1.6+,去掉More库
  2. jQuery,更新2.2+
  3. underscore换成lodash,underscore作者已经哭晕了,coffee渐渐es6取代,underscore被lodash取代,backbones,也不是非他不可,前端mvc如phpmvc一般雨后春笋般冒出,underscore也很久不更新了。
  4. uikit 更新到2.15+
  5. requirejs,Good bye!!
  6. 清查无用的jQuery插件
  7. 开源的工具也依次更新等。
  8. 增加React(react、react-dom)

其次,从内到外,重新合并打包出基础js(页面只加载一次这个js)。

Mootools(这家伙重写原生对象) => jQuery => lodash => uikit => 用户开发的底层JS => jQuery插件 => 用户开发的上层JS => 本次重构新写的JS

React和ReactDOM实际上实在本次重构新写的js中引入的。

上述内容是需要重新打包的js内容。webpack的入口文件——entry代码如下:

// 第一阶段
var jQuery = require('./lib/jquery_hack');
var lodash = require('./lib/lodash');
// var Mootools = require('./lib/mootools-core-1.5.1-full-nocompat');

window.$ = document.id;
window.jQuery = jQuery;
window._ = lodash;

// 第二阶段 uikit ui部分扩展
var uikit = require('./lib/uikit');

// 第三阶段 各种乱七八糟的类库,jQuery扩展之类的
require('./lib/jquery-address');
require('./lib/jquery-mobile-events');
require('./lib/jquery-datetimepicker');
require('./lib/jquery.pinto');
require('./lib/spark-md5');

// 第四阶段 自己写的js加载
require('./base/mootools-extends');
require('./base/mobile-detect');
require('./base/custom-functions');
var uk = require('./base/uikit-extends');
// 这是一个jquery的插件
require('./base/tablesaw');

var ui = require('./main/ui');
var shopping = require('./main/shopping');


require('./components');
jQuery(document).ready(function() {
	ui.initNumberInput();
	require('./page');
});

jQuery.fn.extend({
	animateCss: function (animationName) {
		var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
		jQuery(this).addClass('animated ' + animationName).one(animationEnd, function() {
			jQuery(this).removeClass('animated ' + animationName);
		});
	}
});

经过多方尝试,发现Mootools新版Core库,在PC端使用没有问题,但是在手机中,存在各种错误,尤其是在手机中的webkit系浏览器中,估计是因为更新了es6的scoping的问题,因为mootools的源码很多在块({})与块之间引用变量的问题,比如Slick、Element等,在这个块定义的方法,在下一个块就调用不到了。而且苹果和安卓,还各有不同的特征,修正了安卓下的问题,苹果又出毛病了。所以,最后实在没办法,Mootools 1.6.+ Core的代码单独在页面优先加载,之后是按照上述规则打包出来的基础JS。

下面是webpack的webpack.config.js,这个文件是用于生成开发版本调试用的:

const path = require("path");
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const gbdo = 'public/assets', test = 'assets/public';

const basePath = gbdo;

module.exports = {
	entry: {
		gbdo: ['./assets/js/app.js'],
	},
	// target: 'node', // http://stackoverflow.com/questions/33001237/webpack-not-excluding-node-modules
	// externals: [nodeExternals()],
	output: {
		path: path.resolve(__dirname, basePath),
		// publicPath: "/",
		filename: '[name].js'
	},
	module: {
		loaders: [
			{
				test: /\.less$/,
				loader: ExtractTextPlugin.extract('style', 'css!less')
			},
			{
				test: /\.styl$/,
				loader: ExtractTextPlugin.extract('style', 'css-loader!stylus-loader')
				// loader: 'css-loader!stylus-loader?paths=node_modules/bootstrap-stylus/stylus/'
			},
			{
				test: /\.css$/,
				loader: "style!css"
			},
			{
				test: /\.(png|jpg|jpeg|gif|(woff|woff2)?(\?v=[0-9]\.[0-9]\.[0-9])?)$/,
				loader: 'url-loader?limit=1000'
			},
			{
				test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
				loader: 'file'
			},
			{
				test: /\.(es6|jsx)?$/,
				exclude: /(node_modules|bower_components)/,
				loader: 'babel',
				query: {
					presets: ['es2015', 'react'],
					plugins: [
						"transform-es2015-block-scoping",
						"transform-class-properties",
						"transform-es2015-computed-properties"
					]
				}
			}
		]
	},
	plugins: [
		new webpack.optimize.UglifyJsPlugin({
			compress: {
				warnings: false,
			},
			output: {
				comments: false,
			},
		}),
	]
};

下面是webpack.build.js,是用于打包出最终的版本,以push到git用的:

const path = require("path");
const webpack = require('webpack');

var config = require('./webpack.config');

config.plugins.push(new webpack.DefinePlugin({
	'process.env':{
		'NODE_ENV': JSON.stringify('production')
	}
}));


module.exports = config;

为什么单独做一个webpack.build呢?这个后面会说到,其实主要问题是因为react这个多事鬼。

而ckeditor、jsoneditor、plupload、datetimepicker(jQuery版)、highcharts,这些属于外围的工具辅助类,以页面需要用到的时候,才发起调用。

webpack vs Gulp

其实我还有另外一个一模一样的打包的gulpfile.js,内容就不发了。两者打包出来的容量是相当的,webpack是696kb,gulp是691kb,不过就调试环境而言,差别就很大了,如果webpack以dev-server方式启动,他会保留完整的代码引用结构,以方便你检阅各个部分的代码:

使用webpack前端重构感受_第1张图片

所以如果同样是合并输出,webpack提供了更多的细节以让你进行调试。

当然,其实gulp也可以透过sourceMap的方式来实现,不过我不得不吐槽,gulp如果要生成js的sourceMap,执行时间相差实在太大了,稍微大一些的文件,或者是结合了babel,起码要等上几秒乃至更长的时间,完全没有实用的价值。

而且就合并处理的方式而言,当你执行webpack或者webpack-dev-server,如果转译的js或者css有错,他只会跳过这个文件,而继续往后执行,并且不中断当前的进程,也即你并不需要去手动重启webpack。

而gulp的话,就比较头疼了,虽然加入gutils对于部分的错误可以跳过,但是还是有一些异常是会让gulp中断的,所以用gulp watch的时候,你修改代码,必须小心翼翼,起码必须保证代码不能包含一些语法检查中可能引发的异常状态。

而关于i/o检索的准确性,gulp一直让我比较头疼,比如假定我监控的是指定的目录下的全部js文件,如果你新加了一个js文件,gulp watch是不会马上发现的,虽然他迟早会发现这个文件存在,但这需要有一个周期,所以更好的办法是停止当前的gulp watch,然后重新启动。

其次是,gulp虽然可以指定一个目录下的文件来检索,比如:js/*.js,js/*/*.js,可是一个很重要的问题是,这些文件加载是有序的,所以实际上你还是要一条一条来写,或者使用gulp-order、gulp-sort之类的插件,但实际上你还是必须手动指定具体的内容的。非常不爽。

相较而言,webpack则完全保留了node_modules的目录引用机制,就是该目录下的index.js索引文件,比如:require('./dir'),实际上就是引用的是dir/index.js。

entry入口文件,你确定引用需要的目录的索引文件,然后启动webpack或者webpack-dev-server,之后增加或者删除文件,修改entry文件,或者修改目录索引文件,webpack都会实时检索到更新,这比gulp操作起来要简便多了。

最后就是代码规模的问题,上面说了,同样的素材源代码,同样的uglifyJS配置,最基本的压缩,如果不压缩js,gulp还是挺快的,可是加上uglifyJS,gulp就成了一台年迈的老爷车。而webpack,除了上述的源代码,还增加了很多很多webpack自己的源代码,最后合并、并进行uglifyJS compress,依旧轻松愉快。

详细的技术细节我就不分析太多了,webpack的hot update,得益于他清晰结构化的合并代码结构,而不是纯粹简单的合并,不过这也会让不熟悉js的用户——尤其是不熟悉浏览器环境下调试的用户,增加了一层复杂度。但从实际使用的体验层面来说,webpack比gulp带来更好的体验感——最关键的是,gulp,还没用,就要装一大堆插件:

使用webpack前端重构感受_第2张图片

258个文件,你确定不是在逗我?我只是想写js……

webpack则相对要集中得多了。

从模式上来说,webpack关注的是集中,整合,并且严谨的检查前端引用的每一个资源,并根据你的配置打包输出到指定的目录下,一丝不苟,但容错性又很强。

相对来说,gulp兼容性很强,容忍,松散,效能低下,更严格意义上说,他只是你系统文件流的搬运工,而且容错性很低。

从上手来说,gulp和webpack初始上手都很容易,大家表层的配置和调用的接口都设计的巨简单。但是两者深入使用的时候,都很复杂,gulp你需要安装比jquery更多的插件,可能你项目实际用到的插件库,还没有gulp多。而webpack的配置,隐晦的东西太多太多,他是可以很牛掰,而且很多东西其实官网也有提过(但也就是那么一提),你不翻阅github issues,stackoverflow,根本不了解,哦原来官网那么简单一提的东西,原来是有那么深刻的用意的。

所以严格来说,webpack要熟练精通的话,可能会需要更高的投入。

转载于:https://my.oschina.net/janpoem/blog/677146

你可能感兴趣的:(webpack,前端,javascript)