iSlider怎么ppt跳转到指定页

&p&给没有计算机学历 转行的,写个&b&简单、可行性高&/b&的流程:&/p&&p&&br&&/p&&p&先看个Java入门视频 认真学习java基本语法和特性 以及常用的数据结构&/p&&p&学习MySQL 增删改查 怎么建表 表与表之间的关系&/p&&p&用 SpringMVC 为网站做个简单的后端 跟着教学视频抄一遍都可以 但一定要动手敲代码 &/p&&p&做完基本就入门了。&/p&&p&&br&&/p&&p&后端还应该会的: &/p&&p&最基础的那几种算法: &/p&&p&1 排序 (重要)&/p&&p&2 搜索:DFS BFS 二分法 (重要)&/p&&p&3 动态规划&/p&&p&以及:&/p&&p&4 设计模式 (重要)&/p&&p&5 Linux的常用命令 (重要)&/p&&p&6 NoSQL &/p&&p&&br&&/p&&p&然后你跟科班的差距就剩下:&/p&&p&计算机组成原理、计算机网络、操作系统、编译原理&/p&&p&(不用怕 这些内容 科班出来的也大部分忘了 但很多概念应该要听说过 找几本书 有时间过一下就行了 &b&这些东西其实不是必须的 但决定你的上限&/b&)&/p&
给没有计算机学历 转行的,写个简单、可行性高的流程: 先看个Java入门视频 认真学习java基本语法和特性 以及常用的数据结构学习MySQL 增删改查 怎么建表 表与表之间的关系用 SpringMVC 为网站做个简单的后端 跟着教学视频抄一遍都可以 但一定要动手敲代码 …
&figure&&img src=&https://pic4.zhimg.com/v2-f53d7dd7241ce8aea25f068ba4cc08ca_b.jpg& data-rawwidth=&720& data-rawheight=&364& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic4.zhimg.com/v2-f53d7dd7241ce8aea25f068ba4cc08ca_r.jpg&&&/figure&&p&如今对于每一个前端工程师来说,webpack 已经成为了一项基础技能,它基本上包办了本地开发、编译压缩、性能优化的所有工作,从这个角度上来说,webpack 确实是伟大的,它的诞生意味着一整套工程化体系开始普及,并且慢慢统一了前端自动构建的让前端开发彻底告别了之前的刀耕火种时代。现在 webpack 之于前端开发,正如同 gcc/g++ 之于 C/C++,是一个你无论如何都绕不开的工具。&/p&&p&但是,即使它如此伟大,也有一个巨大的问题,那就是 &b&webpack 实在是太难用了!!!&/b&&/p&&p&我从多年前的 webpack 1.0 时代就一直在用它,现在也不能说完全掌握了它,很多时候真的让我产生了怀疑,究竟是因为我的能力不足,还是因为 webpack 自身的设计就太难用?随着我接触到越来越多的前端项目,听到越来越多的吐槽,我也越发地相信,是 webpack 自身的问题,导致它变得如此复杂又难用。&/p&&p&举个简单的例子,一个 vue-cli 生成的最简单的脚手架项目,开发、构建相关的文件就有 14 个之多,代码超过 800 行,而真实的项目只会比这个更多:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-09b87e624c2d1e9bdfc8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&274& data-rawheight=&313& class=&content_image& width=&274&&&/figure&&p&所以,既然这篇文章的标题是《webpack 为什么这么难用?》,那我们就好好在这里分析一下,webpack 难用的根本原因。&/p&&hr&&h2&一、文档极其不完善&/h2&&p&是的,这就是第一位的原因。&/p&&p&我作为参加过 webpack 中文文档翻译的人,真的想说 webpack 即使经过了这么多年的不断迭代,如今的文档依然还是是一坨那啥。作为一个开源项目,设计好不好、易用性怎么样、扩展性怎么样这些问题都是仁者见仁智者见智的,但文档写得很烂这一点上,真的没有任何可以开脱的理由。&/p&&h2&对于使用者的不友好&/h2&&p&比如,webpack 的插件体系可以说是 webpack 最核心的一部分功能了,基本上一个项目的构建中,大部分任务都是由各种插件完成的。然而,官方文档上对于插件的介绍只有寥寥几句话:&a href=&http://link.zhihu.com/?target=https%3A//webpack.js.org/concepts/plugins/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&webpack · Plugins&/a&,甚至推荐你直接去看 webpack 的源码:&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-460bec9aeaa10d31350afb9dac3b6668_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1408& data-rawheight=&200& class=&origin_image zh-lightbox-thumb& width=&1408& data-original=&https://pic1.zhimg.com/v2-460bec9aeaa10d31350afb9dac3b6668_r.jpg&&&/figure&&p&&br&&/p&&p&更糟的是,现有的文档里(包括 webpack 一些插件的文档也是),大部分内容都是在告诉你 “&b&你这样做就可以了&/b&”,而没有解释 “&b&你为什么需要这么做&/b&” 以及 “&b&你这么做了会有哪些后果&/b&”。&/p&&p&比如,在 target 配置上,&a href=&http://link.zhihu.com/?target=https%3A//webpack.js.org/configuration/target/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&官方文档&/a&里列举了你可以构建到哪些 target,如 &code&node&/code&、&code&node-webkit&/code&、&code&electron-main&/code&,但都只是简单的一句话带过:&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-2eff395de27d465bea820_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1410& data-rawheight=&988& class=&origin_image zh-lightbox-thumb& width=&1410& data-original=&https://pic1.zhimg.com/v2-2eff395de27d465bea820_r.jpg&&&/figure&&p&&br&&/p&&p&想知道 target 为 &code&electron-main&/code& 时,和浏览器环境的打包有什么不同?对不起,官方文档不想告诉你,看源码或者去 stackoverflow 上搜吧。&/p&&p&官方文档语焉不详的直接后果就是,当你遇到了任何问题,你都没办法在文档里得到直接的回答,而是需要看无数的代码、github issue、stackoverflow、博客文章,然后在自己的项目里反反复复试了好多次,才能大致解决问题。而这种所谓的“解决问题”,一般都是个人经验性的,意味着其它任何一个人想要解决这个问题,都要重复一遍这个流程,时间成本大量上升。&/p&&p&这就是为什么使用 webpack 的时候,经常会出现下面的哲学三问:&/p&&ul&&li&这是 webpack 的问题吗?&/li&&li&我要怎么解决这个问题?&/li&&li&咦我是怎么解决的?&/li&&/ul&&p&&br&&/p&&h2&对于开发者的不友好&/h2&&p&&b&我们要如何开发一个 webpack 的插件?&/b&&/p&&p&官方文档里确实写了一些关于&a href=&http://link.zhihu.com/?target=https%3A//webpack.js.org/contribute/writing-a-plugin/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&如何开发插件&/a&的指南。但这份指南也只有 60 分刚及格的水平,它确实向你介绍了 webpack 插件的基础范例、基本概念以及一些 API,但当你读完这份简短的文档后想自己真的去开发一个插件时,你会发现文档里讲的东西真的远远不够。&/p&&p&我们不妨来看看现在 webpack 生态里那些成熟的插件是怎么写的,以 &a href=&http://link.zhihu.com/?target=https%3A//github.com/jantimon/html-webpack-plugin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&html-webpack-plugin&/a& 为例,这是一个广泛用于生成 html 文件的插件。在它的源码里你会发现,它引用了&b&五个 webpack 内部自带的插件&/b&(&a href=&http://link.zhihu.com/?target=https%3A//github.com/jantimon/html-webpack-plugin/blob/master/lib/compiler.js& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&源码在这里&/a&):&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kd&&var&/span& &span class=&nx&&NodeTemplatePlugin&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'webpack/lib/node/NodeTemplatePlugin'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&NodeTargetPlugin&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'webpack/lib/node/NodeTargetPlugin'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&LoaderTargetPlugin&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'webpack/lib/LoaderTargetPlugin'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&LibraryTemplatePlugin&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'webpack/lib/LibraryTemplatePlugin'&/span&&span class=&p&&);&/span&
&span class=&kd&&var&/span& &span class=&nx&&SingleEntryPlugin&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'webpack/lib/SingleEntryPlugin'&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&p&嗯哼?这五个插件都是用来干什么的?&/p&&p&官方文档上对内置的插件一个字都没有提及,是的,甚至连 &a href=&http://link.zhihu.com/?target=https%3A//webpack.js.org/plugins/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Plugins&/a& 这里都没有。&a href=&http://link.zhihu.com/?target=https%3A//github.com/webpack/docs/wiki/internal-webpack-plugins& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&官方的 wiki&/a& 上倒是写了,但真的真的太简略了,而且看起来很久没更新了。&/p&&p&再看另外一个同样常用的 &a href=&http://link.zhihu.com/?target=https%3A//github.com/webpack-contrib/uglifyjs-webpack-plugin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&uglifyjs-webpack-plugin&/a&,它倒是没依赖 webpack 的内置插件,不过也引用了 webpack 内部的两个文件:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kr&&import&/span& &span class=&nx&&RequestShortener&/span& &span class=&nx&&from&/span& &span class=&s1&&'webpack/lib/RequestShortener'&/span&&span class=&p&&;&/span&
&span class=&kr&&import&/span& &span class=&nx&&ModuleFilenameHelpers&/span& &span class=&nx&&from&/span& &span class=&s1&&'webpack/lib/ModuleFilenameHelpers'&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&文档里同样没有对这两个文件做任何介绍。令人欣慰(?)的是,这两个文件从文件名上看,起码是方法库(实际上也确实是),使用起来不会太复杂。&/p&&p&换句话说,如果你想给 webpack 写一个广为人知的插件,你就必须深入了解 webpack 的全部,这一点我不反对,毕竟 &b&webpack 开发者&/b&和 &b&webpack 使用者&/b&在能力的要求上有高低之分。但即使是有经验的开发者,遇到一个文档如此不完善的开源项目,也是很吃力的。&b&很多能帮助开发者的东西本应该正大光明地写在文档和指南里,而不是隐藏在源代码里。&/b&&/p&&hr&&h2&二、过重的插件体系&/h2&&p&插件体系是 webpack 的核心,事实上,webpack 的大部分功能都是通过内部插件或者第三方插件来完成的。可以说,webpack 的生态就是建立在众多插件之上的。&/p&&p&但插件体系也同样有很多问题。&/p&&h2&插件数量问题&/h2&&p&先问一个问题,一个通过 webpack 构建的项目需要多少插件?&/p&&p&还是以一个标准的 vue-cli 生成的脚手架项目为例,一共有 7 个第三方插件:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&s2&&&copy-webpack-plugin&&/span&&span class=&o&&:&/span& &span class=&s2&&&^4.0.1&&/span&&span class=&p&&,&/span&
&span class=&s2&&&extract-text-webpack-plugin&&/span&&span class=&o&&:&/span& &span class=&s2&&&^3.0.0&&/span&&span class=&p&&,&/span&
&span class=&s2&&&friendly-errors-webpack-plugin&&/span&&span class=&o&&:&/span& &span class=&s2&&&^1.6.1&&/span&&span class=&p&&,&/span&
&span class=&s2&&&html-webpack-plugin&&/span&&span class=&o&&:&/span& &span class=&s2&&&^2.30.1&&/span&&span class=&p&&,&/span&
&span class=&s2&&&webpack-bundle-analyzer&&/span&&span class=&o&&:&/span& &span class=&s2&&&^2.9.0&&/span&&span class=&p&&,&/span&
&span class=&s2&&&optimize-css-assets-webpack-plugin&&/span&&span class=&o&&:&/span& &span class=&s2&&&^3.2.0&&/span&&span class=&p&&,&/span&
&span class=&s2&&&uglifyjs-webpack-plugin&&/span&&span class=&o&&:&/span& &span class=&s2&&&^1.1.1&&/span&&span class=&p&&,&/span&
&/code&&/pre&&/div&&p&以及 7 个 webpack 内置插件:&/p&&ul&&li&&code&HashedModuleIdsPlugin&/code& &/li&&li&&code&ModuleConcatenationPlugin&/code&&/li&&li&&code&CommonsChunkPlugin&/code&&/li&&li&&code&DefinePlugin&/code&&/li&&li&&code&HotModuleReplacementPlugin&/code&&/li&&li&&code&NamedModulesPlugin&/code&&/li&&li&&code&NoEmitOnErrorsPlugin&/code&&/li&&/ul&&p&总共 14 个插件,我们按照平均一个插件含有 2-3 个配置项(这已经是往低了算了)来计算,14 个插件就有 30 多项配置,这已经是一个现代 webpack 开发、构建使用的很基础的配置了,真实的项目只会比这个更多。&/p&&p&&b&要注意到,30 多个配置项带来的复杂程度是远胜于 30 行代码的。&/b& 因为配置项已经具有了比较高的抽象性,一项配置包含的副作用是要远大于一行代码的。比如下面是常常用于提取公共模块的 &code&CommonsChunkPlugin&/code& 的配置:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&k&&new&/span& &span class=&nx&&webpack&/span&&span class=&p&&.&/span&&span class=&nx&&optimize&/span&&span class=&p&&.&/span&&span class=&nx&&CommonsChunkPlugin&/span&&span class=&p&&({&/span&
&span class=&nx&&name&/span&&span class=&o&&:&/span& &span class=&s1&&'app'&/span&&span class=&p&&,&/span&
&span class=&nx&&async&/span&&span class=&o&&:&/span& &span class=&s1&&'vendor-async'&/span&&span class=&p&&,&/span&
&span class=&nx&&children&/span&&span class=&o&&:&/span& &span class=&kc&&true&/span&&span class=&p&&,&/span&
&span class=&nx&&minChunks&/span&&span class=&o&&:&/span& &span class=&mi&&3&/span&
&span class=&p&&})&/span&
&/code&&/pre&&/div&&p&如果你不是一个 webpack 老手的话,看到这 4 项配置肯定是一脸懵逼的:&/p&&ul&&li&&code&name&/code& 该填什么?随便命个名就好吗?&/li&&li&&code&async&/code& 是什么?异步模块?那为什么是个字符串?&/li&&li&&code&children&/code& 是个啥?为什么不是 &code&Array&/code& 而是个 &code&boolean&/code&?&/li&&li&&code&minChunks&/code& 这个数字是什么?&code&chunk&/code& 又是什么?&/li&&/ul&&p&然后你就去看了 &a href=&http://link.zhihu.com/?target=https%3A//webpack.js.org/plugins/commons-chunk-plugin/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&CommonsChunkPlugin 的文档&/a&,十五分钟艰难的阅读之后,你会发现这四项配置都不简单,每一项的更改会给构建带来很大的影响。&/p&&p&&b&然而坏消息是,像这样的配置在项目里整整有 30 多处!&/b&&/p&&p&所以我每次改一个项目的构建时,基本都是这样的:&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-0d1ef56c9c07f775e10bdca_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&620& data-rawheight=&413& class=&origin_image zh-lightbox-thumb& width=&620& data-original=&https://pic3.zhimg.com/v2-0d1ef56c9c07f775e10bdca_r.jpg&&&/figure&&p&&br&&/p&&h2&面向配置的插件&/h2&&p&在讨论这个话题之前,先回答两个问题:&/p&&ul&&li&&b&webpack 的插件先后顺序会影响构建结果吗?&/b&&/li&&li&&b&如果插件顺序不同,会影响哪些东西?&/b&&/li&&/ul&&p&实际上,这两个问题我找遍了官方文档,也没有提到插件的顺序会影响哪些东西,stackoverflow 上倒是找到了一个问题:&a href=&http://link.zhihu.com/?target=https%3A//stackoverflow.com/questions//webpack-does-the-order-of-plugins-matter& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Webpack: Does the order of plugins matter?&/a&&/p&&p&所以回答就是:&b&插件的顺序有影响,但作用不明。&/b&&/p&&p&其实问题不止在插件的顺序先后上,就连一个插件到底对构建产生了哪些影响,我们也很难得知,除非你极其熟悉这个插件或者就是这个插件的作者。为什么会这样?根本原因就是,&b&webpack 的插件是面向配置的,而不是面向过程的&/b&&/p&&p&什么叫&b&面向过程&/b&?如果你知道或者使用过 gulp 这个自动化工具的话,应该会记得 gulp 管道的概念,即从源头那里得到源数据(js/css/html 源码、图片、字体等等),然后数据通过一个又一个组合起来的管道,最后输出成为构建的结果。写成伪代码的话,大概是这样:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&nx&&gulp&/span&&span class=&p&&.&/span&&span class=&nx&&src&/span&&span class=&p&&(&/span&&span class=&s1&&'某些源文件'&/span&&span class=&p&&)&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&处理一&/span&&span class=&p&&)&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&处理二&/span&&span class=&p&&)&/span&
&span class=&p&&.&/span&&span class=&nx&&pipe&/span&&span class=&p&&(&/span&&span class=&nx&&处理三&/span&&span class=&p&&)&/span&
&span class=&p&&.&/span&&span class=&nx&&dest&/span&&span class=&p&&(&/span&&span class=&s1&&'构建结果'&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&这种管道化,或者说面向过程的构建,非常容易 debug 或者修改,因为它构建的每一步过程,都整齐的按照顺序展示给你看了。想要修改其中任何一步的心智负担是很低的,因为它的处理机制非常纯函数。&/p&&p&然而如果是 webpack 的话,就类似这样:&/p&&div class=&highlight&&&pre&&code class=&language-json&&&span&&/span&&span class=&p&&{&/span&
&span class=&err&&plugins:&/span& &span class=&err&&[&/span&
&span class=&err&&插件一,&/span&
&span class=&err&&插件二,&/span&
&span class=&err&&插件三&/span&
&span class=&err&&]&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&这里,插件一二三是完全面向配置的,没有告诉你任何执行顺序,它们可能会在 webpack 构建的每个时间点触发,你只能从它们的功能上大致猜出它是在哪个时间点工作的。这就是为什么修改一些 webpack 的配置,就像要解开一条放在包里很久的耳机线一样,麻烦又闹心。&/p&&p&当然,这种配置化的插件也是有好处的,配置化代表了高集成度,当你只有 1-3 个插件时,维护这些配置的心智负担是可以接受的,并且比维护面向过程的配置更加方便。&b&但当插件数量超过这个值的时候,构建的复杂程度就会呈指数式上升&/b&,我们之前就已经提到了,一个现代的 webpack 项目起码会有 14 个以上的插件以及至少 30 多项配置,这种情况下,面向过程就会好于面向配置,这就是为什么我一直觉得 gulp + webpack 才是正确解决方案的原因。&/p&&p&&i&当然还是要说一句,gulp 和 webpack 并不能直接比较,前者是一个 task runner,而后者是一个 module bundler,它们两者之间都有一些相互不可替代的功能。&/i&&/p&&hr&&h2&三、配置化是银弹吗?&/h2&&p&在日常业务中,特别是大公司的一些运营性质的业务里,我们常常会看到 “某某业务已经实现完全配置化” 这样的字眼,在这个语境里,配置化代表了低维护成本、高灵活性、高封装性。&/p&&p&在技术的世界里,配置化也同样是个好东西,很多工具都会宣称自己是完全配置化的,只要你的项目里加入一个配置文件,那么这个工具就可以帮你做很多很多的事情,&a href=&http://link.zhihu.com/?target=http%3A//babeljs.io/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&babel&/a&、&a href=&http://link.zhihu.com/?target=https%3A//eslint.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&eslint&/a&、&a href=&http://link.zhihu.com/?target=https%3A//stylelint.io/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&stylelint&/a&,还有本文讨论的 webpack 都是如此。&/p&&p&所以配置化是不是就是所有工具进化的终点了呢?它是不是能解决所有的问题呢?&/p&&p&软件工程上有一句耳熟能详的话:“&b&&a href=&http://link.zhihu.com/?target=http%3A//www.itu.dk/people/hesj/BSUP/artikler/no-silver-bullit.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&没有银弹&/a&&/b&”,指的是&b&复杂的软件工程问题无法靠简单的答案来解决&/b&。在前端工程构建这个问题上,也同样不例外。&/p&&p&如何解决前端工程的构建?webpack 给出的答案是:&b&通过 webpack + loader + plugin,让一切资源构建可配置。&/b& 这在它诞生的那个时代看来,是非常厉害的,一份简单的配置文件就帮你搞定了所有资源构建的问题。&/p&&p&但是当时间的推移,一个前端项目的构建变得越来越复杂,webpack 的配置也越来越多,维护起来越来越难,这个时候,也就慢慢诞生了诸如 &a href=&http://link.zhihu.com/?target=https%3A//github.com/facebookincubator/create-react-app& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&create-react-app&/a&、&a href=&http://link.zhihu.com/?target=https%3A//github.com/vuejs/vue-cli& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vue-cli&/a& 这样的脚手架工具,在 webpack 的基础上进一步封装,来帮你自动生成 webpack 的配置。这个时候,webpack 更多地变成了一个“底层”工具,而这些脚手架才是你实际上的“构建工具”,或者说,&b&这些脚手架提供的配置,才是你真正的构建配置&/b&。&/p&&p&为什么会这样?&/p&&p&这个问题的根源在于,&b&webpack 现在提供的配置的封装性已经不够了&/b&,它面对一个如今复杂得多的大型前端工程,仅有的配置已经没办法像几年前那样为我们屏蔽掉大部分的构建细节了,所以在它的基础上诞生了如此多的脚手架工具帮我们进一步封装复杂性。&/p&&p&所以我们现在可以回答这一段的标题了:配置化是解决复杂度的银弹吗?当然不是,因为&b&配置会随着复杂度的提升,而也逐渐变得复杂,维护越来越难,直到超过某个临界值,就会需要在它的基础上进一步封装,产生新的配置化。&/b&&/p&&hr&&h2&四、前端工程构建的未来&/h2&&p&正如我在上一章所说的,随着复杂度的上升,需要不断地封装复杂性,以让维护配置的心智成本降到可以接受的程度。而在前端构建工具上,截止到趋势也正是如此:&/p&&ul&&li&前端的远古时代我们不需要构建,因为这时的前端项目还很简单,原始的 html/js/css 就足以应付需求,手工处理这些资源方便又快捷。&/li&&li&随着前端的复杂化,手工处理的效率越来越低,grunt、gulp 这样的自动化工具就诞生了,它们屏蔽掉了很多资源处理的细节问题,让资源的处理可以自动完成。&/li&&li&随着构建流程越来越多、资源种类越来越多、ECMAScript 的语言特性愈加复杂、开始区分开发/测试/生产环境等等因素,gulpfile/grunt 这样的工具已经不能满足我们的需求,我们需要的是一整套完整的配置化的构建方案,而 webpack 就是这样一种方案。&/li&&li&随着 webpack 配置越来越复杂,维护成本也越来越高,于是诞生了很多脚手架工具,帮你生成 webpack 的配置,封装起 webpack 的复杂性。&/li&&/ul&&p&那么未来的&b&下一代前端构建工具&/b&是怎样的呢?&/p&&p&现在广泛使用的这些脚手架工具,终究依赖的是 webpack,我们实际上需要的是集成度更高、封装性更高(甚至零配置)的构建工具。更详细地说,下一代前端构建工具,必然会有下面的某些特性:&/p&&ul&&li&内置的功能更多,比如自带 babel、dev-server、HMR、sourceMap 等等功能;&/li&&li&配置更少,甚至零配置;&/li&&li&更低成本区分开发、测试、生产环境;&/li&&li&性能更好,整合冗长的构建流程,支持多核 CPU 等;&/li&&li&对于新型模块的支持:异步模块、WebAssembly 模块等。&/li&&/ul&&p&事实上,这也就是部分 &a href=&http://link.zhihu.com/?target=https%3A//github.com/webpack/webpack/issues/6064& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&webpack 4.0 将会有的新特性&/a&,以及前段时间看到的 &a href=&http://link.zhihu.com/?target=https%3A//github.com/parcel-bundler/parcel& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&parcel&/a& 也具有其中的某些特点(虽然它现在看起来还很不成熟)。未来这样的构建工具只会越来越多。&/p&&hr&&h2&总结&/h2&&p&这篇文章很久之前就在构思了,只是近期在工作上集中遇到了很多 webpack 的坑,让我彻底有动力来吐槽一下它的种种不是。&/p&&p&webpack 为什么这么难用?本文给出的答案浓缩起来就是两点:&/p&&ul&&li&文档不完善,导致使用者和开发者遇到问题都很难下手;&/li&&li&项目需要使用的插件数量太多,且面向配置,导致维护成本指数级上升。&/li&&/ul&&p&这些问题未来会有改善吗?当然。其实,这篇文章其实有标题党的嫌疑,更准确的标题应该是:&/p&&p&《&b&现在的&/b& webpack 为什么这么难用?》&/p&&p&因为这篇文章里提到的问题,都会在 webpack 4.0 中得到改善。&/p&&p&额……至于它的文档嘛……算了不提了不提了 O__O &…&/p&
如今对于每一个前端工程师来说,webpack 已经成为了一项基础技能,它基本上包办了本地开发、编译压缩、性能优化的所有工作,从这个角度上来说,webpack 确实是伟大的,它的诞生意味着一整套工程化体系开始普及,并且慢慢统一了前端自动构建的让前端开发彻底…
其实我到感觉前端应该了解从http发起请求,到dns到apache,到某后端语言,然后回来,浏览器渲染的整个过程。这样有助于更好的把前端做好,也为了方便问题的排查。&br&其实我一直认为这是一个很好的面试题,比一上手问人闭包,更具有实战意义。&br&以下是积累的一些资料,分享一下,希望有用:&br&&br&&p&&a href=&//link.zhihu.com/?target=http%3A//www.html5rocks.com/zh/tutorials/internals/howbrowserswork/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&浏览器的工作原理:现代网络浏览器幕后揭秘&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.html5rocks.com/zh/tutorials/internals/howbrowserswork/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&浏览器的工作原理:现代网络浏览器幕后揭秘&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//ux.sohu.com/topics/de3e752e0081ff%3Fqq-pf-to%3Dpcqq.group& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&NutUX&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.smallni.com/css-performance-from-the-browsers-rendering/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从浏览器的渲染原理讲CSS性能-Smallni's blog&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//coolshell.cn/articles/9666.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&浏览器的渲染原理简介&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.vtmer.com/2013/05/high-performance-javascript-1/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&javascript文件并行加载与顺序执行 《高性能javascript》读书笔记&/a&&br&
js 并行加载与顺序执行 &br&&a href=&//link.zhihu.com/?target=http%3A//fex.baidu.com/blog/2014/05/what-happen/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从输入 URL 到页面加载完成的过程中都发生了什么事情? FEX 做最专业的前端&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//ux.sohu.com/topics/de3e752e0081ff%3Fqq-pf-to%3Dpcqq.group& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&NutUX&/a&&br&
浏览器的工作原理:新式网络浏览器幕后揭秘 &br&&a href=&//link.zhihu.com/?target=http%3A//hikejun.com/blog//js& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&js和css的顺序关系&/a&%E5%92%8Ccss%E7%9A%84%E9%A1%BA%E5%BA%8F%E5%85%B3%E7%B3%BB&/p&&p&js css的顺序 &br&&a href=&//link.zhihu.com/?target=http%3A//coolshell.cn/articles/9749.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Javascript 装载和执行&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//renyongjie668.blog.163.com/blog/static/7062789/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&浏览器加载和渲染html的顺序&/a&&br&&/p&&br&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.sina.com.cn/s/blog_012p5e.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&DNS工作流程及原理 域名、IP与DNS的关系_longshu_新浪博客&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/maminyao/article/details/7390208& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&DNS工作流程及原理 浅说域名、IP与DNS的关系&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//baike.baidu.com/view/172221.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&DNS域名服务器&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.cnblogs.com/NetSos/archive//1891194.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HTML解析原理&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/longeremmy/article/details/8030736& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&浏览器加载渲染网页过程解析--总结(三)&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/longeremmy/article/details/8028738& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&浏览器加载渲染网页过程解析(二)&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//kb.cnblogs.com/page/129756/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端必读:浏览器内部工作原理&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.html5rocks.com/zh/tutorials/internals/howbrowserswork/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&浏览器的工作原理:现代网络浏览器幕后揭秘&/a&&/p&&br&&p&&a href=&//link.zhihu.com/?target=http%3A//www.cnblogs.com/li0803/archive//1324746.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HTTP协议详解(真的很经典)&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//baike.baidu.com/view/1628025.htm%3Ffromtitle%3Dhttp%26fromid%3Dtype%3Dsyn& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&超文本传送协议&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.sina.com.cn/s/blog_clrw.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&TCP与UDP区别_动物园黑手党&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//www.yc-edu.org/PHPpeixun/1428.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&php和apache的关系和作用&/a&&/p&&br&&p&有其它疑问,加群吧:,禁止闲聊,非喜勿加。&/p&
其实我到感觉前端应该了解从http发起请求,到dns到apache,到某后端语言,然后回来,浏览器渲染的整个过程。这样有助于更好的把前端做好,也为了方便问题的排查。 其实我一直认为这是一个很好的面试题,比一上手问人闭包,更具有实战意义。 以下是积累的一…
&figure&&img src=&https://pic3.zhimg.com/v2-b0caf318d71f4b313c33_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic3.zhimg.com/v2-b0caf318d71f4b313c33_r.jpg&&&/figure&&p&「数据结构与算法」这门计算机专业课其实非常重要,这一点大家都明白,尤其是在找工作的时候,现在很多的互联网公司都非常看重求职者的数据结构和算法的基础,无论是国外的 IT 巨头,像 Google,FB 这种,亦或是国内的互联网大公司,笔试最喜欢考的就是「数据结构与算法」。 &/p&&p&所以想进大公司做软件开发的话,无论如何都要把 「数据结构与算法」学好。&/p&&p&其实说实话,这门课还是蛮抽象的,个人认为它算是计算机专业课中难度相对较高的课程。&/p&&p&不过现在网络这么发达,肯定有可以利用的工具来简化你的学习过程,让你学的时候至少不会这么痛苦。&/p&&p&San Francisco 大学计算机学院关于这门课就提供给了大家这样一个可视化的教学资源,感觉蛮实用的,强烈推荐给大家。&/p&&p&&br&&/p&&p&这里带大家先睹为快。&/p&&h2&&b&队列&/b&&/h2&&p&手动输入一个你想要的数,可以观看入队和出队的过程。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-a2df20f9f07ac3cbc50bc_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&569& data-rawheight=&414& class=&origin_image zh-lightbox-thumb& width=&569& data-original=&https://pic1.zhimg.com/v2-a2df20f9f07ac3cbc50bc_r.jpg&&&/figure&&p&&br&&/p&&h2&&b&递归&/b&&/h2&&p&动态观看用递归的方法来计算阶乘的过程。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-ad60b238f10d3f884657_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&417& data-rawheight=&270& class=&content_image& width=&417&&&/figure&&p&&br&&/p&&h2&&b&排序算法&/b&&/h2&&p&各种排序算法的动态演示。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-0ae3ab6eea68f386e85a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&640& data-rawheight=&300& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic3.zhimg.com/v2-0ae3ab6eea68f386e85a_r.jpg&&&/figure&&p&&br&&/p&&h2&&b&深度优先查找&/b&&/h2&&p&查找的动态过程,直观的不能再直观了。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-a055f9f946c5e5dba97c20_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&640& data-rawheight=&421& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&https://pic1.zhimg.com/v2-a055f9f946c5e5dba97c20_r.jpg&&&/figure&&p&&br&&/p&&p&这里只带大家看这么多,网站上各种数据结构和算法都有,可以自己去看。&/p&&p&&br&&/p&&p&&b&网址在这里:&/b&&/p&&p&&a href=&http://link.zhihu.com/?target=https%3A//www.cs.usfca.edu/%7Egalles/visualization/Algorithms.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&cs.usfca.edu/~galles/vi&/span&&span class=&invisible&&sualization/Algorithms.html&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&关于这个网站,我觉得非常赞,简直堪称学习的神器。&/p&&p&对了,是免费的,真不是广告。&/p&&p&&br&&/p&&p&&br&&/p&&blockquote&&b&来自微信公众号:红猴子&/b&&/blockquote&&p&&/p&&p&&/p&&p&&/p&
「数据结构与算法」这门计算机专业课其实非常重要,这一点大家都明白,尤其是在找工作的时候,现在很多的互联网公司都非常看重求职者的数据结构和算法的基础,无论是国外的 IT 巨头,像 Google,FB 这种,亦或是国内的互联网大公司,笔试最喜欢考的就是「数…
&p&本文原载于&a href=&http://link.zhihu.com/?target=https%3A//juejin.im/post/59bb37fa6fb9a00a554f89d2%3Futm_source%3Dgold_browser_extension& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&掘金&/a&,作者&a href=&http://link.zhihu.com/?target=https%3A//juejin.im/user/574f8d8d2e958a005fd4edac& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&夕阳&/a&(饥人谷学员),转载已获作者授权。&/p&&blockquote&该文使用的 Webpack 版本为 3.6.0,本文分两部分。第一步是简单的使用 webpack,第二部分通过一个真实项目来配置 webpack,没有使用任何的 CLI,都是一步步配置直到完成生产代码的打包。&a href=&http://link.zhihu.com/?target=https%3A//link.juejin.im/%3Ftarget%3Dhttps%253A%252F%252Fgithub.com%252FKieSun%252Fwebpack-demo& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&这是本项目对应的仓库&/a&,每个小节基本都对应了一次 commit。&/blockquote&&p&这是本文的大纲,如果觉得有兴趣你就可以往下看了&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-4f76fc22a812ccb2dbf699efd78e4977_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1280& data-rawheight=&419& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic4.zhimg.com/v2-4f76fc22a812ccb2dbf699efd78e4977_r.jpg&&&/figure&&p&&br&&/p&&h2&Webpack 到底是什么&/h2&&p&自从出现模块化以后,大家可以将原本一坨代码分离到个个模块中,但是由此引发了一个问题。每个 JS 文件都需要从服务器去拿,由此会导致加载速度变慢。Webpack 最主要的目的就是为了解决这个问题,将所有小文件打包成一个或多个大文件,官网的图片很好的诠释了这个事情,除此之外,Webpack 也是一个能让你使用各种前端新技术的工具。&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-adddc12a98e30fe17afc2_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1016& data-rawheight=&417& class=&origin_image zh-lightbox-thumb& width=&1016& data-original=&https://pic3.zhimg.com/v2-adddc12a98e30fe17afc2_r.jpg&&&/figure&&p&&br&&/p&&h2&简单使用&/h2&&h2&安装&/h2&&p&在命令行中依次输入&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&mkdir
webpack-demo
cd webpack-demo
// 创建 package.json,这里会问一些问题,直接回车跳过就行
推荐这个安装方式,当然你也安装在全局环境下
// 这种安装方式会将 webpack 放入 devDependencies 依赖中
npm install --save-dev webpack
&/code&&/pre&&/div&&p&然后按照下图创建文件&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-2e67bcbf0ec59ac028e9297_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&264& data-rawheight=&215& class=&content_image& width=&264&&&/figure&&p&&br&&/p&&p&在以下文件写入代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// sum.js
// 这个模块化写法是 node 环境独有的,浏览器原生不支持使用
module.exports = function(a, b) {
return a + b
// index.js
var sum = require('./sum')
console.log(sum(1, 2))
&!DOCTYPE html&
&html lang=&en&&
&title&Document&/title&
&div id=&app&&&/div&
&script src=&./build/bundle.js&&&/script&
&/code&&/pre&&/div&&p&现在我们开始配置最简单的 webpack,首先创建 webpack.config.js 文件,然后写入如下代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// 自带的库
const path = require('path')
module.exports = {
'./app/index.js', // 入口文件
path: path.resolve(__dirname, 'build'), // 必须使用绝对地址,输出文件夹
filename: &bundle.js& // 打包后输出文件的文件名
&/code&&/pre&&/div&&p&现在我们可以开始使用 webpack 了,在命令行中输入&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&node_modules/.bin/webpack
&/code&&/pre&&/div&&p&没问题的话你应该可以看到类似的样子&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-791d512c61dda9c5813a6ce_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&444& data-rawheight=&149& class=&origin_image zh-lightbox-thumb& width=&444& data-original=&https://pic3.zhimg.com/v2-791d512c61dda9c5813a6ce_r.jpg&&&/figure&&p&&br&&/p&&p&可以发现原本两个 JS 文件只有 100B,但是打包后却增长到 2.66KB,这之中 webpack 肯定做了什么事情,我们去 bundle.js 文件中看看。&/p&&p&把代码简化以后,核心思路是这样的&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&var array = [(function () {
var sum = array[1]
console.log(sum(1, 2))
(function (a,b) {
return a + b
array[0]() // -& 3
&/code&&/pre&&/div&&p&因为 module.export 浏览器是不支持的,所以 webpack 将代码改成浏览器能识别的样子。现在将 index.html 文件在浏览器中打开,应该也可以看到正确的 log。&/p&&p&我们之前是在文件夹中安装的 webpack,每次要输入 node_modules/.bin/webpack 过于繁琐,可以在 package.json 如下修改&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&scripts&: {
&start&: &webpack&
&/code&&/pre&&/div&&p&然后再次执行 npm run start,可以发现和之前的效果是相同的。简单的使用到此为止,接下来我们来探索 webpack 更多的功能。&/p&&h2&Loader&/h2&&p&Loader 是 webpack 一个很强大功能,这个功能可以让你使用很多新的技术。&/p&&h2&Babel&/h2&&p&Babel 可以让你使用 ES 写代码而不用顾忌浏览器的问题,Babel 可以帮你转换代码。首先安装必要的几个 Babel 库&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm i --save-dev babel-loader babel-core babel-preset-env
&/code&&/pre&&/div&&p&先介绍下我们安装的三个库&/p&&ul&&li&babel-loader 用于让 webpack 知道如何运行 babel&/li&&li&babel-core 可以看做编译器,这个库知道如何解析代码&/li&&li&babel-preset-env 这个库可以根据环境的不同转换代码&/li&&/ul&&p&接下来更改 webpack-config.js 中的代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
// js 文件才使用 babel
test: /\.js$/,
// 使用哪个 loader
use: 'babel-loader',
// 不包括路径
exclude: /node_modules/
&/code&&/pre&&/div&&p&配置 Babel 有很多方式,这里推荐使用 .babelrc 文件管理。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// ..babelrc
&presets&: [&babel-preset-env&]
&/code&&/pre&&/div&&p&现在将之前 JS 的代码改成 ES6 的写法&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// sum.js
export default (a, b) =& {
return a + b
// index.js
import sum from './sum'
console.log(sum(1, 2))
&/code&&/pre&&/div&&p&执行 npm run start,再观察 bundle.js 中的代码,可以发现代码被转换过了,并且同样可以正常 输出3。&/p&&p&当然 Babel 远不止这些功能,有兴趣的可以前往官网自己探索。&/p&&h2&处理图片&/h2&&p&这一小节我们将使用 url-loader 和 file-loader,这两个库不仅可以处理图片,还有其他的功能,有兴趣的可以自行学习。&/p&&p&先安装库&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm i --save-dev url-loader file-loader
&/code&&/pre&&/div&&p&创建一个 images 文件夹,放入两张图片,并且在 app 文件夹下创建一个 js 文件处理图片&br&,目前的文件夹结构如图&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-99c7c1ee17eb4a1a478fd400bc116d65_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&232& data-rawheight=&372& class=&content_image& width=&232&&&/figure&&p&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// addImage.js
let smallImg = document.createElement('img')
// 必须 require 进来
smallImg.src = require('../images/small.jpeg')
document.body.appendChild(smallImg)
let bigImg = document.createElement('img')
bigImg.src = require('../images/big.jpeg')
document.body.appendChild(bigImg)
&/code&&/pre&&/div&&p&接下来修改 webpack.config.js 代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
// 图片格式正则
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
// 配置 url-loader 的可选项
options: {
// 限制 图片大小 10000B,小于限制会将图片转换为 base64格式
limit: 10000,
// 超出限制,创建的文件格式
// build/images/[图片名].[hash].[图片格式]
name: 'images/[name].[hash].[ext]'
&/code&&/pre&&/div&&p&运行 npm run start,打包成功如下图&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-ea8cd578ea71c8b29f28eac_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&657& data-rawheight=&279& class=&origin_image zh-lightbox-thumb& width=&657& data-original=&https://pic1.zhimg.com/v2-ea8cd578ea71c8b29f28eac_r.jpg&&&/figure&&p&&br&&/p&&p&可以发现大的图片被单独提取了出来,小的图片打包进了 bundle.js 中。&/p&&p&在浏览器中打开 HTML 文件,发现小图确实显示出来了,但是却没有看到大图,打开开发者工具栏,可以发现我们大图的图片路径是有问题的,所以我们又要修改 webpack.config.js 代码了。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
'./app/index.js', // 入口文件
path: path.resolve(__dirname, 'build'), // 必须使用绝对地址,输出文件夹
filename: &bundle.js&, // 打包后输出文件的文件名
publicPath: 'build/' // 知道如何寻找资源
&/code&&/pre&&/div&&p&最后运行下 npm run start,编译成功了,再次刷新下页面,可以发现这次大图被正确的显示了。下一小节我们将介绍如何处理 CSS 文件。&/p&&h2&处理 CSS 文件&/h2&&p&添加 styles 文件夹,新增 addImage.css 文件,然后在该文件中新增代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&img {
.test {border: 5}
&/code&&/pre&&/div&&p&这一小节我们先使用 css-loader 和 style-loader 库。前者可以让 CSS 文件也支持 impost,并且会解析 CSS 文件,后者可以将解析出来的 CSS 通过标签的形式插入到 HTML 中,所以后面依赖前者。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm i --save-dev css-loader style-loader
&/code&&/pre&&/div&&p&首先修改 addImage.js 文件&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import '../styles/addImage.css'
let smallImg = document.createElement('img')
smallImg.src = require('../images/small.jpeg')
document.body.appendChild(smallImg)
// let bigImg = document.createElement('img')
// bigImg.src = require('../images/big.jpeg')
// document.body.appendChild(bigImg)
&/code&&/pre&&/div&&p&然后修改 webpack.config.js 代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
test: /\.css$/,
use: ['style-loader',
loader: 'css-loader',
options: {
modules: true
&/code&&/pre&&/div&&p&运行下 npm run start,然后刷新页面,可以发现图片被正确的加上了边框,现在我们来看一下 HTML 的文件结构&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-77d411a75c82bf6ed17c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&328& data-rawheight=&231& class=&content_image& width=&328&&&/figure&&p&&br&&/p&&p&从上图可以看到,我们在 addImage.css 文件中写的代码被加入到了 style 标签中,并且因为我们开启了 CSS 模块化的选项,所以 .test 被转成了唯一的哈希值,这样就解决了 CSS 的变量名重复问题。&/p&&p&但是将 CSS 代码整合进 JS 文件也是有弊端的,大量的 CSS 代码会造成 JS 文件的大小变大,操作 DOM 也会造成性能上的问题,所以接下来我们将使用 extract-text-webpack-plugin插件将 CSS 文件打包为一个单独文件&/p&&p&首先安装 npm i --save-dev extract-text-webpack-plugin&/p&&p&然后修改 webpack.config.js 代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&const ExtractTextPlugin = require(&extract-text-webpack-plugin&)
module.exports = {
test: /\.css$/,
// 写法和之前基本一致
loader: ExtractTextPlugin.extract({
// 必须这样写,否则会报错
fallback: 'style-loader',
loader: 'css-loader',
options: {
modules: true
// 插件列表
plugins: [
// 输出的文件路径
new ExtractTextPlugin(&css/[name].[hash].css&)
&/code&&/pre&&/div&&p&运行下 npm run start,可以发现 CSS 文件被单独打包出来了&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-67b767fdd2e91eee93456f5_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&614& data-rawheight=&230& class=&origin_image zh-lightbox-thumb& width=&614& data-original=&https://pic2.zhimg.com/v2-67b767fdd2e91eee93456f5_r.jpg&&&/figure&&p&&br&&/p&&p&但是这时候刷新页面会发现图片的边框消失了,那是因为我们的 HTML 文件没有引用新的 CSS 文件,所以这里需要我们手动引入下,在下面的章节我们会通过插件的方式自动引入新的文件。&/p&&p&接下来,会用一个项目来继续我们的 webpack 学习,在这之前,先 clone 一下项目。该项目原地址是 &a href=&http://link.zhihu.com/?target=https%3A//link.juejin.im/%3Ftarget%3Dhttps%253A%252F%252Fgithub.com%252FStephenGrider%252FWebpackProject& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&这里&/a&,因为使用的 webpack 版本太低,并且依赖的库也有点问题,故我将项目拷贝了过来并修改了几个库的版本号。&/p&&p&请依次按照以下代码操作&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&git clone https://github.com/KieSun/webpack-demo.git
cd webpack-demo
// 切换到 0.1 标签上并创建一个新分支
git checkout -b demo 0.1
// 查看分支是否为 demo,没问题的话就可以进行下一步
&/code&&/pre&&/div&&h2&如何在项目中使用 webpack&/h2&&p&项目中已经配置了很简单的 babel 和 webpack,直接运行 npm run start 即可&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-f5ecaa91b5e_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&506& data-rawheight=&114& class=&origin_image zh-lightbox-thumb& width=&506& data-original=&https://pic3.zhimg.com/v2-f5ecaa91b5e_r.jpg&&&/figure&&p&&br&&/p&&p&这时候你会发现这个 bundle.js 居然有这么大,这肯定是不能接受的,所以接下来章节的主要目的就是将单个文件拆分为多个文件,优化项目。&/p&&h2&分离代码&/h2&&p&先让我们考虑下缓存机制。对于代码中依赖的库很少会去主动升级版本,但是我们自己的代码却每时每刻都在变更,所以我们可以考虑将依赖的库和自己的代码分割开来,这样用户在下一次使用应用时就可以尽量避免重复下载没有变更的代码,那么既然要将依赖代码提取出来,我们需要变更下入口和出口的部分代码。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// 这是 packet.json 中 dependencies 下的
const VENOR = [&faker&,
&react-dom&,
&react-input-range&,
&react-redux&,
&redux-form&,
&redux-thunk&
module.exports = {
// 之前我们都是使用了单文件入口
// entry 同时也支持多文件入口,现在我们有两个入口
// 一个是我们自己的代码,一个是依赖库的代码
// bundle 和 vendor 都是自己随便取名的,会映射到 [name] 中
bundle: './src/index.js',
vendor: VENOR
path: path.join(__dirname, 'dist'),
filename: '[name].js'
&/code&&/pre&&/div&&p&现在我们 build 一下,看看是否有惊喜出现&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-d2f1d9c82b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&498& data-rawheight=&158& class=&origin_image zh-lightbox-thumb& width=&498& data-original=&https://pic1.zhimg.com/v2-d2f1d9c82b_r.jpg&&&/figure&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-6bdd7fb1aa889ce7f552b57_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&309& data-rawheight=&300& class=&content_image& width=&309&&&/figure&&p&&br&&/p&&p&真的有惊喜。。为什么 bundle 文件大小压根没变。这是因为 bundle 中也引入了依赖库的代码,刚才的步骤并没有抽取 bundle 中引入的代码,接下来让我们学习如何将共同的代码抽取出来。&/p&&h2&抽取共同代码&/h2&&p&在这小节我们使用 webpack 自带的插件 CommonsChunkPlugin。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
path: path.join(__dirname, 'dist'),
// 既然我们希望缓存生效,就应该每次在更改代码以后修改文件名
// [chunkhash]会自动根据文件是否更改而更换哈希
filename: '[name].[chunkhash].js'
plugins: [
new webpack.optimize.CommonsChunkPlugin({
// vendor 的意义和之前相同
// manifest文件是将每次打包都会更改的东西单独提取出来,保证没有更改的代码无需重新打包,这样可以加快打包速度
names: ['vendor', 'manifest'],
// 配合 manifest 文件使用
minChunks: Infinity
&/code&&/pre&&/div&&p&当我们重新 build 以后,会发现 bundle 文件很明显的减小了体积&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-3cbf0a88a373ae71b8fd581_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&621& data-rawheight=&157& class=&origin_image zh-lightbox-thumb& width=&621& data-original=&https://pic2.zhimg.com/v2-3cbf0a88a373ae71b8fd581_r.jpg&&&/figure&&p&&br&&/p&&p&但是我们使用哈希来保证缓存的同时会发现每次 build 都会生成不一样的文件,这时候我们引入另一个插件来帮助我们删除不需要的文件。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm install --save-dev clean-webpack-plugin
&/code&&/pre&&/div&&p&然后修改配置文件&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
plugins: [
// 只删除 dist 文件夹下的 bundle 和 manifest 文件
new CleanWebpackPlugin(['dist/bundle.*.js','dist/manifest.*.js'], {
// 打印 log
verbose: true,
// 删除文件
dry: false
&/code&&/pre&&/div&&p&然后 build 的时候会发现以上文件被删除了。&/p&&p&因为我们现在将文件已经打包成三个 JS 了,以后也许会更多,每次新增 JS 文件我们都需要手动在 HTML 中新增标签,现在我们可以通过一个插件来自动完成这个功能。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm install html-webpack-plugin --save-dev
&/code&&/pre&&/div&&p&然后修改配置文件&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
plugins: [
// 我们这里将之前的 HTML 文件当做模板
// 注意在之前 HTML 文件中请务必删除之前引入的 JS 文件
new HtmlWebpackPlugin({
template: 'index.html'
&/code&&/pre&&/div&&p&执行 build 操作会发现同时生成了 HTML 文件,并且已经自动引入了 JS 文件&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-3bd46d319d6cd19439dcfc31ae2d165b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&546& data-rawheight=&159& class=&origin_image zh-lightbox-thumb& width=&546& data-original=&https://pic4.zhimg.com/v2-3bd46d319d6cd19439dcfc31ae2d165b_r.jpg&&&/figure&&p&&br&&/p&&h2&按需加载代码&/h2&&p&在这一小节我们将学习如何按需加载代码,在这之前的 vendor 入口我发现忘记加入 router 这个库了,大家可以加入这个库并且重新 build 下,会发现 bundle 只有不到 300KB 了。&/p&&p&现在我们的 bundle 文件包含了我们全部的自己代码。但是当用户访问我们的首页时,其实我们根本无需让用户加载除了首页以外的代码,这个优化我们可以通过路由的异步加载来完成。&/p&&p&现在修改 src/router.js&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// 注意在最新版的 V4路由版本中,更改了按需加载的方式,如果安装了 V4版,可以自行前往官网学习
import React from 'react';
import { Router, Route, IndexRoute, hashHistory } from 'react-router';
import Home from './components/Home';
import ArtistMain from './components/artists/ArtistMain';
const rootRoute = {
component: Home,
path: '/',
indexRoute: { component: ArtistMain },
childRoutes: [
path: 'artists/new',
getComponent(location, cb) {
System.import('./components/artists/ArtistCreate')
.then(module =& cb(null, module.default))
path: 'artists/:id/edit',
getComponent(location, cb) {
System.import('./components/artists/ArtistEdit')
.then(module =& cb(null, module.default))
path: 'artists/:id',
getComponent(location, cb) {
System.import('./components/artists/ArtistDetail')
.then(module =& cb(null, module.default))
const Routes = () =& {
&Router history={hashHistory} routes={rootRoute} /&
export default R
&/code&&/pre&&/div&&p&然后执行 build 命令,可以发现我们的 bundle 文件又瘦身了,并且新增了几个文件&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-fa3abeac823_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&638& data-rawheight=&196& class=&origin_image zh-lightbox-thumb& width=&638& data-original=&https://pic4.zhimg.com/v2-fa3abeac823_r.jpg&&&/figure&&p&&br&&/p&&p&将 HTML 文件在浏览器中打开,当点击路由跳转时,可以在开发者工具中的 Network 一栏中看到加载了一个 JS 文件。&/p&&p&首页&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-8e63dc8a303dc600e8f5_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&512& data-rawheight=&291& class=&origin_image zh-lightbox-thumb& width=&512& data-original=&https://pic2.zhimg.com/v2-8e63dc8a303dc600e8f5_r.jpg&&&/figure&&p&&br&&/p&&p&点击右上角 Random Artist 以后&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-b1e8ab9832f92aab35ca9dea119e4f17_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&504& data-rawheight=&298& class=&origin_image zh-lightbox-thumb& width=&504& data-original=&https://pic4.zhimg.com/v2-b1e8ab9832f92aab35ca9dea119e4f17_r.jpg&&&/figure&&p&&br&&/p&&h2&自动刷新&/h2&&p&每次更新代码都需要执行依次 build,并且还要等上一会很麻烦,这一小节介绍如何使用自动刷新的功能。&/p&&p&首先安装插件&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm i --save-dev webpack-dev-server
&/code&&/pre&&/div&&p&然后修改 packet.json 文件&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&scripts&: {
&build&: &webpack&,
&dev&: &webpack-dev-server --open&
&/code&&/pre&&/div&&p&现在直接执行 npm run dev 可以发现浏览器自动打开了一个空的页面,并且在命令行中也多了新的输出&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-97e556d2f5c668f9f1ff46ecabf09138_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&643& data-rawheight=&135& class=&origin_image zh-lightbox-thumb& width=&643& data-original=&https://pic1.zhimg.com/v2-97e556d2f5c668f9f1ff46ecabf09138_r.jpg&&&/figure&&p&&br&&/p&&p&等待编译完成以后,修改 JS 或者 CSS 文件,可以发现 webpack 自动帮我们完成了编译,并且只更新了需要更新的代码&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-80c583ecf928d605cc2d6e0ea5e521b3_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&634& data-rawheight=&241& class=&origin_image zh-lightbox-thumb& width=&634& data-original=&https://pic4.zhimg.com/v2-80c583ecf928d605cc2d6e0ea5e521b3_r.jpg&&&/figure&&p&&br&&/p&&p&但是每次重新刷新页面对于 debug 来说很不友好,这时候就需要用到模块热替换了。但是因为项目中使用了 React,并且 Vue 或者其他框架都有自己的一套 hot-loader,所以这里就略过了,有兴趣的可以自己学习下。&/p&&h2&生成生产环境代码&/h2&&p&现在我们可以将之前所学和一些新加的插件整合在一起,build 生产环境代码。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm i --save-dev url-loader optimize-css-assets-webpack-plugin file-loader extract-text-webpack-plugin
&/code&&/pre&&/div&&p&修改 webpack 配置&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin')
var CleanWebpackPlugin = require('clean-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const VENOR = [&faker&,
&react-dom&,
&react-input-range&,
&react-redux&,
&redux-form&,
&redux-thunk&,
&react-router&
module.exports = {
bundle: './src/index.js',
vendor: VENOR
// 如果想修改 webpack-dev-server 配置,在这个对象里面修改
devServer: {
port: 8081
path: path.join(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
test: /\.js$/,
use: 'babel-loader'
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[hash:7].[ext]'
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
// 这边其实还可以使用 postcss 先处理下 CSS 代码
loader: 'css-loader'
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor', 'manifest'],
minChunks: Infinity
new CleanWebpackPlugin(['dist/*.js'], {
verbose: true,
dry: false
new HtmlWebpackPlugin({
template: 'index.html'
// 生成全局变量
new webpack.DefinePlugin({
&process.env.NODE_ENV&: JSON.stringify(&process.env.NODE_ENV&)
// 分离 CSS 代码
new ExtractTextPlugin(&css/[name].[contenthash].css&),
// 压缩提取出的 CSS,并解决ExtractTextPlugin分离出的 JS 重复问题
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
// 压缩 JS 代码
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
&/code&&/pre&&/div&&p&修改 packet.json 文件&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&scripts&: {
&build&: &NODE_ENV=production webpack -p&,
&dev&: &webpack-dev-server --open&
&/code&&/pre&&/div&&p&执行 npm run build&/p&&figure&&img src=&https://pic1.zhimg.com/v2-b60b0d4caa6a2fc4ed28b8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&797& data-rawheight=&206& class=&origin_image zh-lightbox-thumb& width=&797& data-original=&https://pic1.zhimg.com/v2-b60b0d4caa6a2fc4ed28b8_r.jpg&&&/figure&&p&&br&&/p&&p&可以看到我们在经历了这么多步以后,将 bundle 缩小到了只有 27.1KB,像 vendor 这种常用的库我们一般可以使用 CDN 的方式外链进来。&/p&&h2&补充&/h2&&p&webpack 配置上有些实用的小点在上文没有提到,统一在这里提一下。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&module.exports = {
resolve: {
// 文件扩展名,写明以后就不需要每个文件写后缀
extensions: ['.js', '.css', '.json'],
// 路径别名,比如这里可以使用 css 指向 static/css 路径
'@': resolve('src'),
'css': resolve('static/css')
// 生成 source-map,用于打断点,这里有好几个选项
devtool: '#cheap-module-eval-source-map',
&/code&&/pre&&/div&&h2&后记&/h2&&p&如果你是跟着本文一个个步骤敲下来的,那么大部分的 webpack 配置你应该都是可以看懂了,并且自己应该也知道如何去配置。谢谢大家看到这里,&a href=&http://link.zhihu.com/?target=https%3A//link.juejin.im/%3Ftarget%3Dhttps%253A%252F%252Fgithub.com%252FKieSun%252Fwebpack-demo& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&这是本项目对应的仓库&/a&,每个小节基本都对应了一次 commit。&/p&&p&文章较长,有错误也难免,如果你发现了任何问题或者我有任何表述的不明白的地方,都可以留言给我。&/p&&p&—————————end———————————&/p&&p&&br&&/p&&p&加饥人谷官方微信号: hungervalley ,暗号:来自知乎&/p&&p&每日一题,每周资源推荐,精彩博客推荐,工作、笔试、面试经验交流解答,免费直播课,群友轻分享... 数不尽的福利免费送&/p&
本文原载于,作者(饥人谷学员),转载已获作者授权。该文使用的 Webpack 版本为 3.6.0,本文分两部分。第一步是简单的使用 webpack,第二部分通过一个真实项目来配置 webpack,没有使用任何的 CLI,都是一步步配置直到完成生产代码的打包。
学过的东西杂而不精,算不得大牛。带过前端团队,也算是有几年前端负责人的经验。&br&随着这几年前端node.js,react,Angularjs等技术新起,越来越多从之前单纯的前端开发到前端全栈开发,技术之多,之有趣,前端实在是繁华得很。&br&但是目前大多数情况下的前端开发,主要还是在web开发上,所使用的技术无非就是html,css,javascript。所以我觉得这个基础是很有必要的,把html,css,javascript学精通,已经是小神级别(我就很羡慕那些可以写一手好看的js的前端工程师)。&br&进入下一个阶段,优化!不管是前端,后端,任何一个技术方向,都实现功能,好的代码结构,接下来就是优化。你需要开始考虑页面的加载速度,代码压缩,图片压缩,dom节点的加载顺序,你会发现进入了新的境地。&br&&br&作为前端负责人:&br&1 前端开发的能力&br&2 技术选型&br&3 管理团队&br&4 前端团队文化塑造&br&&br&本回答只从技术角度阐述。&br&前端开发的能力,把html,css,javascript学好,你已经没有问题啦。&br&技术的选型,这对负责人的前端技术视野,甚至后端技术也有要求,还需要考虑团队的整体技术能力。&br&&br&转一个资源汇总,对技术视野或有帮助(转自 &a href=&//link.zhihu.com/?target=http%3A//cnodejs.org/topic/56ef3edda99d00e& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端资源教程&/a& 侵权删)&br&-----------————————————————————————&br&感谢知友,有好的前端内容告知我一下,列表持续更新&br&&br&&ol&&li&&p&综合类&/p&&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.cnblogs.com/sb/p/3894452.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端知识体系&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/JacksonTian/fks& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端知识结构&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/unruledboy/WebFrontEndStack& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Web前端开发大系概览&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.cnblogs.com/unruledboy/p/WebFrontEndStack.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Web前端开发大系概览-中文版&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//raw.githubusercontent.com/unruledboy/WebFrontEndStack/master/Web%2520Front%2520End%2520Stack.png& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Web Front-end Stack v2.2&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/justjavac/free-programming-books-zh_CN& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&免费的编程中文书籍索引&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/dypsilon/frontend-dev-bookmarks& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端书籍&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/vhf/free-programming-books& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端免费书籍大全&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.cnblogs.com/sb/p/3894452.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端知识体系&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/justjavac/free-programming-books-zh_CN& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&免费的编程中文书籍索引&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//study.163.com/course/introduction/224014.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&智能社 - 精通JavaScript开发&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&重新介绍 JavaScript(JS 教程)&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//v.163.com/special/opencourse/bianchengdaolun.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&麻省理工学院公开课:计算机科学及编程导论&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//segmentfault.com/a/0298& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JavaScript中的this陷阱的最全收集–没有之一&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/ch1.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JS函数式编程指南&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//liubin.github.io/promises-book/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JavaScript Promise迷你书(中文版)&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/AlloyTeam/Mars& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&腾讯移动Web前端知识库&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/Front-End-Developers-Hunan/Front-End-Develop-Guide& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Front-End-Develop-Guide 前端开发指南&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//li-xinyang.gitbooks.io/frontend-notebook/content/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端开发笔记本&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/nieweidong/fetool& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&大前端工具集 - 聂微东&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//dwqs.gitbooks.io/frontenddevhandbook/content/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端开发者手册&/a&&/li&&/ul&&/li&&li&&p&入门类&/p&&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.cnblogs.com/jikey/p/3613082.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端入门教程&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.liaoxuefeng.com/wiki/867bd51a89c25cc8b43bdb3000& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&瘳雪峰的Javascript教程&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/view/11& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&jQuery基础教程&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/view/506& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&前端工程师必备的PS技能——切图篇&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/qiu-deqing/FE-learning& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&结合个人经历总结的前端入门方法&/a&&/li&&/ul&&/li&&li&&p&效果类&/p&&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/learn/58& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&弹出层&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/learn/18& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&焦点图轮播特效&/a&&/li&&/ul&&/li&&li&&p&工具类&/p&&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/learn/93& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&css sprite 雪碧图制作&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/learn/390& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&版本控制入门 – 搬进 Github&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/learn/30& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Grunt-beginner前端自动化工具&/a&&/li&&/ul&&/li&&li&&p&慕课专题&/p&&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.gongchengketang.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&最体系最负责的前端在线教学网站&/a&&br&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/space/teacher/id/197450& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&张鑫旭 - 慕课系列&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/space/teacher/id/104593& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&lyn - 慕课系列&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/space/teacher/id/290139& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&艾伦 - 慕课系列&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.imooc.com/view/494& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&碧仔 - Hello,移动WEB&/a&&/li&&/ul&&/li&&li&&p&周报类&/p&&ul&&li&&a href=&//link.zhihu.com/?target=https%3A//github.com/PaicHyperionDev/MobileDevWeekly& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&平安科技移动开发二队技术周报&/a&&/li&&/ul&&/li&&/ol&六. API:1. 总目录&ol&&li&&p&开发中心&/p&&ul&&li&&a href=&//link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/JavaScript& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&mozilla js参考&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//developer.chrome.com/extensions/api_index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&chrome开发中心(chrome的内核已转向blink)&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//developer.apple.com/library/safari/navigation& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&safari开发中心&/a&&/li&&li&&a href=&//link.zhihu.com/?target=https%3A//msdn.microsoft.com/zh-cn/library/d1et7k7c%28v%3Dvs.94%29.aspx& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&microsoft js参考&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//sanshi.me/articles/JavaScript-Garden-CN/html/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&js秘密花园&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//bonsaiden.github.io/JavaScript-Garden/zh/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&js秘密花园&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//www.w3help.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&w3help&/a& 综合Bug集合网站&/li&&/ul&&/li&&li&&p&综合搜索&/p&&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.javascripting.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&javascripting&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//microjs.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&各种流行库搜索&/a&&/li&&/ul&&/li&&li&&p&综合API&/p&&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.runoob.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&runoob.com-包含各种API集合&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//tool.oschina.net/apidocs& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&开源中国在线API文档合集&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3A//devdocs.io/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&devdocs&/a& 英文综合API网站&/li&&/ul&&/li&&/ol&2. jQuery&ul&&li&&a href=&//link.zhihu.com/?target=http%3A//www.jquery123.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&jQuery API 中文文档&/a&&/li&&li&&a href=&//link.zhihu.com/?target=http%3

我要回帖

更多关于 ppt跳转到指定页 的文章

 

随机推荐