谁知道主播楠楠和水仙网吧兮兮楠楠的网址

您现在的位置: >
> 文章内容 >
仿美团外卖、饿了么、大众点评app源码开发
仿美团外卖、饿了么、大众点评app源码多少钱?【系统定制热线:】当前外卖跑腿app已经成为了很多创业者看好的投资项目,正所谓知己知彼百战不殆,一款好的app不是要自己埋头设计,而是要充分对市场进行考察,针对市场设计具有特殊的系统。山东济南专业外卖app制作公司捷森科技今天就通过美团外卖、饿了么、大众点评等几款热门外卖app,来说说未来的发展前景。
任何一个品牌的发展都难免不会出现磕磕绊绊,随着美团外卖和饿了吗的关注度升高,现状两款app已经大幅度的降低了烧钱力度。然后来看看山东济南外卖APP同城跑腿O2O平台下载量以及活跃用户数量,据了解,不少人都是同时下载三款app,总的来说美团外卖和饿了么略高些。
要开发一款好的外卖app,就要了解当前这些主流产品的后台特点,以大众点评为例,开始的时候是以“点评+优惠券”的消费方式为核心,成为商家投放广告的首选,之后进军团购领域,如今希望以用户点评信息为基础,打造出本地生活服务平台。之后大众点评和饿了么互相合作,大众打开了外卖市场,饿了么则是进入了中高端外卖。
美团是以团购起家,目的是让消费者能够享受到更低的折扣以及更优质的服务,优惠力度大是它的一个显著优势,根据山东济南专业外卖app制作公司捷森科技的了解美团外卖app在外卖市场还未进入白热化竞争的时候就已经迅速出击,同时与本地商家紧密合作,因此用户使用率高,大大提高了美团跟商户和用户的粘度,这为美团往后的战略布局有举足轻重的意义。
仿美团外卖、饿了么、大众点评app源码多少钱?【微电:
扣扣:】总的来说山东济南外卖APP同城跑腿O2O平台已经形成了自己独有的发展特点,创业者要开发一款好的同城外卖app要先明确自己的app都要具备哪些功能,然后找一家可靠的山东济南专业外卖app制作公司进行功能定制开发,确保功能完善可靠,能够保障工期,如期上线运营。
山东济南专业外卖app制作公司捷森科技为广大用户提供专业的外卖系统定制服务,同时实现三端合一,数据互通。
相关资讯:
2090195818521820180717651658152014431361饿了么商家入驻页 H5页面
数据可视化举例,引导商家加盟
打开微信“扫一扫”,将本文章分享到朋友圈
快给朋友分享吧!
Ctrl+Enter
你的打赏就是我的动力!
悄悄说,听说打赏的人收入都比我高,不信你试试。
注: 打赏金额随意,完成后,请手动关闭本窗口。
Ctrl+Enter
您将要删除您的大作
饿了么商家入驻页 H5页面
在她入驻到UI中国的日子里
总共吸引了1729位设计师的驻足流连
总共收获了5位设计师的由衷赞赏
总共获得了8位设计师的悉心珍藏
总共引起了1位设计师的深入讨论
依然要删除吗?[!!! 原版课程在此]Vue.js 高仿饿了么外卖 App 课程源码 - 知乎专栏
你正在使用一个过时的浏览器。请以查看此页面。
{"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"title":"[!!! 原版课程在此]Vue.js 高仿饿了么外卖 App 课程源码","author":"ddfe","content":"由 DDFE 的黄轶带来的原创课程在慕课网关注颇高,使用 Vue.js+es6+webpack 等前端最新最热的技术,采用组件化、模块化的开发方式,让你用更少的代码做更快速的开发,我们把源码分享出来供大家阅读。欢迎收藏,谢绝转载!!!源码地址:","updated":"T03:02:16.000Z","canComment":false,"commentPermission":"anyone","commentCount":28,"collapsedCount":0,"likeCount":70,"state":"published","isLiked":false,"slug":"","lastestTipjarors":[{"isFollowed":false,"name":"咫尺天涯","headline":"","avatarUrl":"/da8e974dc_s.jpg","isFollowing":false,"type":"people","slug":"zhi-chi-tian-ya-57-73","profileUrl":"/people/zhi-chi-tian-ya-57-73","bio":"前端开发/知乎是我见过最垃圾的APP","hash":"2c4a28fa68fbd0e6849eb","uid":013000,"isOrg":false,"description":"","isOrgWhiteList":false,"avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"}},{"isFollowed":false,"name":"李木子","headline":"猫奴,家有主子一只","avatarUrl":"/44b92a80dbcb79ce7e4d0886_s.jpg","isFollowing":false,"type":"people","slug":"li-mu-zi-55-79","profileUrl":"/people/li-mu-zi-55-79","bio":"一只安静的小猿猿","hash":"c5cdad0cca1a87e1cef905","uid":989900,"isOrg":false,"description":"猫奴,家有主子一只","isOrgWhiteList":false,"avatar":{"id":"44b92a80dbcb79ce7e4d0886","template":"/{id}_{size}.jpg"}}],"isTitleImageFullScreen":false,"rating":"none","titleImage":"/v2-d5a721a128cb352cf20eadcc7ff7108f_r.jpg","links":{"comments":"/api/posts//comments"},"reviewers":[],"topics":[{"url":"/topic/","id":"","name":"Vue.js"}],"adminClosedComment":false,"titleImageSize":{"width":1920,"height":499},"href":"/api/posts/","excerptTitle":"","column":{"slug":"ddfe-weekly","name":"DDFE 技术周刊"},"tipjarState":"activated","tipjarTagLine":"真诚赞赏,手留余香","sourceUrl":"","pageCommentsCount":28,"tipjarorCount":2,"snapshotUrl":"","publishedTime":"T11:02:16+08:00","url":"/p/","lastestLikers":[{"profileUrl":"/people/xiao-kai-wen","bio":"","hash":"d8d5d8c2b322287fdd8a","uid":76,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"xiao-kai-wen","avatar":{"id":"4d037c0c0","template":"/{id}_{size}.jpg"},"name":"凯文先生"},{"profileUrl":"/people/xuxun","bio":"有梦想的咸鱼,江湖人称吃土小2叉……","hash":"c85c944b445b51b31f14a8fa1f05b50b","uid":76,"isOrg":false,"description":"2货吃货坑爹货,爱回收网小前端.. 个人网站:http://xuxun.me \n魔都透明渣反,乐乎: http://xu- \n微信公众号:清风迅来","isOrgWhiteList":false,"slug":"xuxun","avatar":{"id":"","template":"/{id}_{size}.jpg"},"name":"徐迅"},{"profileUrl":"/people/chen-xing-44-77","bio":"心至苦,事至盛也","hash":"2d3f6acd09c8d92dfccad795349edd4b","uid":40,"isOrg":false,"description":"","isOrgWhiteList":false,"slug":"chen-xing-44-77","avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"},"name":"陈行"},{"profileUrl":"/people/peng-xiao-ye-93","bio":"CS大二狗/足球迷/外语控","hash":"3b5f6da9adc7","uid":227300,"isOrg":false,"description":"小菜鸡??⊙⊙??","isOrgWhiteList":false,"slug":"peng-xiao-ye-93","avatar":{"id":"db11df8a80","template":"/{id}_{size}.jpg"},"name":"小潘东"},{"profileUrl":"/people/chen-yao-yao-94-82","bio":"格物致知","hash":"ec805e5efc0b","uid":582500,"isOrg":false,"description":"一个当程序猿的土木?","isOrgWhiteList":false,"slug":"chen-yao-yao-94-82","avatar":{"id":"1d6ecb573d8c47d58f2fd8b50f933297","template":"/{id}_{size}.jpg"},"name":"YasinChan"}],"summary":"由 DDFE 的黄轶带来的原创课程在慕课网关注颇高,使用 Vue.js+es6+webpack 等前端最新最热的技术,采用组件化、模块化的开发方式,让你用更少的代码做更快速的开发,我们把源码分享出来供大家阅读。欢迎收藏,谢绝转载!!!源码地址:","reviewingCommentsCount":0,"meta":{"previous":{"isTitleImageFullScreen":false,"rating":"none","titleImage":"","links":{"comments":"/api/posts//comments"},"topics":[{"url":"/topic/","id":"","name":"前端工程化"},{"url":"/topic/","id":"","name":"webpack"},{"url":"/topic/","id":"","name":"源码阅读"}],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"profileUrl":"/people/ddfe","bio":"前端架构师","hash":"7ca07f92642","uid":922700,"isOrg":false,"description":"我们是 DDFE 前端技术团队,负责滴滴出行公共前端技术方向,目前已出版《Vue.js权威指南》等著作。我们热爱技术,喜欢分享,希望对前端技术发展贡献绵薄之力。","isOrgWhiteList":false,"slug":"ddfe","avatar":{"id":"v2-29fdf7c4d03","template":"/{id}_{size}.jpg"},"name":"DDFE"},"column":{"slug":"ddfe-weekly","name":"DDFE 技术周刊"},"content":"作者:滴滴前端公共团队——钟宇飞个人知乎链接:我们在使用 webpack 的时候可以通过 webpack 这个命令配合一些参数来执行我们打包编译的任务。我们想探究它的源码,从这个命令入手能够比较容易让我们了解整个代码的运行过程。那么在执行这个命令的时候究竟发生了什么呢?注:本文中的 webpack 源码版本为1.13.3。本文中的源码分析主要关注的是代码的整体流程,因此一些我认为不是很重要的细节都会省略,以使得读者不要陷入到细节中而 get 不到整体。按照官方文档,webpack.config.js 会通过 module.exports 暴露一个对象,下文中我们统一把这个对象称为 webpack 编译对象(Webpack compiler object)。Step1:执行脚本 bin/webpack.js// bin/webpack.js\n\n// 引入 nodejs 的 path 模块\nvar path = require (\"path\") ;\n\n// 获取 /bin/webpack.js 的绝对路径\ntry {\n
var localWebpack = require.resolve (path.join (process.cwd (), \"node_modules\", \"webpack\", \"bin\", \"webpack.js\")) ;\n
if (__filename !== localWebpack) {}\n} catch (e) {}\n\n// 引入第三方命令行解析库 optimist\n// 解析 webpack 指令后面追加的与输出显示相关的参数(Display options)\nvar optimist = require (\"optimist\").usage (((\"webpack \" + require (\"../package.json\").version) + \"\\n\") + \"Usage: https://webpack.github.io/docs/cli.html\") ;\nrequire (\"./config-optimist\") (optimist) ;\noptimist\n
.boolean (\"json\").alias (\"json\", \"j\").describe (\"json\")\n
.boolean (\"colors\").alias (\"colors\", \"c\")... ;\n\n// 获取解析后的参数并转换格式\nvar argv = optimist.argv ;\nvar options = require (\"./convert-argv\") (optimist, argv) ;\n\n// 判断是否符合 argv 里的参数,并执行该参数的回调\nfunction ifArg (name, fn, init) {...}\n\n// 处理输出相关(output)的配置参数,并执行编译函数\nfunction processOptions (options) {...}\n// 执行\nprocessOptions (options) ;\n小结1.1:从上面的分析中我们可以比较清晰地看到执行 webpack 命令时会做什么处理,主要就是解析命令行参数以及执行编译。其中 processOptions 这个函数是整个 /bin/webpack.js 里的核心函数。下面我们来仔细看一下这个函数:function processOptions (options) {\n // 支持 Promise 风格的异步回调\n
if ((typeof options.then) === \"function\") {...}\n\n // 处理传入一个 webpack 编译对象是数组时的情况\n
var firstOptions = (Array.isArray (options)) ? options[0]: options;\n\n // 设置输出 options\n
var outputOptions = Object.create ((options.stats || firstOptions.stats) || ({}));\n\n // 设置输出的上下文 context\n
if ((typeof outputOptions.context) === \"undefined\") outputOptions.context = firstOptions.context ;\n\n
// 处理各种显示相关的参数,从略\n
ifArg (\"json\", \n
function (bool){...}\n
// 引入主入口模块 lib/webpack.js\n
var webpack = require (\"../lib/webpack.js\") ;\n\n
// 设置错误堆栈追踪上限\n
Error.stackTraceLimit = 30 ;\n
var lastHash = null ;\n\n // 执行编译\n
var compiler = webpack (options) ;\n\n // 编译结束后的回调函数\n
function compilerCallback (err, stats) {...}\n\n // 是否在编译完成后继续 watch 文件变更\n
if (options.watch) {...}\n
else \n // 执行编译后的回调函数\n
compiler.run (compilerCallback) ;\n}\n小结1.2:从 processOptions 中我们看到,最核心的编译一步,是使用的入口模块 lib/webpack.js 暴露处理的方法,所以我们的数据流接下来要从 bin/webpack.js 来到 lib/webpack.js 了,接下来我们看看 lib/webpack.js 里将会发生什么。step2:执行 lib/webpack.js 中的方法开始编译// lib/webpack.js\n\n// 引入 Compiler 模块\nvar Compiler = require (\"./Compiler\") ;\n\n// 引入 MultiCompiler 模块,处理多个 webpack 配置文件的情况\nvar MultiCompiler = require (\"./MultiCompiler\") ;\n\n// 引入 node 环境插件\nvar NodeEnvironmentPlugin = require (\"./node/NodeEnvironmentPlugin\") ;\n\n// 引入 WebpackOptionsApply 模块,应用 webpack 配置文件\nvar WebpackOptionsApply = require (\"./WebpackOptionsApply\") ;\n\n// 引入 WebpackOptionsDefaulter 模块,应用 webpack 默认配置\nvar WebpackOptionsDefaulter = require (\"./WebpackOptionsDefaulter\") ;\n\n// 核心函数,也是 ./bin/webpack.js 中引用的核心方法\nfunction webpack (options, callback) {...}\nexports = module.exports = webpack ;\n\n// 在 webpack 对象上设置一些常用属性\nwebpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter ;\nwebpack.WebpackOptionsApply = WebpackOptionsApply ;\nwebpack.Compiler = Compiler ;\nwebpack.MultiCompiler = MultiCompiler ;\nwebpack.NodeEnvironmentPlugin = NodeEnvironmentPlugin ;\n\n// 暴露一些插件\nfunction exportPlugins (exports, path, plugins) {...}\nexportPlugins (exports, \".\", [\"DefinePlugin\", \"NormalModuleReplacementPlugin\", ...]) ;\n小结2.1:lib/webpack.js 文件里的代码比较清晰,核心函数就是我们期待已久的 webpack,我们在 webpack.config.js 里面引入的 webpack 模块就是这个文件,下面我们再来仔细看看这个函数。function webpack (options, callback) {\n
var compiler ;\n
if (Array.isArray (options)) {\n
// 如果传入了数组类型的 webpack 编译对象,则实例化一个 MultiCompiler 来处理\n
compiler = new MultiCompiler (options.map(function (options) {\n
return webpack (options) ; // 递归调用 webpack 函数\n
} else if ((typeof options) === \"object\") {\n
// 如果传入了一个对象类型的 webpack 编译对象\n
// 实例化一个 WebpackOptionsDefaulter 来处理默认配置项\n
new WebpackOptionsDefaulter ().process (options) ;\n\n
// 实例化一个 Compiler,Compiler 会继承一个 Tapable 插件框架\n
// Compiler 实例化后会继承到 apply、plugin 等调用和绑定插件的方法\n
compiler = new Compiler () ;\n\n
// 实例化一个 WebpackOptionsApply 来编译处理 webpack 编译对象\n
compiler.options = options ; // 疑惑:为何两次赋值 compiler.options?\n
compiler.options = new WebpackOptionsApply ().process (options, compiler) ;\n\n
// 应用 node 环境插件\n
new NodeEnvironmentPlugin ().apply (compiler) ;\n
compiler.applyPlugins (\"environment\") ;\n
compiler.applyPlugins (\"after-environment\") ;\n
} else {\n
// 抛出错误\n
throw new Error (\"Invalid argument: options\") ;\n
}\n}\n小结2.2:webpack 函数里面有两个地方值得关注一下。一是 Compiler,实例化它会继承
,这个 Tapable 是一个插件框架,通过继承它的一系列方法来实现注册和调用插件,我们可以看到在 webpack 的源码中,存在大量的 compiler.apply、compiler.applyPlugins、compiler.plugin 等Tapable方法的调用。Webpack 的
注册和调用方式,都是源自 Tapable 。Webpack 通过 plugin 的 apply 方法安装该 plugin,同时传入一个 webpack 编译对象(Webpack compiler object)。二是 WebpackOptionsApply 的实例方法 process (options, compiler),这个方法将会针对我们传进去的webpack 编译对象进行逐一编译,接下来我们再来仔细看看这个模块。step3:调用 lib/WebpackOptionsApply.js 模块的 process 方法来逐一编译 webpack 编译对象的各项。// lib/WebpackOptionsApply.js\n// ...此处省略一堆依赖引入\n\n// 创建构造器函数 WebpackOptionsApply\nfunction WebpackOptionsApply () {\n
OptionsApply.call (this) ;\n}\n\n// 将构造器暴露\nmodule.exports = WebpackOptionsApply ;\n\n// 修改构造器的原型属性指向\nWebpackOptionsApply.prototype = Object.create (OptionsApply.prototype) ;\n\n// 创建 WebpackOptionsApply 的实例方法 process\nWebpackOptionsApply.prototype.process = function (options, compiler) {\n // 处理 context 属性,根目录\n
compiler.context = options.context ;\n // 处理 plugins 属性\n
if (options.plugins && (Array.isArray (options.plugins))) {...}\n// 缓存输入输出的目录地址等\n
compiler.outputPath = options.output.path ;\n
compiler.recordsInputPath = options.recordsInputPath || options.recordsPath ;\n
compiler.recordsOutputPath = options.recordsOutputPath || options.recordsPath ;\n
compiler.name = options.name ;\n// 处理 target 属性,该属性决定包 (bundle) 应该运行的环境\n
if ((typeof options.target) === \"string\") {...}\n
if (options.target !== false) {...}\n
else {...}\n // 处理 output.library 属性,该属性决定导出库 (exported library) 的名称\n
if (options.output.library || (options.output.libraryTarget !== \"var\")) {...}\n // 处理 externals 属性,告诉 webpack 不要遵循/打包这些模块,而是在运行时从环境中请求他们\n
if (options.externals) {...}\n // 处理 hot 属性,它决定 webpack 了如何使用热替换\n
if (options.hot) {...}\n// 处理 devtool 属性,它决定了 webpack 的 sourceMap 模式\n
if (options.devtool && (((options.devtool.indexOf (\"sourcemap\")) &= 0) || ((options.devtool.indexOf (\"source-map\")) &= 0))) {...}\n
else if (options.devtool && ((options.devtool.indexOf (\"eval\")) &= 0)) {...}\n\n// 以下是安装并调用各种插件 plugin,由于功能众多个人阅历有限,不能面面俱到\n\n
compiler.apply (new EntryOptionPlugin ()) ; // 调用处理入口 entry 的插件\n
compiler.applyPluginsBailResult (\"entry-option\", options.context, options.entry) ;\n
if (options.prefetch) {...}\n \n
compiler.apply (new CompatibilityPlugin (),\n
new LoaderPlugin (), // 调用 loader 的插件\n
new NodeStuffPlugin (options.node), // 调用 nodejs 环境相关的插件\n
new RequireJsStuffPlugin (), // 调用 RequireJs 的插件\n
new APIPlugin (), // 调用变量名的替换,webpack 编译后的文件里随处可见的 __webpack_require__ 变量名就是在此处理\n
new ConstPlugin (), // 调用一些 if 条件语句、三元运算符等语法相关的插件\n
new RequireIncludePlugin (), // 调用 require.include 函数的插件\n
new RequireEnsurePlugin (), // 调用 require.ensure 函数的插件\n
new RequireContextPlugin(options.resolve.modulesDirectories, options.resolve.extensions),\n
new AMDPlugin (options.module, options.amd || ({})), // 调用处理符合 AMD 规范的插件\n
new CommonJsPlugin (options.module)) ; // 调用处理符合 CommonJs 规范的插件\n\n
compiler.apply (new RemoveParentModulesPlugin (), // 调用移除父 Modules 的插件\n
new RemoveEmptyChunksPlugin (), // 调用移除空 chunk 的插件\n
new MergeDuplicateChunksPlugin (), // 调用合并重复多余 chunk 的插件\n
new FlagIncludedChunksPlugin ()) ; // \n\n
compiler.apply (new TemplatedPathPlugin ()) ;\n
compiler.apply (new RecordIdsPlugin ()) ; // 调用记录 Modules 的 Id 的插件\n
compiler.apply (new WarnCaseSensitiveModulesPlugin ()) ; // 调用警告大小写敏感的插件\n\n
// 处理 webpack.optimize 属性下的几个方法\n
if (options.optimize && options.optimize.occurenceOrder) {...} // 调用 OccurrenceOrderPlugin 插件\n
if (options.optimize && options.optimize.minChunkSize) {...} // 调用 MinChunkSizePlugin 插件\n
if (options.optimize && options.optimize.maxChunks) {...} // 调用 LimitChunkCountPlugin 插件\n
if (options.optimize.minimize) {...} // 调用 UglifyJsPlugin 插件\n\n
// 处理cache属性(缓存),该属性在watch的模式下默认开启缓存\n
if ((options.cache === undefined) ? options.watch: options.cache) {...}\n
// 处理 provide 属性,如果有则调用 ProvidePlugin 插件,这个插件可以让一个 module 赋值为一个变量,从而能在每个 module 中以变量名访问它\n
if ((typeof options.provide) === \"object\") {...}\n
// 处理define属性,如果有这个属性则调用 DefinePlugin 插件,这个插件可以定义全局的常量\n
if (options.define) {...}\n
// 处理 defineDebug 属性,调用并开启 DefinePlugin 插件的 debug 模式?\n
if (options.defineDebug !== false) compiler.apply (new DefinePlugin ({...})) ; // 处理定义插件的\n \n // 调用一些编译完后的处理插件\n
compiler.applyPlugins (\"after-plugins\", compiler) ;\n
compiler.resolvers.normal.apply (new UnsafeCachePlugin (options.resolve.unsafeCache)...) ;\n
compiler.resolvers.context.apply (new UnsafeCachePlugin (options.resolve.unsafeCache)...) ;\n
compiler.resolvers.loader.apply (new UnsafeCachePlugin (options.resolve.unsafeCache)...) ;\n
compiler.applyPlugins (\"after-resolvers\", compiler) ;\n\n // 最后把处理过的 webpack 编译对象返回\n
return options;\n};\n小结3.1:我们可以在上面的代码中看到 webpack 文档中
中介绍的各个属性,同时看到了这些属性对应的处理插件都是谁。我个人看完这里之后,熟悉了好几个平常不怎么用到,但是感觉还是很有用的东西,例如 externals 和 define 属性。step4:在 step3 中调用的各种插件会按照 webpack 编译对象的配置来构建出文件由于插件繁多,切每个插件都有不同的细节,我们这里选择一个大家可能比较熟悉的插件 UglifyJsPlugin.js(压缩代码插件)来理解 webpack 的流程。// lib/optimize/UglifyJsPlugin.js\n\n// 引入一些依赖,主要是与 sourceMap 相关\nvar SourceMapConsumer = require(\"webpack-core/lib/source-map\").SourceMapConsumer;\nvar SourceMapSource = require(\"webpack-core/lib/SourceMapSource\");\nvar RawSource = require(\"webpack-core/lib/RawSource\");\nvar RequestShortener = require(\"../RequestShortener\");\nvar ModuleFilenameHelpers = require(\"../ModuleFilenameHelpers\");\nvar uglify = require(\"uglify-js\");\n\n// 定义构造器函数\nfunction UglifyJsPlugin(options) {\n
...\n}\n// 将构造器暴露出去\nmodule.exports = UglifyJsPlugin;\n\n// 按照 Tapable 风格编写插件\nUglifyJsPlugin.prototype.apply = function(compiler) {\n
// 编译器开始编译\n
compiler.plugin(\"compilation\", function(compilation) {\n
// 编译器开始调用 \"optimize-chunk-assets\" 插件编译\n
compilation.plugin(\"optimize-chunk-assets\", function(chunks, callback) {\n
var files = [];\n
files.forEach(function(file) {\n
var asset = compilation.assets[file];\n
if(asset.__UglifyJsPlugin) {\n
compilation.assets[file] = asset.__UglifyJsPlugin;\n
if(options.sourceMap !== false) {\n
// 需要 sourceMap 时要做的一些操作...\n
} else {\n
// 获取读取到的源文件\n
var input = asset.source(); \n
// base54 编码重置\n
uglify.base54.reset(); \n
// 将源文件生成语法树\n
var ast = uglify.parse(input, {\n
filename: file\n
// 语法树转换为压缩后的代码\n
if(options.compress !== false) {\n
ast.figure_out_scope();\n
var compress = uglify.Compressor(options.compress); // eslint-disable-line new-cap\n
ast = ast.transform(compress);\n
// 处理混淆变量名\n
if(options.mangle !== false) {\n
ast.figure_out_scope();\n
ast.compute_char_frequency(options.mangle || {});\n
ast.mangle_names(options.mangle || {});\n
if(options.mangle && options.mangle.props) {\n
uglify.mangle_properties(ast, options.mangle.props);\n
// 定义输出变量名\n
var output = {};\n
// 处理输出的注释\n
output.comments = Object.prototype.hasOwnProperty.call(options, \"comments\") ? options.comments : /^\\**!|@preserve|@license/;\n
// 处理输出的美化\n
output.beautify = options.beautify;\n
for(var k in options.output) {\n
output[k] = options.output[k];\n
// 处理输出的 sourceMap\n
if(options.sourceMap !== false) {\n
var map = uglify.SourceMap({ // eslint-disable-line new-cap\n
file: file,\n
root: \"\"\n
output.source_map = map; // eslint-disable-line camelcase\n
// 将压缩后的数据输出\n
var stream = uglify.OutputStream(output); // eslint-disable-line new-cap\n
ast.print(stream);\n
if(map) map = map + \"\";\n
stream = stream + \"\";\n
asset.__UglifyJsPlugin = compilation.assets[file] = (map ?\n
new SourceMapSource(stream, file, JSON.parse(map), input, inputSourceMap) :\n
new RawSource(stream));\n
if(warnings.length & 0) {\n
compilation.warnings.push(new Error(file + \" from UglifyJs\\n\" + warnings.join(\"\\n\")));\n
} catch(err) {\n
// 处理异常\n
} finally {\n
// 回调函数\n
callback();\n
compilation.plugin(\"normal-module-loader\", function(context) {\n
context.minimize = true;\n
});\n};\n小结4.1:从这个插件的源码分析,我们可以基本看到 webpack 编译时的读写过程大致是怎么样的:实例化插件(如 UglifyJsPlugin )--& 读取源文件 --& 编译并输出总结现在我们回过头来再看看整体流程,当我们在命令行输入 webpack 命令,按下回车时都发生了什么: 1. 执行 bin 目录下的 webpack.js 脚本,解析命令行参数以及开始执行编译。 2. 调用 lib 目录下的 webpack.js 文件的核心函数 webpack ,实例化一个 Compiler,继承 Tapable 插件框架,实现注册和调用一系列插件。 3. 调用 lib 目录下的 /WebpackOptionsApply.js 模块的 process 方法,使用各种各样的插件来逐一编译 webpack 编译对象的各项。 4. 在3中调用的各种插件编译并输出新文件。","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T19:46:48+08:00","url":"/p/","title":"[webpack]源码解读:命令行输入webpack的时候都发生了什么?","summary":"作者:滴滴前端公共团队——钟宇飞 个人知乎链接:我们在使用 webpack 的时候可以通过 webpack 这个命令配合一些参数来执行我们打包编译的任务。我们想探究它的源码,从这个命令入手能够比较容易让我们了解整个代码的运行过程。那么在执行这个命…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":0,"likesCount":0},"next":{"isTitleImageFullScreen":false,"rating":"none","titleImage":"","links":{"comments":"/api/posts//comments"},"topics":[{"url":"/topic/","id":"","name":"Vue.js"}],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"profileUrl":"/people/ddfe","bio":"前端架构师","hash":"7ca07f92642","uid":922700,"isOrg":false,"description":"我们是 DDFE 前端技术团队,负责滴滴出行公共前端技术方向,目前已出版《Vue.js权威指南》等著作。我们热爱技术,喜欢分享,希望对前端技术发展贡献绵薄之力。","isOrgWhiteList":false,"slug":"ddfe","avatar":{"id":"v2-29fdf7c4d03","template":"/{id}_{size}.jpg"},"name":"DDFE"},"column":{"slug":"ddfe-weekly","name":"DDFE 技术周刊"},"content":"作者:小春 + 殷献勇滴滴前端公共团队相对组件来说,Vue 的插件开发受到的关注要少一点。但是插件的功能是十分强大的,能够完成许多 Vue 框架本身不具备的功能。 大家一般习惯直接调用现成的插件,比如官方推荐的 vue-router、vue-touch 等。 下面就看一下 Vue 的插件开发如何入门。首先我们简单回顾一下 Vue.js 官方文档中对于插件开发的描述。Vue 的插件必须提供一个公开方法 install,该方法会在你使用该插件,也就是 Vue.use(yourPlugin) 时被调用,相当于是一个插件的注册或者声明。install 接受 Vue 构造器作为第一个参数,并且有一个可选的选项对象作为第二个参数,比如:yourPlugin.install = function (Vue, options) {\n
// 1. 添加全局方法或属性\n
Vue.myGlobalMethod = ...\n
// 2. 添加全局资源\n
Vue.directive('my-directive', {})\n
// 3. 添加实例方法\n
Vue.prototype.$myMethod = ...\n}\n插件在使用时有两种方式:第一种是如上述提到的,可以通过 Vue.use(yourPlugin) 全局方法进行调用。 进行 Vue 的大型项目开发时,如果用 vue-cli 生成项目目录结构,Vue.use() 方法一般在 main.js 中调用。第二种实际上是插件本身帮你完成了 Vue.use()的调用。 这种情况下,插件会去检测是否存在 Vue 全局变量,如果存在,就自动调用 Vue.use()。所以,如果你的项目中是使用 script 方式引入的 Vue.js(这种情况下 Vue 才会作为一个全局变量存在),在使用比如 vue-router 之类的插件时就可以直接引入然后使用,不用再调用 Vue.use()。 但是,在模块环境下应当始终显式调用该方法,以保证插件可以正常使用:// 通过 Browserify 或 Webpack 使用 CommonJS 兼容模块\nvar Vue = require('vue')\nvar VueRouter = require('vue-router')\n// 不要忘了调用此方法\nVue.use(VueRouter)\n\n// 或者可以多传入一个选项对象\n// Vue.use(VueRouter, { hashbang: true })\n接下来我们看一下一些官方的常用插件的实现,我们配合去除具体逻辑的源码进行一些解读:1、vue-touch// version: 1.1.0\n// vue-touch.js\n\nvar vueTouch = {}\n\n// 暴露出的全局配置项,也就是在调用 Vue.use(Vue, options) 时传入的第二个选项参数\nvueTouch.config = {}\n\n// 核心部分,插件的具体逻辑均在此实现\nvueTouch.install = function (Vue) {\n
Vue.directive('touch', {\n
bind: function () {\n
update: function () {\n
unbind: function () {\n
})\n}\n\n// 支持 CommonJS\nif (typeof exports == \"object\") {\n
module.exports = vueTouch\n// 支持 AMD\n} else if (typeof define == \"function\" && define.amd) {\n
define([], function(){ return vueTouch })\n// Vue 是全局变量时,自动调用 Vue.use()\n} else if (window.Vue) {\n
window.VueTouch = vueTouch\n
Vue.use(vueTouch)\n}\n2、vue-router// version: 0.7.13\n// src/index.js\n\nlet Vue\n\n// 封装为 ES6 class\nclass Router {\n
// 可传入全局配置项\n
constructor({\n
hashbang = true,\n
abstract = false,\n
history = false,\n
saveScrollPosition = false,\n
transitionOnLoad = false,\n
suppressTransitionError = false,\n
root = null,\n
linkActiveClass = 'v-link-active'\n
} = {}) {\n
}\n}\n\n// 避免重复 install,设立 flag\nRouter.installed = false\nRouter.install = function (externalVue) {\n
if (Route.installed) {\n
Vue = externalVue\n\n
// install 的具体逻辑,此处省略\n
// install 完毕\n
Router.installed = true\n}\n\n// 同样,Vue 作为全局变量时自动 install\n\nif (typeof window !== 'undefined' && window.Vue) {\n
window.Vue.use(Router)\n}\n\nexport default Router\n3、 vue-resource// version: 1.0.3\n// src/index.js\n\n// install 方法\nfunction plugin(Vue) {\n
if (plugin.installed) {\n
// 插件核心逻辑,此处省略\n
// ...\n}\n\n// 同上,Vue 是全局变量时,自动 install\nif (typeof window !== 'undefined' && window.Vue) {\n
window.Vue.use(plugin);\n}\n\nexport default plugin;\n看完以上三个官方例子,相信各位已经对 Vue 的插件开发过程有了一定的了解,大家就可以根据自己的需要为 Vue 增加各种全局功能了。更多内容欢迎扫码关注 DDFE 公众号~","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T20:02:34+08:00","url":"/p/","title":"[Vue]插件开发入门","summary":"作者:小春 + 殷献勇滴滴前端公共团队相对组件来说,Vue 的插件开发受到的关注要少一点。但是插件的功能是十分强大的,能够完成许多 Vue 框架本身不具备的功能。 大家一般习惯直接调用现成的插件,比如官方推荐的 vue-router、vue-touch 等。 下面就看一下 …","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":0,"likesCount":0}},"commentsCount":28,"likesCount":70,"FULLINFO":true}},"User":{"ddfe":{"isFollowed":false,"name":"DDFE","headline":"我们是 DDFE 前端技术团队,负责滴滴出行公共前端技术方向,目前已出版《Vue.js权威指南》等著作。我们热爱技术,喜欢分享,希望对前端技术发展贡献绵薄之力。","avatarUrl":"/v2-29fdf7c4d03_s.jpg","isFollowing":false,"type":"people","slug":"ddfe","bio":"前端架构师","hash":"7ca07f92642","uid":922700,"isOrg":false,"description":"我们是 DDFE 前端技术团队,负责滴滴出行公共前端技术方向,目前已出版《Vue.js权威指南》等著作。我们热爱技术,喜欢分享,希望对前端技术发展贡献绵薄之力。","profileUrl":"/people/ddfe","avatar":{"id":"v2-29fdf7c4d03","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false,"badge":{"identity":null,"bestAnswerer":null}}},"Comment":{},"favlists":{}},"me":{},"global":{},"columns":{"ddfe-weekly":{"following":false,"canManage":false,"href":"/api/columns/ddfe-weekly","name":"DDFE 技术周刊","creator":{"slug":"ddfe"},"url":"/ddfe-weekly","slug":"ddfe-weekly","avatar":{"id":"v2-b530c79b70cc82bd1c443ae","template":"/{id}_{size}.jpg"}}},"columnPosts":{},"postComments":{},"postReviewComments":{"comments":[],"newComments":[],"hasMore":true},"favlistsByUser":{},"favlistRelations":{},"promotions":{},"env":{"isAppView":false,"appViewConfig":{"content_padding_top":128,"content_padding_bottom":56,"content_padding_left":16,"content_padding_right":16,"title_font_size":22,"body_font_size":16,"is_dark_theme":false,"can_auto_load_image":true,"app_info":"OS=iOS"},"isApp":false},"sys":{}}

我要回帖

更多关于 水仙楠楠6部 的文章

 

随机推荐