-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
93 lines (62 loc) · 32.9 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>熊乐写字的地方</title>
<link href="/atom.xml" rel="self"/>
<link href="https://tracyxiong1.github.io/"/>
<updated>2018-06-10T08:34:46.783Z</updated>
<id>https://tracyxiong1.github.io/</id>
<author>
<name>tracyxiong1</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>minipack 源码解析</title>
<link href="https://tracyxiong1.github.io/2018/06/09/minipack-%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/"/>
<id>https://tracyxiong1.github.io/2018/06/09/minipack-源码解析/</id>
<published>2018-06-09T09:30:33.000Z</published>
<updated>2018-06-10T08:34:46.783Z</updated>
<content type="html"><![CDATA[<h1 id="minipack-是什么"><a href="#minipack-是什么" class="headerlink" title="minipack 是什么"></a>minipack 是什么</h1><blockquote><p> A simplified example of a modern module bundler written in JavaScript</p></blockquote><p>正如 <a href="https://github.com/ronami/minipack" target="_blank" rel="noopener">github</a> 介绍,这是一个用 JavaScript 编写的现代模块构建工具的简化示例。</p><p>作为一名 FE, 平时可能会使用 Webpack/Browserify/Rollup/Parcel 等构建工具。了解这些构建工具的工作原理可以帮助我们更好地决定编写代码的方式,所以了解他们的工作原理还是很有必要的。</p><p>本文将围绕 minipack 的源码来分析如何实现一个 module bundlers.</p><a id="more"></a><h2 id="module-bundlers"><a href="#module-bundlers" class="headerlink" title="module bundlers"></a>module bundlers</h2><p>module bundlers 将小块代码编译成更大和更复杂的代码,让其运行在 Web 浏览器中。 它拥有入口文件的概念,我们让 module bundlers 知道哪个文件是我们应用程序的入口文件,然后让 module bundlers 从该文件开始,并去尝试理解它依赖哪些文件,然后它会尝试了解这些文件的依赖关系,直到它发现应用程序中的每个模块,以及它们如何相互依赖,最后构成 dependenciesGraph(依赖图).</p><h2 id="源码解析"><a href="#源码解析" class="headerlink" title="源码解析"></a>源码解析</h2><p>代码主要有三个重要方法</p><h3 id="createAsset"><a href="#createAsset" class="headerlink" title="createAsset"></a>createAsset</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 该方法接受文件路径, 读取内容并提取它的依赖关系</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createAsset</span>(<span class="params">filename</span>) </span>{</span><br><span class="line"> <span class="comment">// 以字符串形式读取文件的内容</span></span><br><span class="line"> <span class="keyword">const</span> content = fs.readFileSync(filename, <span class="string">'utf-8'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 使用 babylon 转换我们的原始代码,转换之后生成抽象语法树(AST)</span></span><br><span class="line"> <span class="comment">// babylon 的介绍可以参考 https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md#toc-babylon</span></span><br><span class="line"> <span class="comment">// 如果对 AST 不太了解,可以通过 https://astexplorer.net/ 查看生成的 AST 代码是怎样的</span></span><br><span class="line"> <span class="keyword">const</span> ast = babylon.parse(content, {</span><br><span class="line"> sourceType: <span class="string">'module'</span>,</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 当我们解析完以后,我们就可以提取当前文件中的 dependencies</span></span><br><span class="line"> <span class="comment">// dependencies 翻译为依赖,也就是我们文件中所有的 `import xxxx from xxxx`</span></span><br><span class="line"> <span class="comment">// 我们将这些依赖都放在 dependencies 的数组里面,这个数组将保存这个模块依赖的模块的相对路径</span></span><br><span class="line"> <span class="keyword">const</span> dependencies = [];</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 使用 babel-traverse 遍历 AST,babel-traverse 的介绍可以参考 https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md#toc-babel-traverse</span></span><br><span class="line"> traverse(ast, {</span><br><span class="line"> <span class="comment">// 当遍历到类型为 `ImportDeclaration` 的 AST 节点,其实就是我们的 `import xxx from xxx.js`</span></span><br><span class="line"> ImportDeclaration: <span class="function">(<span class="params">{node}</span>) =></span> {</span><br><span class="line"> <span class="comment">// 将匹配到的模块路径 push 到 dependencies</span></span><br><span class="line"> dependencies.push(node.source.value);</span><br><span class="line"> },</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 递增简单计数器为此模块分配唯一标识符</span></span><br><span class="line"> <span class="keyword">const</span> id = ID++;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// es6 module 以及 es6 语法无法兼容所有浏览器</span></span><br><span class="line"> <span class="comment">// 为了确保 bundle 能在所有的浏览器种运行,使用 babel 进行编译,转换成 CommonJS 代码</span></span><br><span class="line"> <span class="comment">// 使用 babel-preset-env 确定需要支持的浏览器</span></span><br><span class="line"> <span class="keyword">const</span> {code} = transformFromAst(ast, <span class="literal">null</span>, {</span><br><span class="line"> presets: [<span class="string">'env'</span>],</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 最后将模块导出</span></span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> id,</span><br><span class="line"> filename,</span><br><span class="line"> dependencies,</span><br><span class="line"> code,</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="createGraph"><a href="#createGraph" class="headerlink" title="createGraph"></a>createGraph</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 该方法接收入口文件的文件路径,获取整个应用程序的每个模块的依赖关系,可以把它抽象理解为依赖图</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createGraph</span>(<span class="params">entry</span>) </span>{</span><br><span class="line"> <span class="comment">// 首先解析入口文件,获取入口模块的信息</span></span><br><span class="line"> <span class="keyword">const</span> mainAsset = createAsset(entry);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> queue = [mainAsset];</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 使用一个`for ... of`循环遍历 queue</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> asset <span class="keyword">of</span> queue) {</span><br><span class="line"><span class="comment">// 子模块的依赖关系</span></span><br><span class="line"> asset.mapping = {};</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> dirname = path.dirname(asset.filename);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 遍历依赖的模块</span></span><br><span class="line"> asset.dependencies.forEach(<span class="function"><span class="params">relativePath</span> =></span> {</span><br><span class="line"> <span class="comment">// 转换成绝对路径</span></span><br><span class="line"> <span class="keyword">const</span> absolutePath = path.join(dirname, relativePath);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析依赖</span></span><br><span class="line"> <span class="keyword">const</span> child = createAsset(absolutePath);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 供后期 require ${id} 使用</span></span><br><span class="line"> asset.mapping[relativePath] = child.id;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将解析的依赖 push 到 queue 中</span></span><br><span class="line"> queue.push(child);</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 最后将 queue 返回,包含了目标应用中每个 module 的信息</span></span><br><span class="line"> <span class="keyword">return</span> queue;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="bundle"><a href="#bundle" class="headerlink" title="bundle"></a>bundle</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 该方法将 graph 加工成浏览器中可执行代码</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bundle</span>(<span class="params">graph</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> modules = <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在我们到达该函数的主体之前,我们将构建一个作为该函数的参数的对象</span></span><br><span class="line"> <span class="comment">// 请注意, 我们构建的这个字符串被两个花括号 ({}) 包裹, 因此对于每个模块,</span></span><br><span class="line"> <span class="comment">// 我们添加一个这种格式的字符串: `key: value,`</span></span><br><span class="line"> graph.forEach(<span class="function"><span class="params">mod</span> =></span> {</span><br><span class="line"> <span class="comment">// 图表中的每个模块在这个对象中都有一个`entry`. 我们使用`模块的id`作为`key`和一个数组作为`value` (用数组因为我们在每个模块中有2个值)</span></span><br><span class="line"> <span class="comment">// 第一个值是用函数包装的每个模块的代码. 这是因为模块应该被 限定范围: 在一个模块中定义变量不会影响 其他模块 或 全局范围</span></span><br><span class="line"> <span class="comment">// 我们的模块在我们将它们`转换{被 babel 转译}`后, 使用`commonjs`模块系统: 他们期望一个`require`, 一个`module`和`exports`对象可用. 那些在浏览器中通常不可用,所以我们将它们实现并将它们注入到函数包装中</span></span><br><span class="line"> <span class="comment">// 对于第二个值,我们用`stringify`解析模块及其依赖之间的关系(也就是上文的asset.mapping). 解析后的对象看起来像这样: `{'./relative/path': 1}`</span></span><br><span class="line"> <span class="comment">// 这是因为我们模块的被转换后会通过相对路径来调用`require()`. 当调用这个函数时,我们应该能够知道依赖图中的哪个模块对应于该模块的相对路径</span></span><br><span class="line"> modules += <span class="string">`<span class="subst">${mod.id}</span>: [</span></span><br><span class="line"><span class="string"> function (require, module, exports) { <span class="subst">${mod.code}</span> },</span></span><br><span class="line"><span class="string"> <span class="subst">${<span class="built_in">JSON</span>.stringify(mod.mapping)}</span>,</span></span><br><span class="line"><span class="string"> ],`</span>;</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 这一段代码实际上才是模块引入的核心逻辑</span></span><br><span class="line"> <span class="comment">// 我们制造一个顶层的 require 函数,这个函数接收一个 id 作为值,并且返回一个全新的 module 对象</span></span><br><span class="line"> <span class="comment">// 我们倒入我们刚刚制作好的模块,给他加上 {},使其成为 {1:[...],2:[...]} 这样一个完整的形式</span></span><br><span class="line"> <span class="comment">// 然后塞入我们的立即执行函数中(function(modules) {...})()</span></span><br><span class="line"> <span class="comment">// 在 (function(modules) {...})() 中,我们先调用 require(0)</span></span><br><span class="line"> <span class="comment">// 理由很简单,因为我们的主模块永远是排在第一位的</span></span><br><span class="line"> <span class="comment">// 紧接着,在我们的 require 函数中,我们拿到外部传进来的 modules,利用我们一直在说的全局数字 id 获取我们的模块</span></span><br><span class="line"> <span class="comment">// 每个模块获取出来的就是一个二维元组</span></span><br><span class="line"> <span class="comment">// 然后,我们要制造一个 `子require`</span></span><br><span class="line"> <span class="comment">// 这么做的原因是我们在文件中使用 require 时,我们一般 require 的是地址,而顶层的 require 函数参数时 id</span></span><br><span class="line"> <span class="comment">// 不要担心,我们之前的 idMapping 在这里就用上了,通过用户 require 进来的地址,在 idMapping 中找到 id</span></span><br><span class="line"> <span class="comment">// 然后递归调用 require(id),就能够实现模块的自动倒入了</span></span><br><span class="line"> <span class="comment">// 接下来制造一个 const newModule = {exports: {}};</span></span><br><span class="line"> <span class="comment">// 运行我们的函数 fn(childRequire, newModule, newModule.exports);,将应该丢进去的丢进去</span></span><br><span class="line"> <span class="comment">// 最后 return newModule.exports 这个模块的 exports 对象</span></span><br><span class="line"> <span class="keyword">const</span> result = <span class="string">`</span></span><br><span class="line"><span class="string"> (function(modules) {</span></span><br><span class="line"><span class="string"> function require(id) {</span></span><br><span class="line"><span class="string"> const [fn, mapping] = modules[id];</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> function localRequire(name) {</span></span><br><span class="line"><span class="string"> return require(mapping[name]);</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> const module = { exports : {} };</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> fn(localRequire, module, module.exports);</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> return module.exports;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> require(0);</span></span><br><span class="line"><span class="string"> })({<span class="subst">${modules}</span>})</span></span><br><span class="line"><span class="string"> `</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>回过头来看,思路还是比较清晰的,主要分为两步:</p><ol><li>通过 babel 以及 babel 插件,分析、收集依赖,得到整个程序的依赖图</li><li>实现一个 loader, 用于 require module</li></ol><p>这是一个简化的构建工具设计流程,例子中还有一些问题尚未处理,比如只支持 es6 模块收集,无法兼容 CommonJS/CMD/AMD 模块; 模块引用路径必须写后缀名等问题。需要优化的地方还有很多,感兴趣的同学可以 fork 该项目完善。</p><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="https://github.com/chinanf-boy/minipack-explain/blob/master/src/minipack.js" target="_blank" rel="noopener">minipack-explain</a></p>]]></content>
<summary type="html">
<h1 id="minipack-是什么"><a href="#minipack-是什么" class="headerlink" title="minipack 是什么"></a>minipack 是什么</h1><blockquote>
<p> A simplified example of a modern module bundler written in JavaScript</p>
</blockquote>
<p>正如 <a href="https://github.com/ronami/minipack" target="_blank" rel="noopener">github</a> 介绍,这是一个用 JavaScript 编写的现代模块构建工具的简化示例。</p>
<p>作为一名 FE, 平时可能会使用 Webpack/Browserify/Rollup/Parcel 等构建工具。了解这些构建工具的工作原理可以帮助我们更好地决定编写代码的方式,所以了解他们的工作原理还是很有必要的。</p>
<p>本文将围绕 minipack 的源码来分析如何实现一个 module bundlers.</p>
</summary>
<category term="源码解析" scheme="https://tracyxiong1.github.io/tags/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/"/>
</entry>
<entry>
<title>记一次微信小程序开发过程</title>
<link href="https://tracyxiong1.github.io/2018/04/30/%E8%AE%B0%E4%B8%80%E6%AC%A1%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91%E8%BF%87%E7%A8%8B/"/>
<id>https://tracyxiong1.github.io/2018/04/30/记一次微信小程序开发过程/</id>
<published>2018-04-30T07:00:45.000Z</published>
<updated>2018-05-07T10:18:11.618Z</updated>
<content type="html"><![CDATA[<h1 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h1><p>最近闲来无事,花时间捣鼓了一下微信小程序。<br>微信小程序是个什么东东呢?看看官方对小程序的定义: </p><blockquote><p>微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。</p></blockquote><p>有几个词比较关键了:全新的方式、出色的用户体验。工程师的好奇心驱动,小程序和传统的 web 页有什么不一样可以达到这种效果呢?技术上如何实现呢?小程序究竟是 web 还是 native?带着诸多问题,开始了小程序的探索之旅。</p><a id="more"></a><h1 id="开发一个小程序"><a href="#开发一个小程序" class="headerlink" title="开发一个小程序"></a>开发一个小程序</h1><p>要想明白小程序到底是个什么东东,咱先动手开发一个小程序。开发步骤按照<a href="https://developers.weixin.qq.com/miniprogram/dev/index.html?t=2018413" target="_blank" rel="noopener">官方文档</a>说明操作即可,这里简单罗列下步骤。</p><h2 id="开发步骤"><a href="#开发步骤" class="headerlink" title="开发步骤"></a>开发步骤</h2><ol><li>申请账号, 点击 <a href="https://mp.weixin.qq.com/wxopen/waregister?action=step1" target="_blank" rel="noopener">https://mp.weixin.qq.com/wxopen/waregister?action=step1</a> 根据指引填写信息和提交相应的资料,注册自己的小程序帐号;</li><li>获取 AppId, 用自己的账号登录小程序后台管理平台,然后在菜单 “设置”-“开发设置” 中可以查看;</li><li>安装开发工具,前往 <a href="https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html?t=201853" target="_blank" rel="noopener">开发者工具下载页面</a>;</li><li>打开微信开发工具,创建项目,编码。 </li></ol><p>步骤比较粗略,如果不太明白的可以参照<a href="https://developers.weixin.qq.com/miniprogram/dev/index.html?t=2018413" target="_blank" rel="noopener">官方文档</a>, 图文并茂,非常详细。</p><h2 id="代码构成"><a href="#代码构成" class="headerlink" title="代码构成"></a>代码构成</h2><p>小程序包含了几种类型的文件:</p><ul><li>.json 后缀的 JSON 配置文件,如 app.json/project.config.json/page.json, 根据命名大致能猜到他们的作用,分别用于配置小程序、开发工具、页面配置</li><li>.wxml 后缀的 WXML 模板文件,可以简单理解为 web 开发中的 html, 他们定位很类似,都是用于表示页面的结构,但是在语法上还是有些不同,在写 html 的时候会经常用到 div/span, 但是在 wxml 中就没有这些标签,而是小程序官方提供的 view/text 等</li><li>.wxss 后缀的 WXSS 样式文件,可以简单理解为 web 开发中的 css, 都是用于描述元素样式,但是还是有一些不同需要注意:1) wxss 只支持部分 css 选择器;2) wxss 提供了新的单位 rpx, 该单位可以根据屏幕宽度进行自适应</li><li>.js 后缀的 JS 脚本逻辑文件,可以理解为 web 开发中 javascript, 基本一样,没有太大不同</li></ul><h2 id="Code-阶段"><a href="#Code-阶段" class="headerlink" title="Code 阶段"></a>Code 阶段</h2><p>明白了小程序代码结构之后说干就干,第一个小程序选择了天气预报这样一个简单实用的产品,code 前需要解决两个问题:</p><ol><li>产品/UI 设计,这块借鉴了主流天气 APP 的 UI,没有遇到太大问题;</li><li>数据接口,这块图快、省事,就没自己单独写 API 接口,调用的第三方接口,这块需要注意的是将自己请求的接口在小程序管理后台 - 开发设置 - 服务器域名进行配置,不然无法发送请求。<br>解决 UI 和接口的问题之后就可以愉快地写代码了,开发体验和主流的 MV* 框架差不多,数据驱动,通过数据响应式修改页面 UI, 之前有 react native/vue/react 开发经验,上手还是很快的,不过这块需要注意的是需要熟悉官方提供的组件和 API, 不能想当然的去使用 div/span,开发过程中可以使用开发者工具提供的预览功能,在真机上调试,真机上可以开启 debug 模式,开启之后会有一个 <a href="https://github.com/Tencent/vConsole" target="_blank" rel="noopener">vConsole</a>, 方便调试。</li></ol><p>完成之后的效果图。<br><img src="/2018/04/30/记一次微信小程序开发过程/screenshot.jpeg" alt="小程序截图"><br>这里就不展开如何写代码了,已经将这个项目的代码开源,托管于 <a href="https://github.com/tracyxiong1/cola-weather" target="_blank" rel="noopener">github</a> 上,感兴趣的同学可以在 <a href="https://github.com/tracyxiong1/cola-weather" target="_blank" rel="noopener">github</a> 上查看。</p><h2 id="上线"><a href="#上线" class="headerlink" title="上线"></a>上线</h2><p>步骤如下:</p><ol><li>使用开发者工具上传代码,然后填写版本号以及项目备注;</li><li>上传成功后,登录小程序管理后台 - “开发管理” - “开发版本” 就可以找到刚提交上传的版本;</li><li>选择你提交的版本提交审核,审核还是比较快的(有可能我的小程序比较简单,几个小时就好了);</li><li>审核通过后,点击发布即可。</li></ol><p>上线后的小程序二维码,可以体验下。<br><img src="/2018/04/30/记一次微信小程序开发过程/qrcode.jpg" alt="小程序二维码"></p><h2 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h2><p>可以在小程序管理后台中查看运营数据,进行相应优化。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>体验了从 0 到 1 开发小程序之后,有一些感想:</p><ol><li>开发门槛低,对开发者友好,简单易上手,开发成本低;</li><li>用户体验不错,相较于 wap 页面拥有更流畅的体验,几乎和 native 体验差不多(iOS上的开发体验),加载速度快; </li></ol><p>总的来说,小程序结合了 native 和 wap 的优点,还是大有可为的。”授人以鱼不如授人以渔“,后面再花时间专门介绍小程序的底层实现。</p>]]></content>
<summary type="html">
<h1 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h1><p>最近闲来无事,花时间捣鼓了一下微信小程序。<br>微信小程序是个什么东东呢?看看官方对小程序的定义: </p>
<blockquote>
<p>微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。</p>
</blockquote>
<p>有几个词比较关键了:全新的方式、出色的用户体验。工程师的好奇心驱动,小程序和传统的 web 页有什么不一样可以达到这种效果呢?技术上如何实现呢?小程序究竟是 web 还是 native?带着诸多问题,开始了小程序的探索之旅。</p>
</summary>
<category term="小程序" scheme="https://tracyxiong1.github.io/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
</entry>
<entry>
<title>写在开始</title>
<link href="https://tracyxiong1.github.io/2018/03/28/%E5%86%99%E5%9C%A8%E5%BC%80%E5%A7%8B/"/>
<id>https://tracyxiong1.github.io/2018/03/28/写在开始/</id>
<published>2018-03-28T11:22:06.000Z</published>
<updated>2018-05-07T10:17:06.055Z</updated>
<content type="html"><![CDATA[<p>时间过得挺快,一转眼参加工作将近三年了。<br>说来惭愧,大学时期的博客在参加工作后就很少更新了,不更新的原因总结下来一个字:懒。现在回想,大学时期驱动我写博客主要来自:</p><ol><li>巩固基础知识</li><li>研究新事物并将其记录下来,防止以后忘记</li><li>内心的成就感</li></ol><a id="more"></a><p>那段写博客的经历对我来说,确实产生一些比较实质性的回报:较同时期的同学前端基础更扎实,更宽阔的视野,校招拿到更多的 offer,拥有更多的选择权,内心得到无与伦比的充实感、愉悦,每天都过得很开心。<br>不过现在写博客的驱动力似乎和之前发生了变化,现在的我更期望有一个地方能将平时自己的思考记录下来。虽然平时自己想了很多东西,但是很多时候因为自己可能只是想想,后来并没有足够的动力去加以实践、贯彻、落实,过了一段时间再回顾,就会产生一种感觉:为什么当时没有将这些东西坚持下去,然后留给自己一丝愧疚和挫败感。<br>其实可以提供写字的平台有很多,微信、微博相对来说比较生活,不太适合发这种东西,知乎、简书太喧闹、公开,我更期望选择一个相对来说比较「安静」「舒适」的地方来记录这些东西,写一点自己想写的东西,记录一下自己心路历程、感想、技术分享&发现。</p>]]></content>
<summary type="html">
<p>时间过得挺快,一转眼参加工作将近三年了。<br>说来惭愧,大学时期的博客在参加工作后就很少更新了,不更新的原因总结下来一个字:懒。现在回想,大学时期驱动我写博客主要来自:</p>
<ol>
<li>巩固基础知识</li>
<li>研究新事物并将其记录下来,防止以后忘记</li>
<li>内心的成就感</li>
</ol>
</summary>
<category term="感想" scheme="https://tracyxiong1.github.io/tags/%E6%84%9F%E6%83%B3/"/>
</entry>
</feed>