摘要:概述从去年短时间内对现有系统的改造到如今稳定实施,已经好几个月,这套流程满足了日常前端开发的流程。在讲这之前简单说下前端模块化历程。模块化以上是在规范出来之前的编码方式,大家应该非常熟悉。只要在代码中用来异步加载模块即可。
概述
从去年短时间内对现有系统的改造到如今稳定实施,已经好几个月,这套流程满足了日常前端开发的流程。由于之前项目组的模块化本身做的不是很好,基本算是推到一半重来,虽然阵痛,但回顾起来确实非常值得。webpack,简单来说就是前端静态资源的打包工具,确实好用,原理也很简单,比以AMD、CMD为标准的模块加载器好用多了,难怪玉伯说要给seajs、requirejs立一块墓碑了。在讲webpack这之前简单说下前端模块化历程。
模块化1.0// a.js (function(){ // todo a })(); // b.js (function(){ // todo b })(); // index.html
以上是在CommonJS规范出来之前的编码方式,大家应该非常熟悉。另外还有通过命名空间的方式来进行模块化,其实也没有真正的解决问题。
模块化2.0// a.js define(function(require, exports, module){ // todo a }) // b.js define(function(require, exports, module){ var a = require("./a"); // todo b }) // index.html
这就是过去几年大家都非常熟悉的模块化方式,在发布上线时通过构建工具,提取模块id、以及模块的依赖,合并压缩代码等等构建工作。
但是用requirejs或者seajs,还是有些问题:
只能模块化加载js、css,而且还不帮你合并,需要自己写插件去做合并的逻辑,组件化并不简单。
异步加载也不好用,尤其是部署时,hash后的资源路径自动替换还比较麻烦。
程序还是要依赖seajs这个几kb的库,总感觉有点多余。
模块化3.0webpack出来后,优雅的解决了很多问题,并且简单好用。它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、html、图片等静态资源都作为模块来处理。同时拥有异步加载的能力,非常适用于大型复杂的webapp的场景。webpack有以下特点:
兼容AMD/CMD的模块加载
js模块的写法遵循CommonJS规范
模块化所有静态资源(JS、CSS、html、图片、字体等)
开发、部署便捷,能替代大部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等
通过一个简单的配置文件即可搞定这些。
实战结合项目本身的特点,部分功能webpack无法做到,最终选用gulp+webpack方式来支撑前端的工作流,项目需求:
最小化配置项(webpack.config.js)
所有资源使用增量发布策略,文件名全部 md5 版本化
支持多种模块化策略,使用 webpack 进行模块化打包
自动替换 html/js 内部资源引用路径,替换为 cdn/md5 版本化路径
轻松支持 js资源内嵌到页面
开发时监听文件,自动上传到开发机
由于css是由重构同学写,雪碧图,压缩、发布等等都由他们来做,所以没有考虑加入到构建流程中来。
项目目录结构如下:
src/ js/ widget/ css/ img/ project_tpl/ gulpfile.js app/ js/ css/ img/ index.html tpl/ webpack.config.js gulpfile.js app/
src目录下是项目的源代码,每个目录(app)即为一个项目,为了尽量避免冲突,一个人开发并维护一个项目下的代码。
project_tpl为项目的模板,通过gulp新建项目,完成一些初始化配置,初始化后基本无需配置即可进行项目开发。
js/css/img为站点的一些公共资源模块,widget为公共基础组件。
app项目下为业务的css、js、tpl目录,tpl为前端模板目录,可以通过webpack的html-loader插件加载。
gulpfile.js、webpack.config.js 为项目的构建工具配置文件。
这样一个项目的脚手架搭建完成,可以开始为项目添砖加瓦了。可以点击这里看github上的例子。
webpack配置文件var webpack = require("webpack"); var globalConfig = require("../global.config"); var commonJSEntry = globalConfig.jsCommon; var path = require("path"); module.exports = { // 如果项目有多个HTML,或者多个入口 // 配置js入口文件,base是公共库配置,除了打包工具自动化抽取共用的模块,也可以自定义配置哪些模块为共用的。 entry:{ index: "./js/index", base: commonJSEntry, }, // 文件产出目录 output:{ filename:"../test/js/[name].js", // 异步加载的chunk,命名规则,chunk我暂时理解为从合并的代码里分离出来的代码块,在处理非首屏逻辑,或者异步加载逻辑可以用这个。只要在js代码中用require.ensure来异步加载模块即可。 chunkFilename: "../test/js/[chunkhash:8]_chunk.js", // 资源文件的CDN前缀 publicPath: debug ? "" : "//cdn.xxx.com/webpack/test/" }, resolve: { // 模块的别名,通常可以为第三方模块 alias: { ajax: "../../js/base/ajax", dom: "../../js/base/dom" }, // root模块的根路径,可以指定从哪里找模块,可以为数组[] // 这样在模块依赖的时候就不要写require(../../../xx.js) // 直接为require(xx) root: path.resolve("../../js") }, // 模块加载器,加载不同类型的文件,需要下载或者开发loader插件,以下为加载html模块的加载器 loader: [ {test: /.html$/, loader: "html"} ], /* 1、可以通过配置文件指定哪位模块为公共模块,这样功能模块可以长期缓存。 解释下这个插件的意思,就是提取公共的chunk,base对应了entry中的配置,"../test/js/common.js"是产出的路径,也就是将commonJSEntry中的配置模块合并成一个common.js文件。 2、webpack也可自动提取页面之间公用的代码作为公共部分。下面的代码即是自动提取公共代码了。 var commonsPlugin = new webpack.optimize.CommonsChunkPlugin("../test/js/common.js"); */ plugins: [ new webpack.optimize.CommonsChunkPlugin("base", "../test/js/common.js") ] };
由于项目的特性,没有用到热插拔,所以就不进行讲解了。
gulp跑起来webpack最终是当做gulp的一个插件来运行,读取的上述的webpack配置文件。
gulp.task("watch-html", function() { // upload }); gulp.task("watch-module", function() { var watchPath = [ "../js/**", "../css/**", "../widget/**", "js/**", "css/**", "tpl/**" ]; gulp.watch(watchPath, function(event){ gulp.src(watchPath) .pipe(webpack(require("webpack.config"))) .pipe(gulp.dest(releaseRelativePath + projectName)) .pipe(upload(opt, function(err, data){}) }) }); gulp.task("default", ["watch-html", "watch-module"]); // release build webpack module gulp.task("release-module", function() { var releasePath = [ "../js/**", "../css/**", "../widget/**", "js/**", "css/**", "tpl/**" ]; return gulp.src(watchPath) .pipe(webpack(require("webpack.config"))) .pipe(uglify()) .pipe(hash()) .pipe(rename(function(path) { // 获取当前的日期,将发布文件已日期归类,更方便查找文件 path.dirname = path.dirname + "/" + year + month + day; }) .pipe(gulp.dest(releaseRelativePath + projectName)) .pipe(upload(opt, function(err, data){}) }) }); // release build html gulp.task("release", ["release-module"], function(){ gulp.src(["**/*.html"]) .pipe(parseHtml(releaseRelativePath + projectName, CDN_URL)) .pipe(gulp.dest(releaseRelativePath + projectName)) .pipe(upload(opt, function(err, data){}) .pipe(uploadToCDN()) })
(以上用到的部分npm模块是自定义的)。
1、项目开始前,通过gulp init -p YourProjectName 来初始化项目
2、开发和发布两套命令,开发:gulp,发布:gulp release
3、需要自行编写gulp插件来替换html中引用资源的路径,原理也很简单,在构建webpack模块后,将产出的文件列表与原文件的映射关系保存在数组,查找html中引用的js路径,替换成hash后就可以了。
通过以上方法,就可以满足我们项目之前的需求,基本上做到自动化,自动构建,自动发布脚本,html文件走内部发布系统发布。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/79464.html
摘要:前言与是目前圈子内比较活跃的前端构建工具。对于初学者来说,对这二者往往容易认识不清,今天,就从事件的源头,说清楚与。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。打包后形成的文件出口。 前言:Webpack 与 gulp是目前圈子内比较活跃的前端构建工具。网上有很多二者比较的文章,面试中也会经常遇到gulp,Webpack的区别这样的问题。对于初学者来说,对这二...
摘要:所以它在某些程度上,跟的功能有些相同。严格上讲,模块化不是他强调的东西,他旨在规范前端开发流程。更是明显强调模块化开发,而那些文件压缩合并预处理等功能,不过是他附带的功能。 1. webpack 是什么? showImg(https://segmentfault.com/img/remote/1460000012293461); 先来说一下 webpack 是什么。 webpack 的...
摘要:主有前端后端,并加,各一名。本着工欲善其事,必先利其器的理念,一直以来在工作效率这块,略怀执念一个问题不应该被解决两次。下图为开发项目机制所涉及到的插件工欲善其事,必先利其器,语言,框架皆可以归结为器而不当仅局限于开发工具以及机。 原文链接: http://www.jeffjade.com/2016/05/08/106-vue-es6-jade-scss-webpack-gulp/ 一...
摘要:那时候所配置的任务监听匹配文件的变化自动刷新浏览器自动编译自动补全前缀多雪碧图合并拼图等等基于编译图片的任务,已经是完全满足我们的需求了。直至到后来在雪碧图的合并,多倍图的输出上,在上苦苦找寻不了比较完美的解决方案等等。 折腾 从 2015 到现在,短短的三年内,几乎每年折腾一下工作流的 更新换代 。从最早开始使用 Grunt 到 Gulp 再到 Webpack,再到 Rollup,...
阅读 484·2021-10-09 09:44
阅读 2030·2021-09-02 15:41
阅读 3531·2019-08-30 15:53
阅读 1811·2019-08-30 15:44
阅读 1254·2019-08-30 13:10
阅读 1149·2019-08-30 11:25
阅读 1382·2019-08-30 10:51
阅读 3345·2019-08-30 10:49