<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Allen 的个人博客</title>
    <link>https://blog.helloallen.cn/</link>
    
    <atom:link href="https://blog.helloallen.cn/rss.xml" rel="self" type="application/rss+xml"/>
    
    <description>Allen 的个人博客，记录 AI 技术实践、独立开发、SaaS 出海、一人公司、产品开发与个人成长。</description>
    <pubDate>Fri, 28 Aug 2026 10:22:53 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>Python一键下载公众号所有文章，导出文件支持PDF，HTML，Markdown，Excel，chm等格式</title>
      <link>https://blog.helloallen.cn/ba4eb63d/</link>
      <guid>https://blog.helloallen.cn/ba4eb63d/</guid>
      <pubDate>Thu, 08 Aug 2024 09:48:12 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>今天分享的是用Python一键备份某个公众号的所有文章，原理就是通过抓包抓取微信客户端的接口，用Python请求微信接口获取公众号文章链接再下载。</p><h2 id="1-charles-抓包"><a href="#1-charles-抓包" class="headerlink" title="1. charles 抓包"></a>1. charles 抓包</h2><p>常见的抓包工具有Fiddler，charles，这里用的charles，先去<a href="https://www.charlesproxy.com/download">官网</a> 下载软件,然后打开微信客户端找到公众号，进入文章列表可以看到发过的文章。<br><img src="https://upload-images.jianshu.io/upload_images/23152173-91217817ab889f5d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"></p><p>不过charles没安装证书前获取不到https接口数据，显示unknown。<br><img src="https://upload-images.jianshu.io/upload_images/23152173-d6323050d5a76412.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><br>安装证书后在 proxy-&gt;ssl proxying settings 添加域名和host 。<br><img src="https://upload-images.jianshu.io/upload_images/23152173-f12ade2adea0aaf2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><br>再次抓取可以看到公众号文章接口数据了。</p><p><img src="https://upload-images.jianshu.io/upload_images/23152173-bc7af8b0553b9c8d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"></p><p>公众号文章的接口地址 <code>https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&amp;__biz=MjM5ODIzNDEx&amp;f=json&amp;offset=25&amp;count=10&amp;is_ok=1&amp;scene=124&amp;uin=MTU0MTQzNj&amp;key=f57423</code>，参数比较多，其中有用的参数 __biz 是用户和公众号之间的唯一id，uin是用户的id，这个是不变的，key 是请求的秘钥，一段时间就会失效，offset 是偏移量，count 是每次请求的条数，返回值结构如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">&quot;ret&quot;: 0,</span><br><span class="line">&quot;errmsg&quot;: &quot;ok&quot;,</span><br><span class="line">&quot;msg_count&quot;: 10,信息条数</span><br><span class="line">&quot;can_msg_continue&quot;: 1,是否还可以继续获取，1代表可以。0代表不可以，也就是最后一页</span><br><span class="line">&quot;general_msg_list&quot;: &quot;&#123;\&quot;list\&quot;:[&#123;\&quot;comm_msg_info\&quot;:&#123;\&quot;id\&quot;:1000000182,\&quot;type\&quot;:49,\&quot;datetime\&quot;:1585702800,\&quot;fakeid\&quot;:\&quot;2398234112\&quot;,\&quot;status\&quot;:2,\&quot;content\&quot;:\&quot;\&quot;&#125;,\&quot;app_msg_ext_info\&quot;:&#123;\&quot;title\&quot;:\&quot;张国荣音乐\/演唱会\/电影全集网盘分享\&quot;,\&quot;digest\&quot;:\&quot;#17宠爱张国荣#\&quot;,\&quot;content\&quot;:\&quot;\&quot;,\&quot;fileid\&quot;:0,\&quot;content_url\&quot;:\&quot;http:\/\/mp.weixin.qq.com\/s?__biz=MjM5ODIzNDExMg==&amp;amp;mid=2257484715&amp;amp;idx=1&amp;amp;sn=2fab0a11d62090d5e30e03e334bce636&amp;amp;chksm=a5b70ac492c083d275b6e15f0de85b8baf488ebb76e5429b08f40cdc53ab6e27b0ce5474fb30&amp;amp;scene=27#wechat_redirect\&quot;,\&quot;source_url\&quot;:\&quot;\&quot;,\&quot;cover\&quot;:\&quot;http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/pchiblEh3tErdgYu06FFVuvnKr9aAkddJLB7pgNhaiav0aYGQKJI0Dwn0kpT4wnmQkIglGH1Nciam5IThX19ibyEag\/0?wx_fmt=jpeg\&quot;,\&quot;subtype\&quot;:9,\&quot;is_multi\&quot;:0,\&quot;multi_app_msg_item_list\&quot;:[],\&quot;author\&quot;:\&quot;苏生\&quot;,\&quot;copyright_stat\&quot;:100,\&quot;duration\&quot;:0,\&quot;del_flag\&quot;:1,\&quot;item_show_type\&quot;:0,\&quot;audio_fileid\&quot;:0,\&quot;play_url\&quot;:\&quot;\&quot;,\&quot;malicious_title_reason_id\&quot;:0,\&quot;malicious_content_type\&quot;:0&#125;&#125;]&#125;&quot;, </span><br><span class="line">&quot;next_offset&quot;: 37,</span><br><span class="line">&quot;video_count&quot;: 1,</span><br><span class="line">&quot;use_video_tab&quot;: 1,</span><br><span class="line">&quot;real_type&quot;: 0,</span><br><span class="line">&quot;home_page_list&quot;: []</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到返回数据包括文章标题titile、摘要digest、文章地址content_url、阅读原文地址source_url、封面图cover、作者author ，只要抓取这些有用的数据就行了。</p><h2 id="2-python-抓取公众号文章"><a href="#2-python-抓取公众号文章" class="headerlink" title="2. python 抓取公众号文章"></a>2. python 抓取公众号文章</h2><p>上面分析了接口参数和返回数据，开始用Python请求微信接口就是了。</p><figure class="highlight plaintext"><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><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br></pre></td><td class="code"><pre><span class="line">import requests,json,time</span><br><span class="line">biz = &#x27;MzA5NjYxNDQwNA==&#x27;#随公众号改变（用户和公众号之间的唯一id）</span><br><span class="line">uin = &#x27;MTE3MDQ4MjQ0MQ%3D%3D&#x27;#不变（用户ID）</span><br><span class="line">key = &#x27;b7867b6712aa36fe784e610f7c7fc3a104955a476fa6bf7224e7f96ea3fc7bef0184aef8bd6832abbf4e9f3dfb09b23ead475e5c8aa84d1920618b8faf98820150bd2a001996d55bfc1421bcd2aa12094db071a65ede4c20f97af661292f93800cfa9d7c0e81d908dcebee5afa6a7baa4eb726a85321caaaa1ab3708118dbea4&#x27;</span><br><span class="line">def parse(offset, biz, uin, key):</span><br><span class="line">    # url前缀</span><br><span class="line">    url = &quot;https://mp.weixin.qq.com/mp/profile_ext&quot;</span><br><span class="line">    # 请求头</span><br><span class="line">    headers = &#123;</span><br><span class="line">        &quot;User-Agent&quot;: &quot;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1301.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat&quot;</span><br><span class="line">    &#125;</span><br><span class="line">    proxies = &#123;</span><br><span class="line">        &#x27;https&#x27;: None,</span><br><span class="line">        &#x27;http&#x27;: None,</span><br><span class="line">    &#125;</span><br><span class="line">    # 重要参数https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&amp;__biz=MjM5ODIzNDExMg==&amp;f=json&amp;offset=48&amp;count=10&amp;is_ok=1&amp;scene=124&amp;uin=MTU0MTQzNjQwMw%3D%3D&amp;key=a42654d5f06828b5d9e40deca0ea5f73004fecbf9ae4cfe0d37653465b623e26d82d0948a73d3cdf4fffd5df19bebafed06815f22f05bac0e5679625c86bb429885529cea1973bfb4d9f18481e624a0cea7cd12932fb55e7ed892ccd6dcda141737cf5ed9811d477cd90cdf4d8371a8b1bdd63de15e193787fc75f186cdf41b5&amp;pass_ticket=FjDlSKDCqgdl0E5WNMPJLuBO3eeqP%2FdrlM1Q8%2FzEHxisVbm7ZVemLp6VeXsrLd0i&amp;wxtoken=&amp;appmsg_token=1074_NFjOFA%252FiWPMoGcRLiG7SzMUc-NoJp7QhKSYmYw~~&amp;x5=0&amp;f=json</span><br><span class="line">    param = &#123;</span><br><span class="line">        &#x27;action&#x27;: &#x27;getmsg&#x27;,</span><br><span class="line">        &#x27;__biz&#x27;: biz,</span><br><span class="line">        &#x27;f&#x27;: &#x27;json&#x27;,</span><br><span class="line">        &#x27;offset&#x27;: offset, #偏移量</span><br><span class="line">        &#x27;count&#x27;: &#x27;10&#x27;, #每次请求的条数</span><br><span class="line">        &#x27;is_ok&#x27;: &#x27;1&#x27;,</span><br><span class="line">        &#x27;scene&#x27;: &#x27;124&#x27;,</span><br><span class="line">        &#x27;uin&#x27;: uin,</span><br><span class="line">        &#x27;key&#x27;: key, #请求的秘钥，一段时间就会失效</span><br><span class="line">        &#x27;wxtoken&#x27;: &#x27;&#x27;,</span><br><span class="line">        &#x27;x5&#x27;: &#x27;0&#x27;,</span><br><span class="line">    &#125;</span><br><span class="line">    # 发送请求，获取响应</span><br><span class="line">    response = requests.get(url, headers=headers, params=param, proxies=proxies)</span><br><span class="line">    response_dict = response.json()</span><br><span class="line">    print(response_dict)</span><br><span class="line">    next_offset = response_dict[&#x27;next_offset&#x27;]</span><br><span class="line">    can_msg_continue = response_dict[&#x27;can_msg_continue&#x27;]</span><br><span class="line">    general_msg_list = response_dict[&#x27;general_msg_list&#x27;]</span><br><span class="line">    data_list = json.loads(general_msg_list)[&#x27;list&#x27;]</span><br><span class="line">    htmls = []</span><br><span class="line">    # print(data_list)</span><br><span class="line">    for data in data_list:</span><br><span class="line">        try:</span><br><span class="line">            # 文章发布时间</span><br><span class="line">            date = time.strftime(&#x27;%Y-%m-%d&#x27;, time.localtime(data[&#x27;comm_msg_info&#x27;][&#x27;datetime&#x27;]))</span><br><span class="line">            msg_info = data[&#x27;app_msg_ext_info&#x27;]</span><br><span class="line">            #原创</span><br><span class="line">            if msg_info[&#x27;copyright_stat&#x27;] == 11:</span><br><span class="line">              # 文章标题</span><br><span class="line">              title = msg_info[&#x27;title&#x27;]</span><br><span class="line">              # 文章链接</span><br><span class="line">              url = msg_info[&#x27;content_url&#x27;]</span><br><span class="line">              #文章摘要digest</span><br><span class="line">              #文章封面cover</span><br><span class="line"></span><br><span class="line">              res = requests.get(url,proxies=&#123;&#x27;http&#x27;: None,&#x27;https&#x27;: None&#125;,verify=False, headers=headers)</span><br><span class="line">              content = res.text.replace(&#x27;data-src&#x27;, &#x27;src&#x27;)</span><br><span class="line">              #filename=str(int(time.time()))+&#x27;.html&#x27;</span><br><span class="line">              #生成HTML文件</span><br><span class="line">              #htmls.append(filename)</span><br><span class="line">              with open(date+&#x27;_&#x27;+title+&#x27;.html&#x27;, &#x27;w&#x27;, encoding=&#x27;utf-8&#x27;) as f:</span><br><span class="line">                  f.write(content)</span><br><span class="line">              #生成Excel</span><br><span class="line">              #with open(&#x27;wechat2.csv&#x27;, &#x27;a+&#x27;, encoding=&#x27;gbk&#x27;) as f:</span><br><span class="line">              #    f.write(title.replace(&#x27;,&#x27;, &#x27;，&#x27;)+&#x27;,&#x27;+msg_info[&#x27;digest&#x27;].replace(&#x27;,&#x27;, &#x27;，&#x27;)+&#x27;,&#x27; + msg_info[&#x27;cover&#x27;].replace(&#x27;,&#x27;, &#x27;，&#x27;) + &#x27;,&#x27; +url.replace(&#x27;,&#x27;, &#x27;，&#x27;)+&#x27;,&#x27;+str(date)+ &#x27;\n&#x27;)</span><br><span class="line">              #生成markdown</span><br><span class="line">            #   with open(&#x27;wechat.md&#x27;, &#x27;a+&#x27;, encoding=&#x27;utf-8&#x27;) as f:</span><br><span class="line">            #      f.write(&#x27;[&#123;&#125;]&#x27;.format(title) + &#x27;(&#123;&#125;)&#x27;.format(url)+ &#x27;\n&#x27;)</span><br><span class="line">              #生成PDF</span><br><span class="line">              #try:</span><br><span class="line">              #    pdfkit.from_string(content,&#x27;./&#x27; + date + &#x27;_&#x27; + title.replace(&#x27; &#x27;, &#x27;&#x27;)+&#x27;.pdf&#x27;)</span><br><span class="line">              #except Exception as err:</span><br><span class="line">              #    print(err)</span><br><span class="line">              # 部分文章标题含特殊字符，不能作为文件名</span><br><span class="line">                  #f = datetime.datetime.now().strftime(&#x27;%Y%m%d%H%M%S&#x27;) + &#x27;.pdf&#x27;</span><br><span class="line">                  #pdfkit.from_string(content,f)</span><br><span class="line">                  # 自己定义存储路径（绝对路径）</span><br><span class="line">              #finally:</span><br><span class="line">              #    os.remove(filename)</span><br><span class="line">              #pdfkit.from_url(url, &#x27;./&#x27; + date + title + &#x27;.pdf&#x27;) #图片获取不到</span><br><span class="line">              print(url + title + date + &#x27;成功&#x27;)</span><br><span class="line">        except Exception as err:</span><br><span class="line">            print(err)</span><br><span class="line">    #try:</span><br><span class="line">        #pdfkit.from_file(htmls,&#x27;公众号文章备份.pdf&#x27;)</span><br><span class="line">    #except:</span><br><span class="line">    #    pass</span><br><span class="line">    if can_msg_continue == 1:</span><br><span class="line">        time.sleep(1)</span><br><span class="line">        parse(next_offset,biz,uin,key)</span><br><span class="line">        return True</span><br><span class="line">    else:</span><br><span class="line">        print(&#x27;爬取完毕&#x27;)</span><br><span class="line">        return False</span><br><span class="line"></span><br><span class="line">parse(0,biz,uin,key)</span><br></pre></td></tr></table></figure><p><img src="https://upload-images.jianshu.io/upload_images/23152173-834294997521f48b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"></p><div style="color:gray;font-size:0.9em">    参考:<br>    [1] <a href="https://sushengbuhuo.github.io/2020/08/28/Python%E4%B8%80%E9%94%AE%E4%B8%8B%E8%BD%BD%E5%85%AC%E4%BC%97%E5%8F%B7%E6%89%80%E6%9C%89%E6%96%87%E7%AB%A0%EF%BC%8C%E5%AF%BC%E5%87%BA%E6%96%87%E4%BB%B6%E6%94%AF%E6%8C%81PDF%EF%BC%8CHTML%EF%BC%8CMarkdown%EF%BC%8CExcel%EF%BC%8Cchm%E7%AD%89%E6%A0%BC%E5%BC%8F/">Python一键下载公众号所有文章，导出文件支持PDF，HTML，Markdown，Excel，chm等格式</a></div>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Others/">Others</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%B7%A5%E5%85%B7/">工具</category>
      
      
      <comments>https://blog.helloallen.cn/ba4eb63d/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>通过FFmpeg裁剪视频</title>
      <link>https://blog.helloallen.cn/e8195e92/</link>
      <guid>https://blog.helloallen.cn/e8195e92/</guid>
      <pubDate>Sun, 14 Jul 2024 01:11:03 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在剪辑视频过程中，遇到一个长达18小时，大小8G的视频。而无论是发布平台还是各类剪辑工具都对视频的长度进行了限制，因此想到了通过FFmpeg的方式进行剪辑。目的便是将这个长达18小时的视频，通过FFmpeg将其裁剪为9个子视频，每个子视频长2小时。（以下为windows教程）</p><h2 id="安装FFmpeg"><a href="#安装FFmpeg" class="headerlink" title="安装FFmpeg"></a>安装FFmpeg</h2><h3 id="1-下载FFmpeg"><a href="#1-下载FFmpeg" class="headerlink" title="1. 下载FFmpeg"></a>1. 下载FFmpeg</h3><ol><li>访问 <a href="https://www.gyan.dev/ffmpeg/builds/">FFmpeg 官方网站</a>下载FFmpeg</li><li>将下载的安装包解压到任意目录，例如 D:\ffmpeg（注意：解压目录不能含有中文）</li></ol><h3 id="2-配置环境变量"><a href="#2-配置环境变量" class="headerlink" title="2. 配置环境变量"></a>2. 配置环境变量</h3><ol><li>右键点击“我的电脑”，选择“属性”。</li><li>点击“高级系统设置”。</li><li>点击“环境变量”按钮。</li><li>在“系统变量”区域找到名为“Path”的变量，并点击“编辑”。</li><li>点击“新建”并输入 FFmpeg 的 bin 目录路径（例如：D:\ffmpeg\bin）。</li><li>点击“确定”保存设置。</li></ol><h3 id="3-验证安装"><a href="#3-验证安装" class="headerlink" title="3. 验证安装"></a>3. 验证安装</h3><ol><li>打开命令提示符（cmd）或 PowerShell。</li><li>输入 ffmpeg -version 命令，查看是否能正确显示 FFmpeg 版本信息。</li></ol><h2 id="编写并使用脚本"><a href="#编写并使用脚本" class="headerlink" title="编写并使用脚本"></a>编写并使用脚本</h2><h3 id="1-编写脚本"><a href="#1-编写脚本" class="headerlink" title="1. 编写脚本"></a>1. 编写脚本</h3><p>打开你的文本编辑器，创建一个新的脚本文件，比如叫做split_video.sh，然后输入以下内容：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">#!/bin/bash  </span><br><span class="line">  </span><br><span class="line"># 原始视频文件  </span><br><span class="line">INPUT=&quot;original_video.mp4&quot;  </span><br><span class="line">  </span><br><span class="line"># 开始时间偏移量，初始为0  </span><br><span class="line">START=0  </span><br><span class="line"># 每个视频的长度（秒），2小时 = 2 * 60 * 60秒  </span><br><span class="line">DURATION=7200  </span><br><span class="line"># 输出文件的前缀  </span><br><span class="line">OUTPUT_PREFIX=&quot;part&quot;  </span><br><span class="line">  </span><br><span class="line"># 循环裁剪视频  </span><br><span class="line">for (( i=1; i&lt;=9; i++ ))  </span><br><span class="line">do  </span><br><span class="line">    # 计算当前视频片段的结束时间  </span><br><span class="line">    END=$((START + DURATION - 1))  </span><br><span class="line">    # 构造输出文件名  </span><br><span class="line">    OUTPUT=&quot;$&#123;OUTPUT_PREFIX&#125;$&#123;i&#125;.mp4&quot;  </span><br><span class="line">    # 使用ffmpeg裁剪视频  </span><br><span class="line">    ffmpeg -ss $START -to $END -i &quot;$INPUT&quot; -c copy &quot;$OUTPUT&quot;  </span><br><span class="line">    # 更新下一个视频片段的起始时间  </span><br><span class="line">    START=$((START + DURATION))  </span><br><span class="line">done  </span><br><span class="line">  </span><br><span class="line">echo &quot;视频裁剪完成！&quot;</span><br></pre></td></tr></table></figure><p>注意：-ss 参数在 -i 前面（如脚本所示）时，ffmpeg会更快地定位到起始位置，因为它不会解码直到达到-ss指定的时间点。然而，这可能导致定位不太精确（尤其是当使用基于关键帧的编解码器时）。如果精确度非常重要，你可能需要将 -ss 移到 -i 参数之后，但这会增加处理时间，因为ffmpeg会先解码整个视频直到达到 -ss 指定的时间点。</p><h3 id="2-编译脚本"><a href="#2-编译脚本" class="headerlink" title="2. 编译脚本"></a>2. 编译脚本</h3><p>导航到脚本所在的目录，并运行以下命令：<code>split_video.sh</code></p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Others/">Others</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%B7%A5%E5%85%B7/">工具</category>
      
      
      <comments>https://blog.helloallen.cn/e8195e92/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>未来极具潜力的50项新兴技术（2024全球智库动态）</title>
      <link>https://blog.helloallen.cn/ef54409c/</link>
      <guid>https://blog.helloallen.cn/ef54409c/</guid>
      <pubDate>Sun, 14 Apr 2024 22:53:57 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>英国研究与创新署团队经过深入研究，发布了50项仍处于起步阶段的关键前沿技术，并将这些新兴技术分类编排在7个技术系列中。这50项新兴技术具体如下：</p><center><font color=red size=5>人工智能、数字和计算技术</font></center><ol><li><p><strong>人工智能情绪和表情识别。</strong>可以识别我们的情绪，它可以在护理和陪伴等方面改善我们的日常生活。</p></li><li><p><strong>通用人工智能。</strong>使机器能够像人类一样行为、学习、创造和执行。AGI提出了耐人寻味的问题。我们是否总能分辨出与我们互动的对象是机器还是人类？这对我们来说重要吗？答案将以我们意想不到和无法预测的方式改变我们的生活。</p></li><li><p><strong>受生物启发的人工智能。</strong>包括进化计算和电子学、人工神经网络、免疫系统、生物机器人和蜂群智能，它从生物结构中汲取灵感，使计算能够模仿人类的大脑过程，可以为规划、记忆和视觉刺激提供新的算法。</p></li><li><p><strong>脑机接口技术。</strong>能将我们的思想转化为指令，从而控制外部软件或硬件，如：计算机或机械臂。它让我们更接近机器与人脑的完全对接。脑机接口技术可以用于医疗、老龄化社会、体育、军事、制造业、服务业等。</p><center>   <img      style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"      src="https://mmbiz.qpic.cn/mmbiz_jpg/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrLx0YPdchvE1CpFMmEJMjTFZ62VWOiaFQ5JNLJuk7KVicf8hwiagN8ZoY2A/640?wx_fmt=jpeg&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" /> <div      style="color: #999; padding: 2px;font-size:0.8em">     国内研究团队利用脑机接口技术帮助中风患者康复（网络配图） </div></center></li></ol><ol start="5"><li><p><strong>量子算法。</strong>可应用于密码学、搜索优化和量子系统模拟等领域。从量子计算中获取价值的关键，在于找到量子计算机比经典计算机更擅长的特定算法集。</p></li><li><p><strong>脱氧核糖核酸（DNA）</strong>数据存储。对合成的脱氧核糖核酸或核糖核酸（RNA）链上的数据进行编码和解码。利用生物技术的力量可以满足我们不断升级的数据存储需求，这在我们希望获得复杂的人工智能技术时尤为重要。目前，我们的计算硬件设计已经达到物理极限，脱氧核糖核酸数据存储技术可以消除这一限制，开辟新的计算应用。</p><center>   <img      style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"      src="https://mmbiz.qpic.cn/mmbiz_jpg/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrLQwlKv3JrXtDkOd3AHWVJ1UiaG5cTAMuEWGd11zJ3kFcsg6rN79hXdMA/640?wx_fmt=jpeg&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" /> <div      style="color: #999; padding: 2px;font-size:0.8em">     国内研究团队研发的脱氧核糖核酸存储电极（网络配图） </div></center></li></ol><ol start="7"><li><p><strong>新计算模式。</strong>能提供传统计算机无法达到的数量级性能改进，包括：生物计算、光子计算和神经形态计算。新计算模式将使科学家们回答包括人脑建模、完整的气候模拟以及理解太空探索等问题。</p></li><li><p><strong>新颖的沉浸式界面。</strong>将模糊离线世界和在线世界。这一技术将改变我们观察世界和访问媒体的方式，让我们可以通过感官进行旅行。</p></li></ol><center><font color=red size=5>先进材料与制造业</font></center><ol start="9"><li><strong>4D打印。</strong>具有“自我修复”的潜力，为太空制造、更好的软机器人技术和新的医疗解决方案提供了可能性。</li></ol><center>    <img         style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"         src="https://mmbiz.qpic.cn/mmbiz_jpg/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrLHob4nqga0QbAFzbrLGh8sq9licTuf4oSYcAY900hz57K6E8OTIquecw/640?wx_fmt=jpeg&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" />    <div         style="color: #999; padding: 2px;font-size:0.8em">        4D打印抓手在最佳温度时抓取物体（网络配图）    </div></center><ol start="10"><li><strong>仿生材料。</strong>与同类材料相比，它们更容易重复使用和回收。它可以帮助人类创造出受自然启发、制造成本低、对地球危害小的材料。</li></ol><ol start="11"><li><strong>纳米粒子制造。</strong>就是制造纳米粒子。纳米技术已成为许多行业的基本技术，找到更有效、更高效和更低成本的纳米粒子制造方法，将有助于我们扩大纳米技术的用途和优势。</li></ol><ol start="12"><li><strong>超材料。</strong>在亚波长级别工作，扩展了光与物质的相互作用方式，可用于交通、医疗、科研、电信、能源、创意等领域。超材料是科幻小说与现实的结合，可以使与之相互作用的物质隐形，利用隐形技术可以消除汽车盲点，制造更精确的医疗成像、通讯天线，并显著提高太阳能发电机的效率。</li></ol><center><font color=red size=5>电子、光子和量子技术</font></center><ol start="13"><li><p><strong>新型半导体替代系统。</strong>在越来越多的应用中，当前的半导体已经达到其性能极限。宽带隙（WBG）化合物半导体可以在更高的电压、温度和频率下工作，与目前的半导体相比，性能将大大提高。几乎所有行业都会受到这项技术的影响，主要用于6G、光子学和电力电子。</p></li><li><p><strong>新兴显微技术。</strong>能够在空间和时间上观察生物学的工作，从单个分子到整个生物体。这项技术能使科学家更准确地探索各种材料的结构与特性之间的关系，从而更好地了解它们的行为。这有助于我们开发新材料，更好地了解材料和生物体，以及更好地诊断疾病。</p></li><li><p><strong>高光谱成像。</strong>是将光谱学与多种频率的可见光波长以外的成像技术相结合，从而对物体的构成进行“指纹识别”（fingerprinting）。这项技术可以用于精准农业，使作物产量更高、更可靠；还能用于监测极端气候事件和更好地了解气候系统；以及通过更好的伤口分类和更清晰的微生物成像，为医疗保健带来潜在益处。</p></li><li><p>毫米波和太赫兹技术。在无创传感和成像（包括医疗诊断）方面具有巨大潜力。毫米波或太赫兹波的传输距离比无线电波短，但可以传输更多数据。在成像应用中，它们能提供更高的空间分辨率，从而获得高清晰度图像；太赫兹波还可能会在蛋白质分析和药物发现中发挥作用；也能用于检测有毒气体和检查混凝土结构。</p></li></ol><center>    <img         style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"   src="https://mmbiz.qpic.cn/mmbiz_jpg/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrL4hjtE74Dcm0rh6pI1GSha8iasRuThohSL1oZKrRPFib4DtOjicoOAYCsw/640?wx_fmt=jpeg&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" />    <div         style="color: #999; padding: 2px;font-size:0.8em">        太赫兹人参皂苷检测仪（网络配图）    </div></center><ol start="17"><li><p><strong>光子发生器。</strong>是以单个粒子或光子形式发射光的光源。量子光是开发安全通信和由量子驱动的更强大计算的核心。</p></li><li><p><strong>等离子体学。</strong>涉及利用光照射到金属表面时引发的电子波，可应用于成像、纳米粒子，是其他新兴技术的重要推动力。等离子体学将主要影响科学、工程和医学界，此外还将对其他各行各业产生许多微小的影响。</p></li><li><p>后量子密码学。侧重于开发既能确保量子计算机和经典计算机安全，又能在现有通信网络中运行的加密系统。量子计算将使目前使用的大多数加密解决方案变得不安全，因此我们需要使用后量子加密技术来应对未来的威胁。</p></li><li><p>室温超导体。可以在不浪费能源的情况下进行导电，将使持续低电费成为可能，并从根本上改变能源生产和分配的经济性。</p></li></ol><center><font color=red size=5>能源与环境技术</font></center><ol start="21"><li><p><strong>交联聚合物回收。</strong>交联聚合物极难回收，不仅会增加垃圾填埋量，还会对环境造成危害。开发先进的回收方法可以减少塑料污染，并降低生产新聚合物对石油的需求。</p></li><li><p>电网级无线能源传输和充电。在没有电缆的情况下安全地远距离传输电力，可能会改变我们使用电子设备的方式。实现不受天气影响的电力传输，让我们可以更轻松地将电力输送到需要的地方。</p></li><li><p>高超音速。技术需要克服的关键挑战是，高超音速飞机周围的气流温度非常高，以至于化学键会发生振动并最终断裂。高超音速武器已经问世，高超音速运输将改变人员和货物的流动，如从伦敦到悉尼只需3小时。</p></li></ol><center>    <img         style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"   src="https://mmbiz.qpic.cn/mmbiz_jpg/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrLW1am8fwMvBoEWZkzhNhyY6DST1gNPUYEicwcNSYerxibtOiaSlSFjjgIQ/640?wx_fmt=jpeg&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" />    <div         style="color: #999; padding: 2px;font-size:0.8em">        高超音速技术已在军事领域获得运用（网络配图）    </div></center><ol start="24"><li><p>新型推进或离子推进。通过给予电子能量使其脱离原子来产生推力。离子推力发动机只在太空中使用。与化学推进器相比，离子推进所需的推进剂要少得多，可帮助实现太空旅行，延长卫星寿命。在探索更深远的太空时，它可能成为推动我们前进的可靠技术。</p></li><li><p>新型制氢和储氢技术。对于创造更廉价、更高效的制氢工艺至关重要。可以用于能源、原材料提取、运输、制造等。</p></li><li><p>新型负排放技术。包括从环境中提取二氧化碳的所有新兴技术。通过清除地球大气中新的和现有的温室气体，可以帮助应对气候变化。</p></li><li><p>核聚变。该技术仍然很难实现，但它或许能一举实现我们对清洁能源的追求。如果核聚变能够在地球上以工业规模复制，那么它几乎可以提供无限的清洁、安全、经济的能源。</p></li><li><p>天基太阳能。可以全年全天候提供清洁能源，是去碳化进程中令人兴奋的一个组成部分。通过将太阳能电池阵列置于地球大气层之外来消除对天气的影响，意味着在地球上的任何地方都可以持续增加发电量。</p></li></ol><center><font color=red size=5>生物技术</font></center><ol start="29"><li>人造细胞和人造生命。已经用于治疗肾衰竭。随着发展，我们还能开发人造血细胞，减少献血需求，提高血液制品的安全性。人造细胞还可用于生物制造，生产长效、高产、高纯度的蛋白质和酶。</li></ol><center>    <img         style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"   src="https://mmbiz.qpic.cn/mmbiz_jpg/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrLLrsiaqEu2YnfLgqXWfFh5xBrgCgznELXnQ6t0m9VWAwhCjBXFKbWwcQ/640?wx_fmt=jpeg&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" />    <div         style="color: #999; padding: 2px;font-size:0.8em">        天然酿酒酵母与人造酿酒酵母对比（网络配图）    </div></center><ol start="30"><li><p>细菌和微生物制造。细菌可用于制造药物（包括抗生素）、有用分子、生物混凝土和其他有趣的材料。细菌合成的物质可以创造出具有实用性的新材料。通过细菌制造产生的物质有望用于食品、个人护理、家用化学品、生物医学和纺织品等，几乎涵盖日常生活的方方面面。</p></li><li><p>生物催化膜。具有一些有用的特性，如提高反应效率、改善污染物去除效果，以及在某些过程中能够重复使用酶。该技术目前已应用于制药和生物技术行业，可以促进更可持续、更高效、污染更少的制药生产方法。生物催化膜还可以生产出使营养成分在加热过程中不会流失的改良食品、新型药品，以及被用于废水处理。</p></li><li><p><strong>生物电子学和电子医药学。</strong>拓宽了无需药物或手术的治疗范围，并将推动无线供电等技术的发展。二者具有巨大的医疗保健效益，应用范围从心脏起搏器到治疗帕金森病的脑深部刺激。这些设备将使我们能够实时监测和治疗疾病。</p></li><li><p>微生物遗传育种技术。为改善食品健康并提高生产效率提供了可能。该技术还可以通过单一技术减少污染并生产清洁能源。</p></li><li><p>可编程细胞。将开辟治疗和预防疾病的新方法。对细胞行为进行编程拓展了生物计算的可能性。医药、能源、军事和农业都将从中受益。</p></li><li><p>组织工程中的生物制造。可以灵活制造出满足人类和动物患者个性化需求的组织，甚至器官。这不仅有助于手术治疗，还能提高实验室研究的准确性，例如，确定有效的新药物。</p></li></ol><center><font color=red size=5>健康与医疗技术</font></center><ol start="36"><li><p><strong>成人干细胞生成。</strong>是干细胞医学和再生疗法新领域的开端。可以帮助制造细胞，修复受伤的组织，如皮肤或大脑。此外成人可以同意使用自己的干细胞，因此与使用胚胎干细胞进行研究、治疗相比，争议要小得多。</p></li><li><p>代谢流组。意义在于它收集了来自多个不同组学领域的数据，描绘了分子相互作用的全貌，将基因组学、转录组学、蛋白质组学和代谢组学等领域联系在一起。它可以帮助寻找和开发新的药物治疗方法或新的筛选技术，也是个性化医疗的关键推动因素。</p></li><li><p>抗衰老药物。旨在影响老化和老年相关疾病的根源，延长动物的寿命。这些技术和相关治疗方法可以让我们健康地生活更长时间，减轻老年相关疾病给社会带来的负担，并有可能延长预期寿命。</p></li><li><p>感知检测植入物。可以让装有假肢的人通过这些设备“感觉”自己，恢复或增强听觉或嗅觉。它还能为我们提供与机器互动的新方法。</p><center>  <img     style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"src="https://mmbiz.qpic.cn/mmbiz_jpg/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrL2mapaUTJyHTeZUiaVewpwsZDRHmEkaiaQyeH7iaSpaH2HwlQHTic74YjrA/640?wx_fmt=jpeg&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" /><div     style="color: #999; padding: 2px;font-size:0.8em">    测试中的仿生眼（网络配图）</div></center></li><li><p>抗生素替代品。抗生素用于预防和治疗细菌感染，但常见疾病的细菌正逐渐对抗生素产生耐药性。抗生素耐药性会导致医疗费用增加、住院时间延长和死亡率上升。因此开发替代品是全球健康的当务之急。抗生素替代品可应用于卫生、农业、动物保健行业。</p></li><li><p>微生物组疗法。在降低许多人类疾病的发病率和严重程度方面具有巨大潜力，甚至将开创医学治疗的新领域。微生物组可以生产出本质上更适合人类使用的治疗方法和干预措施，因此可能比一般的临床方案更安全、更成功。</p></li><li><p>个性化核糖核酸疗法。被开发用于癌症靶向治疗，未来将利用核糖核酸为患者提供个性化疗法。核糖核酸技术可将大量蛋白质、转录本和基因作为新的治疗靶点。</p></li><li><p>分阶段基因组组装工具。可以采用新的基因组测序方法，加快生物信息学方面的工作，同时降低错误率。下一代测序可以进行全基因组分期，为复杂性状研究，以及遗传疾病的研究提供信息。</p></li><li><p>全身芯片设备。可以确定药物在其他器官中的疗效和毒性，为临床试验前的治疗测试提供更准确、更具成本效益的方法。</p></li></ol><center><font color=red size=5>机器人和空间技术</font></center><ol start="45"><li><p>完全自主车辆。将做到人类驾驶员能做的任何事情。自动驾驶汽车的开发已经取得了进展，但完全自主车辆才是最终目标。这项技术引发了关于伦理、法律和保险的相关讨论。它可以从根本上改变个人交通方式，并大大增加无法开车之人的出行机会。</p></li><li><p>纳米级机器人技术。能制造出极小的机器或机器人。微型机器人和纳米机器人正应用于生物医学等多个领域，比如“修复”遗传密码缺陷或高度靶向性的药物输送。它们也是连接人体与数字世界的另一种方式。</p></li><li><p>机器人异地制造。对于人类在我们目前的星球之外生活是必不可少的。在太空制造，受益于微重力和真空等效应，将意味着我们可以开发出在地球上无法实现的产品。此外，在地球之外制造产品所需的技术，也是在月球或火星建立任何定居点的重要一步。</p></li><li><p>软体机器人。具有与活体组织相似的机械特性，其灵感通常来自乌贼或蠕虫等无脊椎动物。它可以拓宽机器人技术在社会和工业中的应用范围。软体机器人让我们能够开发与生物系统更加相似的人造肌肉和人造器官。</p><center>  <img     style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 30em;"src="https://mmbiz.qpic.cn/mmbiz_png/bPSwSOgG5gb9To3jvyQ5d9FMfic3lSmrLAqcdVlGmEXeKEJkwZMMhBmicwwlOsQAH6hb4S52UwVvC5vuHQREkSoQ/640?wx_fmt=png&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" /><div     style="color: #999; padding: 2px;font-size:0.8em">    斯坦福大学制造的可任意变形和自由漫步的软体机器人（网络配图）</div></center></li></ol><ol start="49"><li><p>空间核动力和新型空间推进系统。用于航天器的新型非燃烧推进。目前的推进方法需要笨重的燃料。这些技术的开发对于未来的载人太空探索至关重要。</p></li><li><p>极近地轨道卫星。有两大好处：卫星图像的分辨率大幅提高；由于空间碎片不会在这一高度堆积，因此损坏的几率较小。电信、农业、环境监测、海洋监测等行业均可以应用这一技术。</p></li></ol>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/%E4%BB%8E%E5%AE%87%E5%AE%99%E8%B5%B7%E6%BA%90%E5%88%B0%E4%BA%BA%E7%B1%BB%E6%96%87%E6%98%8E/">从宇宙起源到人类文明</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E4%BA%BA%E9%97%B4%E4%B8%96/">人间世</category>
      
      
      <comments>https://blog.helloallen.cn/ef54409c/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>CSS中的物理属性和逻辑属性</title>
      <link>https://blog.helloallen.cn/f3549ddc/</link>
      <guid>https://blog.helloallen.cn/f3549ddc/</guid>
      <pubDate>Tue, 19 Mar 2024 20:25:07 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="书写模式"><a href="#书写模式" class="headerlink" title="书写模式"></a>书写模式</h2><p>书写模式是为了支持不同语言的书写习惯而生的，比如：中文、英文、法语等都是从左到右书写的，而文言文是从上到下书写的，但是阿拉伯语则是从右往左书写的。</p><p>下面是一个例子：</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;width: 100px;&quot;</span>&gt;</span>Hello World 1234我就是一段普普通通的文字，默认效果<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;width: 100px; writing-mode: horizontal-tb;&quot;</span>&gt;</span>Hello World 1234我就是一段普普通通的文字，从左往右从上到下水平书写的<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;height: 100px; writing-mode: vertical-lr;&quot;</span>&gt;</span>Hello World 1234我就是一段普普通通的文字，从上到下从左到右垂直书写的<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;height: 100px; writing-mode: vertical-rl;&quot;</span>&gt;</span>Hello World 1234我就是一段普普通通的文字，从上到下从右到左垂直书写的<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p>效果图如下：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192026774.webp"></p><p>配合 HTML 的 <code>dir</code> 属性和 CSS 的 <code>direction</code> 属性还可以改变元素从左到右排还是从右到左排，他们在配合 <code>writing-mode</code> 使用之后会有不同的效果。</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span> <span class="attr">dir</span>=<span class="string">&quot;rtl&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span>&gt;</span>Hello World 1234我就是一段普普通通的文字<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">br</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;direction: ltr;&quot;</span>&gt;</span>Hello World 1234我就是一段普普通通的文字<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p>效果：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192028755.png"></p><h2 id="物理属性"><a href="#物理属性" class="headerlink" title="物理属性"></a>物理属性</h2><p>物理属性即含有 <code>left</code>、<code>right</code>、<code>top</code> 和 <code>bottom</code> 物理位置关键字的属性，它们与你看到的屏幕紧密相关，左永远是左，不管文本流动的方向如何。</p><p>物理属性在我们修改书写模式之后可能会存在一些问题，请看下面这个例子：</p><p>首先是中文：</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;direction: ltr;&quot;</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;margin-left: 20px; margin-top: 10px;&quot;</span>&gt;</span>中文TITLE<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192029934.webp"></p><p>然后是阿拉伯语：</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;direction: rtl;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;margin-left: 20px; margin-top: 10px;&quot;</span>&gt;</span>              <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192029878.webp"></p><p>看出问题了吗？如果我们是一个国际化的项目，当我们切换成阿拉伯语之后，按照阿拉伯语的书写习惯，margin 应该在右侧才对，那么只是单纯的切换 direction 还不行，还得改 CSS 代码。不过使用逻辑属性编写就不需要修改 CSS 代码了。</p><h2 id="逻辑属性"><a href="#逻辑属性" class="headerlink" title="逻辑属性"></a>逻辑属性</h2><p>逻辑属性定义了在相对方向下与对应的实体属性相等价的属性。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192032241.webp"></p><p>现在我们就可以利用逻辑属性来解决上面的问题了：</p><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;direction: rtl;&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;margin-inline-start: 20px; margin-block-start: 10px;&quot;</span>&gt;</span>              <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192033222.webp"></p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/CSS/">CSS</category>
      
      
      <comments>https://blog.helloallen.cn/f3549ddc/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>CSS中的字体</title>
      <link>https://blog.helloallen.cn/f56369ac/</link>
      <guid>https://blog.helloallen.cn/f56369ac/</guid>
      <pubDate>Tue, 19 Mar 2024 20:00:20 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="1-font-family"><a href="#1-font-family" class="headerlink" title="1. font-family"></a>1. font-family</h2><p><code>font-family</code> 其实不能简单理解为字体，它实际上是一个优先级从高到低的一个字体列表或者字体族名列表，前面的字体（或族名）如果系统没有就继续找后面的字体（或族名），直到找到为止。</p><p>另外，我们通常写的 <code>serif</code>、<code>monospace</code>、<code>monospace</code>、<code>Helvetica</code> 等也不是字体，而是字体族名，是用来描述一组相似设计风格的字体的名称，它们通常由一个主要的字体家族名称和一些特定字体样式组成。</p><p>例如，<code>Helvetica</code> 是一个常见的字体族名，其中包含了 <code>Helvetica Regular</code>、<code>Helvetica Bold</code>、<code>Helvetica Italic</code> 等字体样式。</p><p>常见字体族名：</p><ul><li><code>serif</code>：带衬线字体，笔画结尾有特殊的装饰线或衬线。</li><li><code>sans-serif</code>：无衬线字体，即笔画结尾是平滑的字体。</li><li><code>monospace</code>：等宽字体，即字体中每个字宽度相同。</li><li><code>cursive</code>：草书字体。这种字体有的有连笔，有的还有特殊的斜体效果。因为一般这种字体都有一点连笔效果，所以会给人一种手写的感觉。</li><li><code>system-ui</code>：从浏览器所处平台处获取的默认用户界面字体。由于世界各地的排版习惯之间有很大的差异，因此为那些不适合其他通用字体的字体提供了这个通用字体。</li></ul><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;div&gt;Hello World! 你好世界！&lt;/div&gt;</span><br><span class="line">&lt;div style=&quot;font-family: serif;&quot;&gt;serif Hello World! 你好世界！&lt;/div&gt;</span><br><span class="line">&lt;div style=&quot;font-family: sans-serif;&quot;&gt;sans-serif Hello World! 你好世界！&lt;/div&gt;</span><br><span class="line">&lt;div style=&quot;font-family: monospace;&quot;&gt;monospace Hello World! 你好世界！&lt;/div&gt;</span><br><span class="line">&lt;div style=&quot;font-family: cursive;&quot;&gt;cursive Hello World! 你好世界！&lt;/div&gt;</span><br><span class="line">&lt;div style=&quot;font-family: system-ui;&quot;&gt;system-ui Hello World! 你好世界！&lt;/div&gt;</span><br><span class="line">&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;Arial, Helvetica, sans-serif Hello World! 你好世界！&lt;/div&gt;</span><br><span class="line">&lt;div style=&quot;font-family: &#x27;Courier New&#x27;, Courier, monospace&quot;&gt;&#x27;Courier New&#x27;, Courier, monospace Hello World! 你好世界！&lt;/div&gt;</span><br></pre></td></tr></table></figure><p>效果如下图所示：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192001206.png"></p><h2 id="2-外部字体引入"><a href="#2-外部字体引入" class="headerlink" title="2. 外部字体引入"></a>2. 外部字体引入</h2><p>外部字体引入的第一步是定义字体，使用 <code>@font-face</code> 关键字定义字体，然后再用 <code>font-famliy</code> 使用即可。</p><p>比如，我这里在网上下了一个字体叫”美神勇兔生肖“。</p><figure class="highlight css"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">@font-face</span> &#123;</span><br><span class="line">   <span class="attribute">font-family</span>: MeiShenYongTuShengXiao;</span><br><span class="line">   <span class="attribute">src</span>: <span class="built_in">url</span>(<span class="string">&#x27;./MeiShenYongTuShengXiao.ttf&#x27;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line">&lt;<span class="selector-tag">h1</span> style=&quot;<span class="attribute">font-family</span>: MeiShenYongTuShengXiao;&quot;&gt;Hello World! 你好世界！&lt;/<span class="selector-tag">h1</span>&gt;</span><br></pre></td></tr></table></figure><p>效果如下图所示：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202403192002774.png"></p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/CSS/">CSS</category>
      
      
      <comments>https://blog.helloallen.cn/f56369ac/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>关于乌克兰, 我想谈几点看法（哲学泰斗哈贝马斯）</title>
      <link>https://blog.helloallen.cn/33872f8c/</link>
      <guid>https://blog.helloallen.cn/33872f8c/</guid>
      <pubDate>Wed, 21 Feb 2024 23:57:45 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/sM5SdPkqTeqa5kWSZaFvcgHpL1JHGJkhuh9ickJ9ohD1s3bu3FiasfCMVyMYrMPnsOB7ib6ia1YIsAicQxPKiasibDg2g/640?wx_fmt=jpeg&wxfrom=13" alt="图片"></p><p><strong>导读：</strong></p><p>德国当代知名哲学家、社会学家哈贝马斯近日在《南德意志报》发表文章谈论他对乌克兰战争的看法。在文章中，哈贝马斯指出，<strong>乌克兰正在就德国前几任总理的对俄战略“误判”对德国进行道德勒索</strong>，而西方在决定不参战的时候，就已经注定陷入两难：西方不可能无限制地投入对乌克兰的武装援助。<strong>哈贝马斯赞成德国总理朔尔茨坚持“负责任的权衡”，认为德国外长贝尔伯克对乌克兰的“仓促认同”实际上代表着德国和平主义者正在发生深刻转折，这一转折有可能预示着以对话和维护和平为主旨的德国政治模式的终结。</strong>哈贝马斯谨慎表达了对这些“前和平主义者”草率的情感认同的忧虑，对于哈贝马斯来说，如今不能再以传统意义上“失败”或者“胜利”来设想战争结局，不能指望任何一方落败。正因如此，他支持向谈判开放，并提出了欧盟自主的紧迫命题。欧亚系统科学研究会特转发本文，供读者思考。文章由“新华二代在德国”翻译，仅代表作者本人观点。</p><center><font color=red size=5>关于乌克兰: 战争与愤怒</font></center><center><font face="黑体"><b>文｜哈贝马斯</b></font></center><center><font face="黑体"><b>翻译｜周知语、梁文诵</b></font></center><center><font face="黑体"><b>来源｜《南德意志报》</b></font></center><center>    <img         style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 40em;"   src="https://mmbiz.qpic.cn/mmbiz_jpg/wxX3RC9Es7hM9cCw3ywMGiaf1dYg6BTfOOvEwdauOpc0K1B7QAnwTvW24SX3ibEwnAEI37m82ib8Hfcug2txPGKgA/640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" />    <div         style="color: #999; padding: 2px;font-size:0.8em">        ▲ 尤尔根·哈贝马斯，德国当代最重要的哲学家、社会学家之一。图源：openkat.eu    </div></center><p>在距上一场战争77年之后，在和平仅靠均等的威慑才得以维持且仍旧危机四伏的时代结束33年之后，战争的震撼图景又回来了——就在我们的家门口，俄罗斯专横地挑起了战端。为媒体所呈现的战事前所未有地占据了我们的日常生活。一位深谙图像力量的乌克兰总统带来了令人印象深刻的消息。残暴的破坏场景和触动人心的苦难画面日日更新，并在西方社交媒体中激起了不断自我放大的回响。比起习惯于媒体的年轻人来说，我们老一辈人或许对难以预期的战事的展现方式和经过精心计算的公众影响力的新颖之处更加印象深刻。</p><p>不过，尽管展示出来的图景都是精心编排的产物，但牵动着我们的神经的，令意识到战争近在咫尺的我们愈加受到震撼的，都是实实在在发生的事。因此对西方的观众来说，每一名死者都令他们更不安，每一位被害者都令他们更沮丧，每一个战争罪行都令他们更愤怒——随之增长的，还有以行动来反对它的愿望。</p><p> <strong>1</strong>  <strong>指责朔尔茨的人的自信和攻击性令人困惑</strong></p><p>尽管持有相同的立场，但西方国家联盟的诸政府却开始采取各不相同的做法；<strong>德国爆发了一场出格的、由传媒界的声音煽动起来的观念斗争，主题是如何对被侵略的乌克兰进行军事援助，援助规模该有多大。</strong>无辜被侵略的乌克兰提出来的要求，将前几届德国联邦政府的政治误判和错误的路径选择迅速转化成了道德勒索，这些要求是如此地合情合理，正如它们在我们所有人心里激起的情绪、同情和援助意愿是如此地理所当然。</p><center>    <img         style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 40em;"   src="https://mmbiz.qpic.cn/mmbiz_png/UsTHnrACwn1OoU2ZY81nu8PuvchiaPhAJqG7Zmxonlbl61vp6jfZKOxRzFyDolzEdEhZqEIMZBknGiaiaDcr8xnsA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" />    <div         style="color: #999; padding: 2px;font-size:0.8em">        德国总理朔尔茨    </div></center><p>在德国，在行动方面显得深思熟虑和谨慎保守的联邦政府遭到了激于义愤的指责，可这些责难者所显示出来的笃定的自信令我感到困惑。联邦总理在接受《明镜》采访时说的一句话提到了其政策的要点：<strong>“我们正在用一切手段对抗俄罗斯在乌克兰造成的损害，前提是这不会带来一场失控的事态升级，以至于给整个大陆、甚至是整个世界带来无可估量的损害。”**</strong>西方已然决定不以参战方的身份介入这场冲突，在此之后就存在一个风险界限，它排除了对武装乌克兰的无限制投入。**我国政府最近同盟友在拉姆施泰因达成的共同阵线（注：指4月26日在德国拉姆施泰因美军基地召开的针对乌克兰自卫问题的会议，美国邀请了来自 40个国家的国防部长和代表参加），以及拉夫罗夫重新做出的使用核武器的威胁，都再次将这一界限摆到了刺眼的光线之下。罔顾该界限，想要以进攻性的自信高调不断将联邦总理推向这一方向的人，忽视或误解了西方因为这场战争而陷入的两难；因为西方已经因不参战这一具有充分道德依据的决定而自缚双手。</p><p> <strong>2</strong>  <strong>联邦总理坚持做在政治上负责的权衡是正确的</strong></p><p>当前的两难局面要求西方在两个极端之间进行充满风险的权衡——<strong>一端是乌克兰的败北，另一端是一场有限的冲突升级为第三次世界大战</strong>——这再明显不过了。一方面，我们已从冷战中得到了一条教训，即针对一个有核国家的战争已不再可能在任何理性的意义上“获胜”，至少不可能在一场热战的可以预期的时限之内通过军事手段实现。核武器的威胁潜力带来的后果是，<strong>受到威胁的一方，无论它自身是否拥有核武器，都无法用一场胜利来终结动用武力所造成的绝对无法承受的毁伤，最好的情况是用一种保全双方脸面的妥协来收场。**</strong>在此前提之下，不能指望任何一方落败，从而被迫以“失败者”的身份退场。**目前同战事并行开展的停火谈判就是这种观念的体现；双方都保留着将对方看作可能的谈判对象的目光。尽管俄罗斯的威胁潜力取决于西方相信普京会使用核生化武器。但事实上，过去数周里CIA已经警告说存在使用所谓“小型”核武器的现实危险（这类武器被研发出来的目的显然是令有核国家之间的战争再次成为可能）。这赋予了俄罗斯方面一种相对于北约的非对称优势，后者鉴于世界大战的毁灭性规模——多达四个有核国家会卷入其中——而不愿意成为参战方。</p><p>目前普京正在判断西方于何时越过国际法所定义的界限，之后他就可以将对乌克兰的军事援助视为西方名义上的参战。</p><p><strong>鉴于必须无条件地避免世界毁灭的风险，这一判断的不确定性没有给冒险的下注行为留下任何操作空间。</strong>哪怕西方满不在乎地将使用“小型”核武器的“警告”作为一种风险纳入考量，即在最糟的情况下予以容忍，谁又能保证，到了这个地步还能制止事态升级？余留下的活动空间就是必须带着专业领域必不可少的知识和一切必要的、并不总是对公众开放的信息来小心地斟酌各种论据，以便做出有理有据的决断。西方从一开始就施加了严厉的制裁，他们事实上的参战早已不容怀疑，因此在军事援助方面每迈出新的一步都要小心斟酌，这样做是否会跨过那条因为取决于普京的定义权而并不确定的界线，从而成为名义上的参战国。</p><p><strong>另一方面，由于这种不对称性，西方可以——正如俄方也知道的那样——不让自己被任意勒索。</strong>假使西方对乌克兰坐视不管，那么这不仅在政治道德的视角下是一桩丑闻，而且也不符合其自身的利益。因为在这种情况下西方就必然预料到，接下来将不得不在格鲁吉亚或摩尔多瓦再玩一遍和这回一样的俄罗斯轮盘赌——然后又会轮到谁？毫无疑问，只有在西方有充分的理由畏惧承担一场世界核大战的风险时，这种长远来看可能将西方逼至死胡同的不对称性才会持续存在。因此那种认为不能把普京逼至死角、否则他可能做出任何事的论据就遭到了驳斥，因为这种“畏惧的政策”会让对手放开手脚一步一步地推动冲突升级（Ralf Fücks发表于《南德意志报》的评论）。当然这种论据也只是确证了局势的难以预测。因为只要我们有充分的理由决定不作为新的参战方加入战争以守卫乌克兰，那么就必须从这一角度对军事援助的方式和规模加以评定。以理性可以接受的方式反对“畏惧的政策”的人，自身就已经在政治上负责且在事务上有着全面了解的权衡的论证空间里活动，而联邦总理奥拉夫·朔尔茨坚持这种权衡是正确的。</p><p> <strong>3</strong>  <strong>德国的主流媒体正在散布对普京的猜想</strong></p><p>这里涉及到的是恪守对我们给自己划出的那条由法律所定义的界线的解读，在我们看来这种解读对普京来说也是值得认同的。那些激动地反对政府路线的人，当他们拒绝承认他们并不质疑的原则性决定的潜在后果时，就是前后矛盾的。不参战的决定并不意味着，西方只要还没有直接介入就不得不坐视乌克兰队独自对抗远胜于己的对手。乌克兰自己已决定不惜付出巨大牺牲也要继续抗争，而西方的武器供应显然能够对其进程产生积极影响。但在不亲手拿起武器的情况下寄希望于乌克兰打赢这场俄罗斯发起的残酷战争，这岂不是一厢情愿的自我欺骗？战争煽动者坐在观众席上大放厥词，他们的言论和其所处的位置是不匹配的。因为这种言论无法否定一个有可能孤注一掷的对手的不可预测性。<strong>西方的两难之处在于，西方只能通过自我限制的、始终不越过国际法所定义的参战行为红线的对乌军事援助来彰显其原则，即西方坚持欧洲各国边界的完整。</strong></p><p>对进行着自我限制的军事援助加以冷静的斟酌本就不易，加上还要揣测是什么动机促使俄罗斯方面做出这一明显失算的决定，这事就变得愈加复杂。对普京个人的关注导致出现了五花八门的猜想，我们的主流媒体如今正在散布这些猜想，仿佛正处于臆想性的苏维埃学的全盛时期。<strong>现在占据主导的普京形象是一个坚定的修正主义者，这一观点至少需要我们理性地分析其利益诉求来加以平衡。</strong>即使普京认为苏联解体是个大错，把他看成一个异想天开的梦想家，认为他带着俄罗斯东正教的赐福并受到权威主义意识形态专家亚历山大·杜金的影响，把逐步重建大俄罗斯帝国当作自己毕生的政治使命，这种观点也很难反映其个性的全部真相。但基于这种心理投射又发展出了一个被广泛接受的设想，即普京的侵略意图已超出乌克兰而指向格鲁吉亚和摩尔多瓦，接着又延伸至已加入北约的波罗的海三国，并最终深入巴尔干半岛。</p><p> <strong>4</strong>  <strong>那能够在这场针对有核国家的战争中“获胜”吗？</strong></p><p>普京是一位受妄想驱使着的历史怀旧者。但与这样的人物形象相悖的是：他有着社会地位不断跃升的履历，曾在克格勃受训、任职并发迹，是一个精于理性计算的权力强人。而乌克兰的西向以及白俄罗斯境内的政治反抗运动又增强了他对本国不断发展壮大的自由主义思想团体的政治抗议的顾虑。从这个角度来讲，<strong>一再上演的侵略行为或许更应看作是在沮丧地回应西方的拒绝态度——拒绝就普京的地缘政治议程展开磋商，特别是拒绝在国际上承认他违反国际法的占领区，以及拒绝也应包括乌克兰在内的“前沿地带”的中立化。</strong>此类以及类似的各种猜想只会加深这一两难困境的不确定性，而这一困境“要求最大程度的谨慎和克制”（ 这是Peter Graf Kielmansegg2022年4月19日发表于《法兰克福汇报》上的富有教益的分析文章的结语。）</p><p>但是，那如何解释在内政方面所掀起的关于由联邦总理朔尔茨不断强化的政策——这一政策试图在与欧盟伙伴和北约伙伴的协调一致中审慎地确保与乌克兰的团结——的激烈讨论呢？为了解开这些问题，我将撇开关于是否继续对已变得不可预测的普京采取缓和政策这一问题的争议，这一政策在苏联结束之前甚至之后都是成功的，而现在却被证明是一个重大错误；同样，我也将撇开德国政府所犯的、部分出于经济压力而使自己依赖进口自俄罗斯的廉价石油的错误。今天的这些争论所形成的短暂记忆，有一天将由历史学家的判断来决定。</p><p>但在“新的德国认同危机”这个意味深长的名称下所展开的争论则是另一番状况。这个争论现在就已经在探讨“时代转折”的影响，而这个时代转折最初仅涉及到德国的东方政策和国防预算。之所以说这个争论是不一般的，<strong>乃是因为它首先与那些倡导和平运动的人物的惊人转变有关，而且预告了德国人的那种不断受到右翼谴责、且实际上来之不易的战后心态的历史性转变，因此也预告了以对话和维护和平为主旨的德国政治模式的完全结束。</strong></p><center>    <img         style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36,38,.12), 0 2px 10px 0 rgba(34,36,38,.08);width: 40em;"   src="https://mmbiz.qpic.cn/mmbiz_png/UsTHnrACwn1OoU2ZY81nu8PuvchiaPhAJc0qGF3jwtUuIgVOAcJy2VWC9MBiculKMjtFSWXtyKn2UJFPUHDH3rqQ/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" />    <div         style="color: #999; padding: 2px;font-size:0.8em">        ▲ 德国外长贝尔伯克    </div></center><p> <strong>5</strong>  <strong>情绪激动的外交部长已经成了一个偶像</strong></p><p>这种解读体现在那些被培养得对规范性问题尤为敏感的追随者的例子上，他们不掩饰自己的情绪，最大声地要求更强有力的参与。他们给人的印象是，全新的战争现实已经把他们从和平主义的幻想中惊醒。这也让人联想到已经成为偶像的外交部长，她在战争开始后就紧接着以令人信赖的肢体语言和忏悔式的言辞真实地表达了这种震惊。这并不是说，她以此并未代表在我国民众中普遍存在的同情心以及试图援助的冲动；但除此之外，她也让人信服地促成了对决心取胜的乌克兰领导层的急躁的道德说教的自发认同。这样，我们就触及到了两派人之间冲突的核心，<strong>一派人更为感同身受，但仓促地认同着一个国家为他们的自由、权利和生命而战的观点；另一派的人则从冷战的经历中吸取了不同的教训，</strong>并且——就像那些在我们的街头抗议的人那样——形成了不同的心态。<strong>一派人只能在胜利或失败的选项下来设想战争，而另一些人则知道，针对有核国家的战争已经无法在传统意义上“获胜”。</strong></p><p>粗略来讲，民众偏民族性的心理和偏后民族性的心理构成了对战争的不同态度的背景。当我们把乌克兰人民令人钦佩的英勇抵抗和视死如归的牺牲精神与在类似情况下对“我们”——让我们宽泛地讲——西欧人民的期望相比，那这种差异就变得很明显。我们的钦佩中夹杂着某种惊讶，惊讶于士兵们以及为战斗而征召来的新兵们的必胜的信心和不屈不挠的勇气，他们冷峻地决心要保卫自己的祖国，对抗军事上远胜于他们的敌人。相比之下，我们西方国家则依靠职业军队，我们为之付费，以便在必要时，我们不必自己用手中的武器来保护自己，而可以由职业军人来保护。</p><p> <strong>6</strong>  <strong>另外, 仍然要与普京进行谈判</strong></p><p>20世纪下半叶，在美国的核保护伞下，这种后英雄主义的心态在西欧——如果允许我这样泛化地来讲的话——得到了发展。鉴于核战争可能造成的大破坏，这样一种观点在政治精英和绝大多数民众中蔓延开来，即：<strong>国际冲突原则上只能通过外交和制裁来得到解决；在爆发军事冲突的情况下，战争必须尽快得到调停，因为鉴于难以估算的行将使用核生化武器的风险，战争基本上已经不能在传统意义上以胜利或失败而结束。**</strong>“人们从战争中唯独能学到的就是去创造和平”**，亚历山大·克鲁格（Alexander Kluge）这样说到。这种取向并不意味着全盘的和平主义，即不惜一切代价来保证和平。试图尽快结束毁灭性活动、结束人类的牺牲和反文明活动的这种倾向，并不等同于要求为了单纯保命而牺牲政治上的自由。看来，在面对专制窒息的生活所要求的代价时，对战争暴力手段的质疑就受到了限制——在那种生活中，甚至都还不会意识到强制的规范性与自我决定的生活之间的矛盾。</p><p><strong>时代转折的右翼解释者们欢迎着我们以前的和平主义者的转变。这个转变，在我看来，乃是出于对那两种同时间互相冲突、但在历史上并不同时出现的心态的混淆。</strong>这个独特的群体与乌克兰人一样，对胜利充满着信心，并以极大的信心呼吁回到已受蹂躏的国际法。在布恰事件之后，“送普京去海牙！”的口号就飞快传开了。<strong>这在总体上表明了我们今天在国际关系方面所设的规范标准的自明性，亦即表明了民众的相应期望以及在人道主义方面的敏感度的实际变化程度。</strong></p><p>在我这个年纪，我并不掩饰某种惊讶：甚至那保守的媒体都呼吁国际刑事法庭指派一名检察官，尽管该法庭既不被俄罗斯和中国也不被美国承认，可见我们的子孙今天生存于其上的、自然而然的文化土壤，已经被翻耕得多深了。可惜，在这样的现实状况中，对德国克制态度的日益尖锐的道德谴责所激起的广泛认同也仍旧暴露出空乏的基础。<strong>若要结束战争，或至少是停火，就仍需与普京进行谈判。</strong>我看不出有什么令人信服的理由来要求采取那种在事实上会使不参与这场战争的合理决定面临危险的政策，哪怕在极为痛苦地、愈加无法忍受地目睹每天的悲惨受害者的情景下。</p><p> <strong>7</strong>  <strong>前和平主义者的转变导致了错误和误解</strong></p><p><strong>从不同的历史发展时期中可以得到解释的那些政治心理差异，不应被联盟成员用于相互谴责；联盟成员们应将这些差异作为事实加以认识，并在合作中明智地将其考虑在内。</strong>但只要这些视角上的差异仍还处在背景中，那它们就只会造成情感上的混乱，即不成熟的赞同反应、对他人观点的单纯理解和被给予的自尊之间的杂混，就像是当乌克兰总统在联邦议院进行视频演讲并呼吁道德秩序的时候议员们做出反应时的状况那样。<strong>回顾历史，就可以解释人们在对战争的认识和解释上的差异。</strong>而忽视这些差异，则不仅会导致在相互交往中出现的重大错误，比如粗暴地拒绝德国联邦总统访问的情况。更糟的是，这将会导致彼此对对方实际想法和愿望的误解。</p><p>这种认识也使我们能够更清醒地理解前和平主义者的转变。因为构成他们草率要求之动机背景的是愤慨、惊恐和同情，而这些并不能从他们对所谓的现实主义者一向嘲讽的规范性取向的放弃当中得到解释,而恰是出自对这些原则的过于精简的解读。<strong>他们并未转变成现实主义者，而是一头栽进了现实主义：当然，没有道德感受，就没有道德判断；但普遍性的判断也反而纠正着在近处被激发起的感受的有限作用范围。</strong></p><p>讨论“时代转折”的人是那些左派和自由主义者，这毕竟不是一个偶然。他们在一个急剧变化的大国局势面前，并且在跨大西洋关系的不确定性的阴影下，想要认真对待一个早该有的认识：<strong>欧盟，如果既不想让它的社会生活和政治生活方式从外部遭到破坏，也不想让它们在内部遭到侵蚀，那就**</strong>只有在军事上也能自立的情况下，才能具有政治上的行动力。**<strong>马克龙的连任标志着一种缓和。</strong>但首先我们必须从我们的困境中找到一个建设性的出口。这种希望反映在谨慎地提出乌克兰不能输掉这场战争的目标上。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/%E4%BB%8E%E5%AE%87%E5%AE%99%E8%B5%B7%E6%BA%90%E5%88%B0%E4%BA%BA%E7%B1%BB%E6%96%87%E6%98%8E/">从宇宙起源到人类文明</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E4%BA%BA%E9%97%B4%E4%B8%96/">人间世</category>
      
      
      <comments>https://blog.helloallen.cn/33872f8c/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>一文带你快速上手Rollup</title>
      <link>https://blog.helloallen.cn/fb5d0dd3/</link>
      <guid>https://blog.helloallen.cn/fb5d0dd3/</guid>
      <pubDate>Thu, 08 Feb 2024 11:44:37 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>项目中一直用的都是webpack，前一段需要开发几个类库供其他平台使用，本来打算继续用webpack的，但感觉webpack用来开发js库，不仅繁琐而且打包后的文件体积也比较大。正好之前看vue源码，知道vue也是通过rollup打包的。这次又是开发类库的，于是就快速上手了rollup。</p><p>本篇文章是我有了一定的项目实践后，回过来给大家分享一下如何从零快速上手rollup。</p><h2 id="一、什么是rollup？"><a href="#一、什么是rollup？" class="headerlink" title="一、什么是rollup？"></a>一、什么是rollup？</h2><p>系统的了解rollup之前，我们先来简单了解下What is rollup？</p><p>关于rollup的介绍，官方文档已经写的很清楚了：</p><blockquote><p>Rollup 是一个 JavaScript 模块打包器，可以将小块代码编译成大块复杂的代码，例如 library 或应用程序。</p></blockquote><p>与Webpack偏向于应用打包的定位不同，rollup.js更专注于Javascript类库打包。</p><p>我们熟知的Vue、React等诸多知名框架或类库都是通过rollup.js进行打包的。</p><h2 id="二、为什么是rollup？"><a href="#二、为什么是rollup？" class="headerlink" title="二、为什么是rollup？"></a>二、为什么是rollup？</h2><p>webpack我相信做前端的同学大家都用过，那么为什么有些场景还要使用rollup呢？这里我简单对webpack和rollup做一个比较：</p><p>总体来说webpack和rollup在不同场景下，都能发挥自身优势作用。webpack对于代码分割和静态资源导入有着“先天优势”，并且支持热模块替换(HMR)，而rollup并不支持。</p><p>所以当开发应用时可以优先选择webpack，但是rollup对于代码的Tree-shaking和ES6模块有着算法优势上的支持，若你项目只需要打包出一个简单的bundle包，并是基于ES6模块开发的，可以考虑使用rollup。</p><p>其实webpack从2.0开始就已经支持Tree-shaking，并在使用babel-loader的情况下还可以支持es6 module的打包。实际上，rollup已经在渐渐地失去了当初的优势了。但是它并没有被抛弃，反而因其简单的API、使用方式被许多库开发者青睐，如React、Vue等，都是使用rollup作为构建工具的。</p><h2 id="三、快速上手"><a href="#三、快速上手" class="headerlink" title="三、快速上手"></a>三、快速上手</h2><p>我们先花大概十分钟左右的时间来了解下rollup的基本使用以及完成一个hello world。</p><h3 id="1-安装"><a href="#1-安装" class="headerlink" title="1. 安装"></a>1. 安装</h3><p>首先全局安装rollup：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i rollup -g</span><br></pre></td></tr></table></figure><h3 id="2-目录准备（hello-world）"><a href="#2-目录准备（hello-world）" class="headerlink" title="2. 目录准备（hello world）"></a>2. 目录准备（hello world）</h3><p>接着，我们初始化一个如下所示的项目目录</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">├── dist # 编译结果</span><br><span class="line">├── example # HTML引用例子</span><br><span class="line">│ └── index.html</span><br><span class="line">├── package.json</span><br><span class="line">└── src # 源码</span><br><span class="line">└── index.js</span><br></pre></td></tr></table></figure><p>首先我们在src/index.js中写入如下代码：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">console.log(&quot;柯森&quot;);</span><br></pre></td></tr></table></figure><p>然后在命令行执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rollup src/index.js -f umd -o dist/bundle.js</span><br></pre></td></tr></table></figure><p>执行命令，我们即可在dist目录下生成bundle.js文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (factory) &#123;</span><br><span class="line">typeof define === &#x27;function&#x27; &amp;&amp; define.amd ? define(factory) :</span><br><span class="line">factory();</span><br><span class="line">&#125;((function () &#123; &#x27;use strict&#x27;;</span><br><span class="line"></span><br><span class="line">console.log(&quot;柯森&quot;);</span><br><span class="line"></span><br><span class="line">&#125;)));</span><br></pre></td></tr></table></figure><p>这时，我们再在example/index.html中引入上面打包生成的bundle.js文件，打开浏览器：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081146526.webp"></p><p>如我们所预料的，控制台输出了柯森。</p><p>到这里，我们就用rollup打包了一个最最简单的demo。</p><p>可能很多同学看到这里对于上面命令行中的参数不是很明白，我依次说明下：</p><ul><li>-f。-f参数是–format的缩写，它表示生成代码的格式，amd表示采用AMD标准，cjs为CommonJS标准，esm（或 es）为ES模块标准。-f的值可以为amd、cjs、system、esm（’es’也可以）、iife或umd中的任何一个。</li><li>-o。-o指定了输出的路径，这里我们将打包后的文件输出到dist目录下的bundle.js</li></ul><p>其实除了这两个，还有很多其他常用的命令（这里我暂且列举剩下两个也比较常用的，完整的<a href="https://link.zhihu.com/?target=https://rollupjs.org/guide/en/%23command-line-flags">rollup 命令行参数</a>）：</p><ul><li>-c。指定rollup的配置文件。</li><li>-w。监听源文件是否有改动，如果有改动，重新打包。</li></ul><h3 id="3-使用配置文件-rollup-config-js"><a href="#3-使用配置文件-rollup-config-js" class="headerlink" title="3. 使用配置文件(rollup.config.js)"></a>3. 使用配置文件(rollup.config.js)</h3><p>使用命令行的方式，如果选项少没什么问题，但是如果添加更多的选项，这种命令行的方式就显得麻烦了。</p><p>为此，我们可以创建配置文件来囊括所需的选项</p><p>在项目中创建一个名为rollup.config.js的文件，增加如下代码：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">export default &#123;</span><br><span class="line">  input: [&quot;./src/index.js&quot;],</span><br><span class="line">  output: &#123;</span><br><span class="line">    file: &quot;./dist/bundle.js&quot;,</span><br><span class="line">    format: &quot;umd&quot;,</span><br><span class="line">    name: &quot;experience&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>然后命令行执行：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rollup -c</span><br></pre></td></tr></table></figure><p>打开dist/bundle.js文件，我们会发现和上面采用命令行的方式打包出来的结果是一样的。</p><p>这里，我对配置文件的选项做下简单的说明：</p><ul><li><p>input表示入口文件的路径（老版本为 entry，已经废弃）</p></li><li><p>output表示输出文件的内容，它允许传入一个对象或一个数组，当为数组时，依次输出多个文件，它包含以下内容：</p></li><li><ul><li>output.file：输出文件的路径（老版本为 dest，已经废弃）</li><li>output.format：输出文件的格式</li><li>output.banner：文件头部添加的内容</li><li>output.footer：文件末尾添加的内容</li></ul></li></ul><p>到这里，相信你已经差不多上手rollup了。</p><h2 id="四、进阶"><a href="#四、进阶" class="headerlink" title="四、进阶"></a>四、进阶</h2><p>但是，这对于真实的业务场景是远远不够的。</p><p>下面，我将介绍rollup中的几种常用的插件以及external属性、tree-shaking机制。</p><h3 id="1-resolve插件"><a href="#1-resolve插件" class="headerlink" title="1. resolve插件"></a>1. resolve插件</h3><h4 id="（1）为什么要使用resolve插件"><a href="#（1）为什么要使用resolve插件" class="headerlink" title="（1）为什么要使用resolve插件"></a>（1）为什么要使用resolve插件</h4><p>在上面的入门案例中，我们打包的对象是本地的js代码和库，但实际开发中，不太可能所有的库都位于本地，我们大多会通过npm下载远程的库。</p><p>与webpack和browserify这样的其他捆绑包不同，rollup不知道如何打破常规去处理这些依赖。因此我们需要添加一些配置。</p><h4 id="（2）resolve插件使用"><a href="#（2）resolve插件使用" class="headerlink" title="（2）resolve插件使用"></a>（2）resolve插件使用</h4><p>首先在我们的项目中添加一个依赖the-answer，然后修改src/index.js文件:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import answer from &quot;the-answer&quot;;</span><br><span class="line"></span><br><span class="line">export default function () &#123;</span><br><span class="line">  console.log(&quot;the answer is &quot; + answer);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>执行npm run build。</p><blockquote><p>这里为了方便，我将原本的rollup -c -w添加到了package.json的scripts中：”build”: “rollup -c -w”</p></blockquote><p>会得到以下报错：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081147575.webp"></p><p>打包后的bundle.js仍然会在Node.js中工作，但是the-answer不包含在包中。为了解决这个问题，将我们编写的源码与依赖的第三方库进行合并，rollup.js为我们提供了resolve插件。</p><p>首先，安装resolve插件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i -D @rollup/plugin-node-resolve</span><br></pre></td></tr></table></figure><p>修改配置文件rollup.config.js：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import resolve from &quot;@rollup/plugin-node-resolve&quot;;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  input: [&quot;./src/index.js&quot;],</span><br><span class="line">  output: &#123;</span><br><span class="line">    file: &quot;./dist/bundle.js&quot;,</span><br><span class="line">    format: &quot;umd&quot;,</span><br><span class="line">    name: &quot;experience&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [resolve()],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>这时再次执行npm run build，可以发现报错已经没有了：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081150716.png"></p><p>打开dist/bundle.js文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (global, factory) &#123;</span><br><span class="line">  typeof exports === &quot;object&quot; &amp;&amp; typeof module !== &quot;undefined&quot;</span><br><span class="line">    ? (module.exports = factory())</span><br><span class="line">    : typeof define === &quot;function&quot; &amp;&amp; define.amd</span><br><span class="line">    ? define(factory)</span><br><span class="line">    : ((global =</span><br><span class="line">        typeof globalThis !== &quot;undefined&quot; ? globalThis : global || self),</span><br><span class="line">      (global.experience = factory()));</span><br><span class="line">&#125;)(this, function () &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  var index = 42;</span><br><span class="line"></span><br><span class="line">  function index$1() &#123;</span><br><span class="line">    console.log(&quot;the answer is &quot; + index);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  return index$1;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>打包文件bundle.js中已经包含了引用的模块。</p><p>有些场景下，虽然我们使用了resolve插件，但可能我们仍然想要某些库保持外部引用状态，这时我们就需要使用external属性，来告诉rollup.js哪些是外部的类库。</p><h3 id="2-external-属性"><a href="#2-external-属性" class="headerlink" title="2. external 属性"></a>2. external 属性</h3><p>修改rollup.js的配置文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import resolve from &quot;@rollup/plugin-node-resolve&quot;;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  input: [&quot;./src/index.js&quot;],</span><br><span class="line">  output: &#123;</span><br><span class="line">    file: &quot;./dist/bundle.js&quot;,</span><br><span class="line">    format: &quot;umd&quot;,</span><br><span class="line">    name: &quot;experience&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [resolve()],</span><br><span class="line">  external: [&quot;the-answer&quot;],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>重新打包，打开dist/bundle.js文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (global, factory) &#123;</span><br><span class="line">  typeof exports === &quot;object&quot; &amp;&amp; typeof module !== &quot;undefined&quot;</span><br><span class="line">    ? (module.exports = factory(require(&quot;the-answer&quot;)))</span><br><span class="line">    : typeof define === &quot;function&quot; &amp;&amp; define.amd</span><br><span class="line">    ? define([&quot;the-answer&quot;], factory)</span><br><span class="line">    : ((global =</span><br><span class="line">        typeof globalThis !== &quot;undefined&quot; ? globalThis : global || self),</span><br><span class="line">      (global.experience = factory(global.answer)));</span><br><span class="line">&#125;)(this, function (answer) &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  function _interopDefaultLegacy(e) &#123;</span><br><span class="line">    return e &amp;&amp; typeof e === &quot;object&quot; &amp;&amp; &quot;default&quot; in e ? e : &#123; default: e &#125;;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  var answer__default = /*#__PURE__*/ _interopDefaultLegacy(answer);</span><br><span class="line"></span><br><span class="line">  function index() &#123;</span><br><span class="line">    console.log(&quot;the answer is &quot; + answer__default[&quot;default&quot;]);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  return index;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>这时我们看到the-answer已经是做为外部库被引入了。</p><h3 id="3-commonjs插件"><a href="#3-commonjs插件" class="headerlink" title="3. commonjs插件"></a>3. commonjs插件</h3><h4 id="（1）为什么需要commonjs插件"><a href="#（1）为什么需要commonjs插件" class="headerlink" title="（1）为什么需要commonjs插件"></a>（1）为什么需要commonjs插件</h4><p>rollup.js编译源码中的模块引用默认只支持 ES6+的模块方式import/export。然而大量的npm模块是基于CommonJS模块方式，这就导致了大量 npm模块不能直接编译使用。</p><p>因此使得rollup.js编译支持npm模块和CommonJS模块方式的插件就应运而生：@rollup/plugin-commonjs。</p><h4 id="（2）commonjs插件使用"><a href="#（2）commonjs插件使用" class="headerlink" title="（2）commonjs插件使用"></a>（2）commonjs插件使用</h4><p>首先，安装该模块：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i -D @rollup/plugin-commonjs</span><br></pre></td></tr></table></figure><p>然后修改rollup.config.js文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import resolve from &quot;@rollup/plugin-node-resolve&quot;;</span><br><span class="line">import commonjs from &quot;@rollup/plugin-commonjs&quot;;</span><br><span class="line">export default &#123;</span><br><span class="line">  input: [&quot;./src/index.js&quot;],</span><br><span class="line">  output: &#123;</span><br><span class="line">    file: &quot;./dist/bundle.js&quot;,</span><br><span class="line">    format: &quot;umd&quot;,</span><br><span class="line">    name: &quot;experience&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [resolve(), commonjs()],</span><br><span class="line">  external: [&quot;the-answer&quot;],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="4-babel插件"><a href="#4-babel插件" class="headerlink" title="4. babel插件"></a>4. babel插件</h3><h4 id="（1）为什么需要babel插件？"><a href="#（1）为什么需要babel插件？" class="headerlink" title="（1）为什么需要babel插件？"></a>（1）为什么需要babel插件？</h4><p>我们在src目录下添加es6.js文件(⚠️ 这里我们使用了 es6 中的箭头函数)：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const a = 1;</span><br><span class="line">const b = 2;</span><br><span class="line">console.log(a, b);</span><br><span class="line">export default () =&gt; &#123;</span><br><span class="line">  return a + b;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>然后修改rollup.config.js配置文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import resolve from &quot;@rollup/plugin-node-resolve&quot;;</span><br><span class="line">import commonjs from &quot;@rollup/plugin-commonjs&quot;;</span><br><span class="line">export default &#123;</span><br><span class="line">  input: [&quot;./src/es6.js&quot;],</span><br><span class="line">  output: &#123;</span><br><span class="line">    file: &quot;./dist/esBundle.js&quot;,</span><br><span class="line">    format: &quot;umd&quot;,</span><br><span class="line">    name: &quot;experience&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [resolve(), commonjs()],</span><br><span class="line">  external: [&quot;the-answer&quot;],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>执行打包，可以看到dist/esBundle.js文件内容如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (global, factory) &#123;</span><br><span class="line">  typeof exports === &quot;object&quot; &amp;&amp; typeof module !== &quot;undefined&quot;</span><br><span class="line">    ? (module.exports = factory())</span><br><span class="line">    : typeof define === &quot;function&quot; &amp;&amp; define.amd</span><br><span class="line">    ? define(factory)</span><br><span class="line">    : ((global =</span><br><span class="line">        typeof globalThis !== &quot;undefined&quot; ? globalThis : global || self),</span><br><span class="line">      (global.experience = factory()));</span><br><span class="line">&#125;)(this, function () &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  const a = 1;</span><br><span class="line">  const b = 2;</span><br><span class="line">  console.log(a, b);</span><br><span class="line">  var es6 = () =&gt; &#123;</span><br><span class="line">    return a + b;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  return es6;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>可以看到箭头函数被保留下来，这样的代码在不支持ES6的环境下将无法运行。我们期望在rollup.js打包的过程中就能使用babel完成代码转换，因此我们需要babel插件。</p><h4 id="（2）babel插件的使用"><a href="#（2）babel插件的使用" class="headerlink" title="（2）babel插件的使用"></a>（2）babel插件的使用</h4><p>首先，安装：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i -D @rollup/plugin-babel</span><br></pre></td></tr></table></figure><p>同样修改配置文件rollup.config.js：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import resolve from &quot;@rollup/plugin-node-resolve&quot;;</span><br><span class="line">import commonjs from &quot;@rollup/plugin-commonjs&quot;;</span><br><span class="line">import babel from &quot;@rollup/plugin-babel&quot;;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  input: [&quot;./src/es6.js&quot;],</span><br><span class="line">  output: &#123;</span><br><span class="line">    file: &quot;./dist/esBundle.js&quot;,</span><br><span class="line">    format: &quot;umd&quot;,</span><br><span class="line">    name: &quot;experience&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [resolve(), commonjs(), babel()],</span><br><span class="line">  external: [&quot;the-answer&quot;],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>然后打包，发现会出现报错：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081154951.webp"></p><p>提示我们缺少@babel/core，因为@babel/core是babel的核心。我们来进行安装：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i @babel/core</span><br></pre></td></tr></table></figure><p>再次执行打包，发现这次没有报错了，但是我们尝试打开dist/esBundle.js：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (global, factory) &#123;</span><br><span class="line">  typeof exports === &quot;object&quot; &amp;&amp; typeof module !== &quot;undefined&quot;</span><br><span class="line">    ? (module.exports = factory())</span><br><span class="line">    : typeof define === &quot;function&quot; &amp;&amp; define.amd</span><br><span class="line">    ? define(factory)</span><br><span class="line">    : ((global =</span><br><span class="line">        typeof globalThis !== &quot;undefined&quot; ? globalThis : global || self),</span><br><span class="line">      (global.experience = factory()));</span><br><span class="line">&#125;)(this, function () &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  const a = 1;</span><br><span class="line">  const b = 2;</span><br><span class="line">  console.log(a, b);</span><br><span class="line">  var es6 = () =&gt; &#123;</span><br><span class="line">    return a + b;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  return es6;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>可以发现箭头函数仍然存在，显然这是不正确的，说明我们的babel插件没有起到作用。这是为什么呢？</p><p>原因是由于我们缺少.babelrc文件，添加该文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  &quot;presets&quot;: [</span><br><span class="line">    [</span><br><span class="line">    &quot;@babel/preset-env&quot;,</span><br><span class="line">      &#123;</span><br><span class="line">        &quot;modules&quot;: false,</span><br><span class="line">        // &quot;useBuiltIns&quot;: &quot;usage&quot;</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我们看.babelrc配置了preset env，所以先安装这个插件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i @babel/preset-env</span><br></pre></td></tr></table></figure><p>这次再次执行打包，我们打开dist/esBundle.js文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (global, factory) &#123;</span><br><span class="line">  typeof exports === &quot;object&quot; &amp;&amp; typeof module !== &quot;undefined&quot;</span><br><span class="line">    ? (module.exports = factory())</span><br><span class="line">    : typeof define === &quot;function&quot; &amp;&amp; define.amd</span><br><span class="line">    ? define(factory)</span><br><span class="line">    : ((global =</span><br><span class="line">        typeof globalThis !== &quot;undefined&quot; ? globalThis : global || self),</span><br><span class="line">      (global.experience = factory()));</span><br><span class="line">&#125;)(this, function () &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  var a = 1;</span><br><span class="line">  var b = 2;</span><br><span class="line">  console.log(a, b);</span><br><span class="line">  var es6 = function () &#123;</span><br><span class="line">    return a + b;</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  return es6;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>可以看到箭头函数被转换为了function，说明babel插件正常工作。</p><h3 id="5-json插件"><a href="#5-json插件" class="headerlink" title="5. json插件"></a>5. json插件</h3><h4 id="（1）为什么要使用json插件？"><a href="#（1）为什么要使用json插件？" class="headerlink" title="（1）为什么要使用json插件？"></a>（1）为什么要使用json插件？</h4><p>在src目录下创建json.js文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">import json from &quot;../package.json&quot;;</span><br><span class="line">console.log(json.author);</span><br></pre></td></tr></table></figure><p>内容很简单，就是引入package.json，然后去打印author字段。</p><p>修改rollup.config.js配置文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import resolve from &quot;@rollup/plugin-node-resolve&quot;;</span><br><span class="line">import commonjs from &quot;@rollup/plugin-commonjs&quot;;</span><br><span class="line">import babel from &quot;@rollup/plugin-babel&quot;;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  input: [&quot;./src/json.js&quot;],</span><br><span class="line">  output: &#123;</span><br><span class="line">    file: &quot;./dist/jsonBundle.js&quot;,</span><br><span class="line">    format: &quot;umd&quot;,</span><br><span class="line">    name: &quot;experience&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [resolve(), commonjs(), babel()],</span><br><span class="line">  external: [&quot;the-answer&quot;],</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>执行打包，发现会发生如下报错：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081149454.webp"></p><p>提示我们缺少@rollup/plugin-json插件来支持json文件。</p><h4 id="（2）json插件的使用"><a href="#（2）json插件的使用" class="headerlink" title="（2）json插件的使用"></a>（2）json插件的使用</h4><p>来安装该插件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i -D @rollup/plugin-json</span><br></pre></td></tr></table></figure><p>同样修改下配置文件，将插件加入plugins数组即可。</p><p>然后再次打包，发现打包成功了，我们打开生成的dist/jsonBundle目录：</p><figure class="highlight plaintext"><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">(function (factory) &#123;</span><br><span class="line">  typeof define === &quot;function&quot; &amp;&amp; define.amd ? define(factory) : factory();</span><br><span class="line">&#125;)(function () &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  var name = &quot;rollup-experience&quot;;</span><br><span class="line">  var version = &quot;1.0.0&quot;;</span><br><span class="line">  var description = &quot;&quot;;</span><br><span class="line">  var main = &quot;index.js&quot;;</span><br><span class="line">  var directories = &#123;</span><br><span class="line">    example: &quot;example&quot;,</span><br><span class="line">  &#125;;</span><br><span class="line">  var scripts = &#123;</span><br><span class="line">    build: &quot;rollup -c -w&quot;,</span><br><span class="line">    test: &#x27;echo &quot;Error: no test specified&quot; &amp;&amp; exit 1&#x27;,</span><br><span class="line">  &#125;;</span><br><span class="line">  var author = &quot;Cosen&quot;;</span><br><span class="line">  var license = &quot;ISC&quot;;</span><br><span class="line">  var dependencies = &#123;</span><br><span class="line">    &quot;@babel/core&quot;: &quot;^7.11.6&quot;,</span><br><span class="line">    &quot;@babel/preset-env&quot;: &quot;^7.11.5&quot;,</span><br><span class="line">    &quot;the-answer&quot;: &quot;^1.0.0&quot;,</span><br><span class="line">  &#125;;</span><br><span class="line">  var devDependencies = &#123;</span><br><span class="line">    &quot;@rollup/plugin-babel&quot;: &quot;^5.2.0&quot;,</span><br><span class="line">    &quot;@rollup/plugin-commonjs&quot;: &quot;^15.0.0&quot;,</span><br><span class="line">    &quot;@rollup/plugin-json&quot;: &quot;^4.1.0&quot;,</span><br><span class="line">    &quot;@rollup/plugin-node-resolve&quot;: &quot;^9.0.0&quot;,</span><br><span class="line">  &#125;;</span><br><span class="line">  var json = &#123;</span><br><span class="line">    name: name,</span><br><span class="line">    version: version,</span><br><span class="line">    description: description,</span><br><span class="line">    main: main,</span><br><span class="line">    directories: directories,</span><br><span class="line">    scripts: scripts,</span><br><span class="line">    author: author,</span><br><span class="line">    license: license,</span><br><span class="line">    dependencies: dependencies,</span><br><span class="line">    devDependencies: devDependencies,</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  console.log(json.author);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>完美！！</p><h3 id="6-tree-shaking机制"><a href="#6-tree-shaking机制" class="headerlink" title="6. tree-shaking机制"></a>6. tree-shaking机制</h3><p>这里我们以最开始的src/index.js为例进行说明：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import answer from &quot;the-answer&quot;;</span><br><span class="line"></span><br><span class="line">export default function () &#123;</span><br><span class="line">  console.log(&quot;the answer is &quot; + answer);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>修改上述文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const a = 1;</span><br><span class="line">const b = 2;</span><br><span class="line">export default function () &#123;</span><br><span class="line">  console.log(a + b);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>执行打包。打开dist/bundle.js文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (global, factory) &#123;</span><br><span class="line">  typeof exports === &quot;object&quot; &amp;&amp; typeof module !== &quot;undefined&quot;</span><br><span class="line">    ? (module.exports = factory())</span><br><span class="line">    : typeof define === &quot;function&quot; &amp;&amp; define.amd</span><br><span class="line">    ? define(factory)</span><br><span class="line">    : ((global =</span><br><span class="line">        typeof globalThis !== &quot;undefined&quot; ? globalThis : global || self),</span><br><span class="line">      (global.experience = factory()));</span><br><span class="line">&#125;)(this, function () &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  var a = 1;</span><br><span class="line">  var b = 2;</span><br><span class="line">  function index() &#123;</span><br><span class="line">    console.log(a + b);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  return index;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>再次修改src/index.js文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const a = 1;</span><br><span class="line">const b = 2;</span><br><span class="line">export default function () &#123;</span><br><span class="line">  console.log(a);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>再次执行打包，打开打包文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">(function (global, factory) &#123;</span><br><span class="line">  typeof exports === &quot;object&quot; &amp;&amp; typeof module !== &quot;undefined&quot;</span><br><span class="line">    ? (module.exports = factory())</span><br><span class="line">    : typeof define === &quot;function&quot; &amp;&amp; define.amd</span><br><span class="line">    ? define(factory)</span><br><span class="line">    : ((global =</span><br><span class="line">        typeof globalThis !== &quot;undefined&quot; ? globalThis : global || self),</span><br><span class="line">      (global.experience = factory()));</span><br><span class="line">&#125;)(this, function () &#123;</span><br><span class="line">  &quot;use strict&quot;;</span><br><span class="line"></span><br><span class="line">  var a = 1;</span><br><span class="line">  function index() &#123;</span><br><span class="line">    console.log(a);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  return index;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>发现了什么？</p><p>我们发现关于变量b的定义没有了，因为源码中并没有用到这个变量。这就是ES模块著名的tree-shaking机制，它动态地清除没有被使用过的代码，使得代码更加精简，从而可以使得我们的类库获得更快的加载速度。</p><h2 id="五、总结"><a href="#五、总结" class="headerlink" title="五、总结"></a>五、总结</h2><p>本文大致向大家介绍了什么是rollup以及如何快速上手rollup。文中提到的这些其实只是冰山一角，rollup能玩的东西还有很多，关于更多可以去<a href="https://link.zhihu.com/?target=https://rollupjs.org/guide/en/">rollup 官网</a>查询</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA/">项目构建</category>
      
      
      <comments>https://blog.helloallen.cn/fb5d0dd3/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>使用pnpm workspace管理Monorepo架构</title>
      <link>https://blog.helloallen.cn/d1678c62/</link>
      <guid>https://blog.helloallen.cn/d1678c62/</guid>
      <pubDate>Thu, 08 Feb 2024 11:19:10 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>1、workspace：pnpm中使用workspace协议的目的是将拒绝解析除本地 workspace 包含的 package 之外的任何内容。也就是说如果引入的项目需要强制使用本地包，则可以使用workspace:协议 。</p><p>2、微前端和Monorepo的关系：Monorepo是一种单仓库多应用的代码管理方式。微前端是一种实现了多个子项目间样式隔离、JS隔离、路由、子项目通信等功能的项目架构模式。微前端使用Monorepo进行代码管理可以实现共享工程配置，同时又快捷地共享模块代码的功能。</p><p>3、pnpm：在使用monorepo方式管理项目时，会产生诸多问题，如幽灵依赖、依赖安装耗时的问题，需要使用pnpm进行解决这类问题。</p><p>所以，当仅仅需要对多个子项目间共享工程配置和模块间代码共享时使用Monorepo进行代码管理即可。</p><p>而当需要继承多个不同栈的模块或服务、每个模块需要独立开发部署、需要支持独立的生命周期和版本控制等时使用微前端。</p><p>在开发项目的过程中，我们需要在一个仓库中管理多个项目，每个项目有独立的依赖、脚手架，这种形式的项目结构我们称之为Monorepo，pnpm workspace就是管理这类项目的方案之一。</p><h2 id="一、pnpm"><a href="#一、pnpm" class="headerlink" title="一、pnpm"></a>一、pnpm</h2><p>pnpm代表performance npm（高性能的npmn），同npm和yarn，都属于javascript包管理安装工具，它较npm和yarn在性能上得到很大提升，被称为 快速地，节省磁盘空间的包管理工具。</p><h2 id="二、对比lerna-yarn"><a href="#二、对比lerna-yarn" class="headerlink" title="二、对比lerna+yarn"></a>二、对比lerna+yarn</h2><p>使用lerna+yarn组合，也可以实现Monorepo项目管理。但是相比来说，更推荐pnpm workspace来管理。</p><h2 id="三、构建一个Monorepo"><a href="#三、构建一个Monorepo" class="headerlink" title="三、构建一个Monorepo"></a>三、构建一个Monorepo</h2><p>先上最终的项目结构：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">Monorepo</span><br><span class="line">- umi-antd</span><br><span class="line">- web</span><br><span class="line">-- common1</span><br><span class="line">-- common2</span><br></pre></td></tr></table></figure><p>如上图，我们最终要创建如上图的一个项目结构，其中umi-antd是主项目，web文件夹下的都是子项目，供umi-antd调用。</p><h2 id="1、创建主项目"><a href="#1、创建主项目" class="headerlink" title="1、创建主项目"></a>1、创建主项目</h2><p>主项目这里是使用的umi项目，这里也可以构建基于其他打包工具的各类项目，只要是遵守package.json配置条例的项目，都是可以的。</p><p>构建umi项目</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pnpm dlx create-umi@latest</span><br></pre></td></tr></table></figure><p>这里选择创建Ant Design Pro项目。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">$ npx create-umi@latest</span><br><span class="line">? Pick Umi App Template › - Use arrow-keys. Return to submit.</span><br><span class="line">Simple App</span><br><span class="line">❯ Ant Design Pro</span><br><span class="line">Vue Simple App</span><br></pre></td></tr></table></figure><h2 id="2、创建子项目common1"><a href="#2、创建子项目common1" class="headerlink" title="2、创建子项目common1"></a>2、创建子项目common1</h2><ul><li>进入Monorepo&gt;web目录，创建common1文件夹</li><li>然后进入common1目录，执行命令npm init对项目进行初始化，这时候会生产一个package.json文件</li></ul><p>新建index.ts文件，代码如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">export default function print(msg:string) &#123;</span><br><span class="line">    console.log(msg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3、创建子项目common2"><a href="#3、创建子项目common2" class="headerlink" title="3、创建子项目common2"></a>3、创建子项目common2</h2><p>步骤和创建common1一致</p><h2 id="4、主项目中引入子项目"><a href="#4、主项目中引入子项目" class="headerlink" title="4、主项目中引入子项目"></a>4、主项目中引入子项目</h2><p>安装common1和common2。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">pnpm -F umi-antd add common1</span><br><span class="line">pnpm -F umi-antd add common2</span><br></pre></td></tr></table></figure><p>安装完成后，在umi-antd依赖中出现两个子项目的软链接（或者叫符号链接）。</p><p>在业务代码中调用子项目输出的方法：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">//umi-antd\src\pages\Home\index.tsx</span><br><span class="line"></span><br><span class="line">import Guide from &#x27;@/components/Guide&#x27;;</span><br><span class="line">import &#123; trim &#125; from &#x27;@/utils/format&#x27;;</span><br><span class="line">import &#123; PageContainer &#125; from &#x27;@ant-design/pro-components&#x27;;</span><br><span class="line">import &#123; useModel &#125; from &#x27;@umijs/max&#x27;;</span><br><span class="line">import styles from &#x27;./index.less&#x27;;</span><br><span class="line">import print1 from &#x27;common1&#x27;;</span><br><span class="line">import print2 from &#x27;common2&#x27;;</span><br><span class="line"></span><br><span class="line">const HomePage: React.FC = () =&gt; &#123;</span><br><span class="line">  const &#123; name &#125; = useModel(&#x27;global&#x27;);</span><br><span class="line">  print1(&quot;umi-antd中调用common1&quot;);</span><br><span class="line">  print2(&quot;umi-antd中调用common2&quot;);</span><br><span class="line">  return (</span><br><span class="line">    &lt;PageContainer ghost&gt;</span><br><span class="line">      &lt;div className=&#123;styles.container&#125;&gt;</span><br><span class="line">        &lt;Guide name=&#123;trim(name)&#125; /&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/PageContainer&gt;</span><br><span class="line">  );</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">export default HomePage;</span><br></pre></td></tr></table></figure><h2 id="5、运行主项目"><a href="#5、运行主项目" class="headerlink" title="5、运行主项目"></a>5、运行主项目</h2><p>到这里基本搭建完毕，这时候的整体项目结构如图：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081120071.png"></p><p>然后执行命令启动主项目：pnpm -F umi-antd start，我们可以看到，控制台打印出来子模块中的信息。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081121312.png"></p><h2 id="6、子模块调用子模块"><a href="#6、子模块调用子模块" class="headerlink" title="6、子模块调用子模块"></a>6、子模块调用子模块</h2><p>子模块也是可以相互调用的，这里我们在common1中引入common2的方法。</p><ul><li><p>执行命令pnpm -F common1 add common2</p></li><li><p>在common1中调用common2中方法，代码如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">//web\common1\index.ts</span><br><span class="line">import print2 from &#x27;common2&#x27;;</span><br><span class="line">export default function print(msg:string) &#123;</span><br><span class="line">    console.log(msg);</span><br><span class="line">    print2(&quot;这里是common1中调用common2&quot;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><p>再次运行umi-antd项目时，我们可以看到，控制台已经打印了common2中方法。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081121628.png"></p><h2 id="四、workspace协议-workspace"><a href="#四、workspace协议-workspace" class="headerlink" title="四、workspace协议(workspace:)"></a>四、workspace协议(workspace:)</h2><h2 id="1、协议概述"><a href="#1、协议概述" class="headerlink" title="1、协议概述"></a>1、协议概述</h2><p>默认情况下，如果可用的 packages 与已声明的可用范围相匹配，pnpm 将从工作区链接这些 packages。 例如, 如果bar引用”foo”: “^1.0.0”并且<a href="mailto:&#102;&#111;&#x6f;&#64;&#x31;&#46;&#x30;&#x2e;&#48;">&#102;&#111;&#x6f;&#64;&#x31;&#46;&#x30;&#x2e;&#48;</a>存在工作区，那么pnpm会从工作区将<a href="mailto:&#x66;&#111;&#111;&#64;&#49;&#46;&#x30;&#46;&#x30;">&#x66;&#111;&#111;&#64;&#49;&#46;&#x30;&#46;&#x30;</a>链接到bar。 但是，如果 bar 的依赖项中有 “foo”: “2.0.0”，而 <a href="mailto:&#102;&#111;&#x6f;&#64;&#50;&#x2e;&#48;&#x2e;&#48;">&#102;&#111;&#x6f;&#64;&#50;&#x2e;&#48;&#x2e;&#48;</a> 在工作空间中并不存在，则将从 npm registry 安装 <a href="mailto:&#102;&#x6f;&#111;&#x40;&#50;&#46;&#48;&#x2e;&#x30;">&#102;&#x6f;&#111;&#x40;&#50;&#46;&#48;&#x2e;&#x30;</a> 。 这种行为带来了一些不确定性。</p><p>幸运的是，pnpm 支持 workspace 协议 workspace: 。 当使用此协议时，pnpm 将拒绝解析除本地 workspace 包含的 package 之外的任何内容。 因此，如果您设置为 “foo”: “workspace:2.0.0” 时，安装将会失败，因为 “<a href="mailto:&#x66;&#111;&#111;&#64;&#x32;&#46;&#x30;&#x2e;&#48;">&#x66;&#111;&#111;&#64;&#x32;&#46;&#x30;&#x2e;&#48;</a>“ 不存在于此 workspace 中。</p><p>当 link-workspace-packages 选项被设置为 false 时，这个协议将特别有用。 在这种情况下，仅当使用 workspace: 协议声明依赖，pnpm 才会从此 workspace 链接所需的包。</p><p>以上是官网的解释，实际在使用的时候，如果引入的项目需要强制使用本地包，则可以使用workspace:协议。改造下umi-antd的package.json文件如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&quot;dependencies&quot;: &#123;</span><br><span class="line">    &quot;@ant-design/icons&quot;: &quot;^5.0.1&quot;,</span><br><span class="line">    &quot;@ant-design/pro-components&quot;: &quot;^2.4.4&quot;,</span><br><span class="line">    &quot;@umijs/max&quot;: &quot;^4.0.76&quot;,</span><br><span class="line">    &quot;antd&quot;: &quot;^5.4.0&quot;,</span><br><span class="line">    &quot;common1&quot;: &quot;workspace:^&quot;,</span><br><span class="line">    &quot;common2&quot;: &quot;workspace:^&quot;</span><br><span class="line">  &#125;,</span><br></pre></td></tr></table></figure><p>上面加上common1和common2的依赖声明后，会强制到本地寻找，找不到也不会到npm registry对应的私仓去下载。</p><h2 id="2、版本符号"><a href="#2、版本符号" class="headerlink" title="2、版本符号"></a>2、版本符号</h2><p>workspace协议，区分*、~、^、版本号，表示的意义各部相同，具体如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    &quot;dependencies&quot;: &#123;</span><br><span class="line">        &quot;foo&quot;: &quot;workspace:*&quot;,</span><br><span class="line">        &quot;bar&quot;: &quot;workspace:~&quot;,</span><br><span class="line">        &quot;qar&quot;: &quot;workspace:^&quot;,</span><br><span class="line">        &quot;zoo&quot;: &quot;workspace:^1.5.0&quot;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">// 将会被转化为：</span><br><span class="line">&#123;</span><br><span class="line">    &quot;dependencies&quot;: &#123;</span><br><span class="line">        &quot;foo&quot;: &quot;1.5.0&quot;,</span><br><span class="line">        &quot;bar&quot;: &quot;~1.5.0&quot;,</span><br><span class="line">        &quot;qar&quot;: &quot;^1.5.0&quot;,</span><br><span class="line">        &quot;zoo&quot;: &quot;^1.5.0&quot;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="五、Monorepo工具有哪些？"><a href="#五、Monorepo工具有哪些？" class="headerlink" title="五、Monorepo工具有哪些？"></a>五、Monorepo工具有哪些？</h2><p>Monorepo 是一种代码管理策略，它将一个项目的所有代码存储在一个单独的版本控制库中。Monorepo 解决了多个问题：解决了代码共享与重复的困扰，提供更好的可追踪性和一致性。通过使用Monorepo，开发团队可以更好地组织、共享和管理代码，提高开发效率和协作质量。选择合适的Monorepo工具并灵活运用，能够帮助开发者更好地应对复杂的软件开发需求，推动项目的成功完成。</p><p>参考：</p><p><a href="https://mp.weixin.qq.com/s/kFJqZrJVu5jh5HNOhsOEfg">Hello Monorepo</a></p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA/">项目构建</category>
      
      
      <comments>https://blog.helloallen.cn/d1678c62/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>esbuild 简介</title>
      <link>https://blog.helloallen.cn/63e1a769/</link>
      <guid>https://blog.helloallen.cn/63e1a769/</guid>
      <pubDate>Thu, 08 Feb 2024 11:12:58 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="1、esbuild-极速-JavaScript-打包器"><a href="#1、esbuild-极速-JavaScript-打包器" class="headerlink" title="1、esbuild:  极速 JavaScript 打包器"></a>1、esbuild:  极速 JavaScript 打包器</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081113169.png"></p><h2 id="2、使用情况：Vite-2-0-宣布使用-Esbuild-预构建依赖"><a href="#2、使用情况：Vite-2-0-宣布使用-Esbuild-预构建依赖" class="headerlink" title="2、使用情况：Vite 2.0 宣布使用 Esbuild 预构建依赖"></a>2、使用情况：Vite 2.0 宣布使用 Esbuild 预构建依赖</h2><h2 id="3、为什么这么快？"><a href="#3、为什么这么快？" class="headerlink" title="3、为什么这么快？"></a>3、为什么这么快？</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081113677.png"></p><h2 id="（1）语言优势"><a href="#（1）语言优势" class="headerlink" title="（1）语言优势"></a>（1）语言优势</h2><p>大多数前端打包工具都是基于 JavaScript 实现的，而 Esbuild 则选择使用 Go 语言编写，两种语言各自有其擅长的场景，但是在资源打包这种 CPU 密集场景下，Go 更具性能优势。</p><p>虽然现代 JS 引擎与10年前相比有巨大的提升，但 JavaScript 本质上依然是一门解释型语言，JavaScript 程序每次执行都需要先由解释器一边将源码翻译成机器语言，一边调度执行；而 Go 是一种编译型语言，在编译阶段就已经将源码转译为机器码，启动时只需要直接执行这些机器码即可。也就意味着，Go 语言编写的程序比 JavaScript 少了一个动态解释的过程。</p><p>所以在编译运行层面，Go 前置了源码编译过程，相对 JavaScript 边解释边运行的方式有更高的执行性能。</p><h2 id="（2）多线程优势"><a href="#（2）多线程优势" class="headerlink" title="（2）多线程优势"></a>（2）多线程优势</h2><p>Go 天生具有多线程运行能力，而 JavaScript 本质上是一门单线程语言，直到引入 WebWorker 规范之后才有可能在浏览器、Node 中实现多线程操作。</p><p>我曾经研读过 Rollup、Webpack 的代码，就我熟知的范围内两者均未使用 WebWorker 提供的多线程能力。反观 Esbuild，它最核心的卖点就是性能，它的实现算法经过非常精心的设计，尽可能饱和地使用各个 CPU 核，特别是打包过程的解析、代码生成阶段已经实现完全并行处理。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA/">项目构建</category>
      
      
      <comments>https://blog.helloallen.cn/63e1a769/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>JS三大运行时全面对比：Node.js vs Bun vs Deno</title>
      <link>https://blog.helloallen.cn/dc7ce9e1/</link>
      <guid>https://blog.helloallen.cn/dc7ce9e1/</guid>
      <pubDate>Thu, 08 Feb 2024 09:59:32 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>JavaScript 运行时是指执行 JavaScript 代码的环境。目前，JavaScript 生态中有三大运行时：Node.js、Bun、Deno。老牌运行时 Node.js 的霸主地位正受到 Deno 和 Bun 的挑战，下面就来看看这三个 JS 运行时有什么区别！</p><h2 id="JS-运行时概述"><a href="#JS-运行时概述" class="headerlink" title="JS 运行时概述"></a>JS 运行时概述</h2><h3 id="Node-js"><a href="#Node-js" class="headerlink" title="Node.js"></a>Node.js</h3><p>Node.js 在 2023 年被 Stack Overflow 开发者评为最受欢迎的 Web 技术。Node.js 于 2009 年推出，允许开发人员在浏览器之外使用 JavaScript，彻底改变了服务端编程。它拥有强大的生态系统、庞大的社区，并且经过验证且稳定。为大型应用程序提供 LTS 构建。基于 V8 JavaScript 引擎构建。</p><p>多年来，Node.js 一直是服务端 JavaScript 开发的支柱，通过第三方工具支持了无数功能。其提供了巨大的功能和灵活性。丰富的文档、教程和社区支持使开发者可以更轻松地克服挑战。如果考虑内置工具和与 Web API 的兼容性，它是落后于其他两个运行时的。</p><p>从历史上看，Node.js 因其安全方法（尤其是在包方面）而受到批评。然而，社区和维护者已经显着改善了这一方面。权限模型已经在 Node.js v20 中实现，这使 Node.js 更加安全。</p><h3 id="Deno"><a href="#Deno" class="headerlink" title="Deno"></a>Deno</h3><p>Deno 最初由 Node.js 的原始创建者 Ryan Dahl 于 2018 年创建，旨在解决他认为 Node.js 中存在的一些问题，比如性能、安全性。它专注于安全性、现代 JavaScript 实践和开发人员体验。基于 V8 JavaScript 引擎构建并用 Rust 编写。</p><p>与 Node.js 相比，Deno 具有更全面的功能。它对 Web API 和现代标准有很好的支持，并且还支持大多数 NPM 包。Deno 还提供了出色的开发体验，特别是如果使用 TypeScript，它是开箱即用的。Deno 还具有内置 linting、代码格式化程序等优势，节省一些配置和引导时间。如果你倾向于开箱即用的设置，只需启动编辑器，创建一个main.ts文件，然后就可以开始快乐编码了！</p><h3 id="Bun"><a href="#Bun" class="headerlink" title="Bun"></a>Bun</h3><p>Bun 是 2021 年发布的 JavaScript 运行时，它被设计为 Node.js 的更快、更精简、更现代的替代品。它构建在 JavaScript Core 和 Zig 语言之上。旨在成为一个全功能的运行时环境和工具包，重点关注速度、打包、测试和与 Node.js 包的兼容性。最大的优势之一是它的性能。事实证明，Bun 比 Node.js 和 Deno 都要快。如果 Bun 能够完成这些目标，那么它将成为一个非常有吸引力的选择。Bun使用的是Apple的WebKit引擎，而不是像Node.js和其他运行时一样使用Google的V8引擎。</p><p>Bun 的核心卖点是它的性能，其提供了许多基准测试，显示出令人惊叹的速度。使用 Bun 作为包管理器比使用标准 NPM 命令要快得多。在现实应用中，尤其是 Web 应用，性能差异可能不像基准测试中那么显着。</p><p>Bun 优先考虑简单性和速度。凭借其内置的包管理器，以及与 Node.js 相比改进的开发体验，开发人员可以快速入门，而无需遇到其他运行时可能带来的初始设置障碍。</p><h2 id="认识Bun"><a href="#认识Bun" class="headerlink" title="认识Bun"></a>认识Bun</h2><h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>Bun 不仅仅是一个运行时。它也是：</p><ul><li>一个包管理器 (类似 Yarn、 NPM、 PNPM)</li><li>一个构建工具 (类似 Webpack、 ESBuild、 Parcel)</li><li>一个测试运行器</li><li>…</li></ul><p>Bun 还可以运行脚本。不管它做什么都比其他工具更快。Bun 在 JavaScript 生态系统的许多方面都有新的尝试，其中的重点是性能。它优先支持标准的 Web API，如 Fetch。它也支持许多 Node.js APIs，使其能与大多数 NPM 包兼容。</p><h3 id="1、Bun是一个全能的工具包"><a href="#1、Bun是一个全能的工具包" class="headerlink" title="1、Bun是一个全能的工具包"></a>1、Bun是一个全能的工具包</h3><p>JavaScript 的工具链在发展过程中，各种工具被逐渐添加进来，但没有一个统一的集中规划，导致工具链缺乏整体性和效率，变得运行缓慢和复杂。Bun的目标很简单，就是要消除JavaScript工具链的缓慢和复杂性。</p><p>为了实现这个目标，可能需要放弃一些在使用Bun之后变得不再必要的工具：</p><ul><li><p>Node.js：Bun 的一个可以直接替代的工具，因此不再需要以下工具：</p></li><li><ul><li>node</li><li>npx：Bun 的 bunx 命令比 npx 快5倍。</li><li>nodemon：Bun 内置了监听模式，无需使用 nodemon。</li><li>dotenv、cross-env：Bun 默认支持读取.env文件的配置。</li></ul></li><li><p>转译器：Bun 可以运行.js、.ts、``.cjs、.mjs、.jsx和.tsx文件，因此不再需要以下工具：</p></li><li><ul><li>tsc：仍然可以保留它用于类型检查！</li><li>babel、.babelrc、@babel/preset-*：不再需要使用 Babel 进行转译。</li><li>ts-node、ts-node-esm：Bun 可以直接运行 TypeScript 文件。</li><li>tsx：Bun可以直接运行 TypeScript 的 JSX 文件。</li></ul></li><li><p>构建工具：Bun 具有一流的性能和与esbuild兼容的插件API，因此不再需要以下工具：</p></li><li><ul><li>esbuild</li><li>webpack</li><li>parcel, .parcelrc</li><li>rollup, rollup.config.js</li></ul></li><li><p>包管理器：Bun 是一个与 npm 兼容的包管理器，可以使用熟悉的命令。它可以读取 package.json文件并将依赖写入node_modules目录，与其他包管理器的行为类似，因此可以替换以下工具：</p></li><li><ul><li>npm, .npmrc, package-lock.json</li><li>yarn,yarn.lock</li><li>pnpm, pnpm.lock, pnpm-workspace.yaml</li><li>lern</li></ul></li><li><p>测试库：Bun是一个支持Jest的测试运行器，具有快照测试、模拟和代码覆盖率等功能，因此不再需要以下测试相关的工具：</p></li><li><ul><li>jest, jest.config.js</li><li>ts-jest, @swc/jest, babel-jest</li><li>jest-extended</li><li>vitest, vitest.config.ts</li></ul></li></ul><p>尽管这些工具都有自己的优点，但使用它们时往往需要将它们全部集成在一起，这会导致开发过程变得缓慢和复杂。而Bun通过成为一个单一的工具包，提供了最佳的开发者体验，从性能到API设计都力求做到最好。</p><h3 id="2、Bun：JavaScript-运行时"><a href="#2、Bun：JavaScript-运行时" class="headerlink" title="2、Bun：JavaScript 运行时"></a>2、Bun：JavaScript 运行时</h3><p>（1）Bun内置了JavaScript转译器，因此可以运行JavaScript、TypeScript甚至JSX/TSX文件，无需任何依赖。因此，Bun的速度非常快，启动速度比 Node.js 快 4 倍。当运行TypeScript文件时，这种差异会更加明显，因为在Node.js中运行TypeScript文件需要先进行转译才能运行。</p><p>（2）Bun 同时支持ESM 和 CommonJS 这两种模块系统。无论是使用CommonJS的.js扩展名、.cjs扩展名，还是使用ES模块的.mjs扩展名，Bun都会进行正确的解析和执行，而无需额外的配置。</p><p>甚至可以在同一个文件中同时使用import和require()</p><p>（3）Bun 内置支持浏览器中可用的Web标准API，如fetch、Request、Response、WebSocket和ReadableStream等。开发者不再需要安装像node-fetch和ws这样的包。</p><h3 id="3、Bun：包管理器"><a href="#3、Bun：包管理器" class="headerlink" title="3、Bun：包管理器"></a>3、Bun：包管理器</h3><p>Bun的安装速度比 npm、yarn 和 pnpm 快好几个数量级。</p><h3 id="4、Bun：测试运行器"><a href="#4、Bun：测试运行器" class="headerlink" title="4、Bun：测试运行器"></a>4、Bun：测试运行器</h3><h3 id="5、Bun：构建工具"><a href="#5、Bun：构建工具" class="headerlink" title="5、Bun：构建工具"></a>5、Bun：构建工具</h3><p>根据esbuild的基准测试，Bun比esbuild快1.75倍，比Parcel 2快150倍，比Rollup + Terser快180倍，比Webpack快220倍。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA/">项目构建</category>
      
      
      <comments>https://blog.helloallen.cn/dc7ce9e1/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>ES11、ES12、ES13新特性</title>
      <link>https://blog.helloallen.cn/78e191b0/</link>
      <guid>https://blog.helloallen.cn/78e191b0/</guid>
      <pubDate>Mon, 05 Feb 2024 22:31:05 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="一、ES11新特性（2020）"><a href="#一、ES11新特性（2020）" class="headerlink" title="一、ES11新特性（2020）"></a>一、ES11新特性（2020）</h2><p>ES2020新特性是ECMAScript对应2020年的版本。通过babel中的<code>babel-preset-es2020</code>可以使用。</p><h2 id="1、BigInt"><a href="#1、BigInt" class="headerlink" title="1、BigInt"></a>1、BigInt</h2><h3 id="（1）之前存在的问题"><a href="#（1）之前存在的问题" class="headerlink" title="（1）之前存在的问题"></a>（1）之前存在的问题</h3><p>JavaScript 所有数字都保存成 64 位浮点数，这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位（相当于 16 个十进制位），大于这个范围的整数，JavaScript 是无法精确表示的，这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于2的1024次方的数值，JavaScript 无法表示，会返回Infinity。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 1. 超过 53 个二进制位的数值，无法保持精度</span><br><span class="line">Math.pow(2, 53) === Math.pow(2, 53) + 1 // true</span><br><span class="line"></span><br><span class="line">// 2. 超过 2 的 1024 次方的数值，无法表示</span><br><span class="line">Math.pow(2, 1024) // Infinity</span><br><span class="line"></span><br><span class="line">// 3. 最大安全整数</span><br><span class="line">let max = Number.MAX_SAFE_INTEGER;</span><br><span class="line">let max1 = max + 1</span><br><span class="line">let max2 = max + 2</span><br><span class="line">max1 === max2   // true</span><br></pre></td></tr></table></figure><h3 id="（2）引入BigInt后"><a href="#（2）引入BigInt后" class="headerlink" title="（2）引入BigInt后"></a>（2）引入BigInt后</h3><p>现在引入了一种新的数据类型 BigInt（大整数），来解决这个问题。BigInt 只用来表示整数，没有位数的限制，任何位数的整数都可以精确表示。</p><p>创建 BigInt 类型的值也非常简单，只需要在数字后面加上 n 即可。例如，123 变为 123n。也可以使用全局方法 BigInt(value) 转化，入参 value 为数字或数字字符串。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">let max = BigInt(Number.MAX_SAFE_INTEGER);</span><br><span class="line"></span><br><span class="line">let max1 = max + 1n</span><br><span class="line">let max2 = max + 2n</span><br><span class="line"></span><br><span class="line">max1 === max2   // false</span><br></pre></td></tr></table></figure><h3 id="（3）判断类型："><a href="#（3）判断类型：" class="headerlink" title="（3）判断类型："></a>（3）判断类型：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">typeof 1n === &#x27;bigint&#x27;; // true</span><br><span class="line">typeof BigInt(&#x27;1&#x27;) === &#x27;bigint&#x27;; // true</span><br><span class="line">Object.prototype.toString.call(10n) === &#x27;[object BigInt]&#x27;;    // true</span><br></pre></td></tr></table></figure><h3 id="（4）BigInt和Number不严格相等，但是宽松相等："><a href="#（4）BigInt和Number不严格相等，但是宽松相等：" class="headerlink" title="（4）BigInt和Number不严格相等，但是宽松相等："></a>（4）BigInt和Number不严格相等，但是宽松相等：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">10n === 10 // false</span><br><span class="line">10n == 10  // true</span><br></pre></td></tr></table></figure><h3 id="（5）Number和BigInt可以进行比较"><a href="#（5）Number和BigInt可以进行比较" class="headerlink" title="（5）Number和BigInt可以进行比较"></a>（5）Number和BigInt可以进行比较</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">1n &lt; 2;    // true</span><br><span class="line">2n &gt; 1;    // true</span><br><span class="line">2 &gt; 2;     // false</span><br><span class="line">2n &gt; 2;    // false</span><br><span class="line">2n &gt;= 2;   // true</span><br></pre></td></tr></table></figure><h3 id="（6）如果算上-BigInt，JavaScript-中原始类型就从-6-个变为了-7-个。"><a href="#（6）如果算上-BigInt，JavaScript-中原始类型就从-6-个变为了-7-个。" class="headerlink" title="（6）如果算上 BigInt，JavaScript 中原始类型就从 6 个变为了 7 个。"></a>（6）如果算上 BigInt，JavaScript 中原始类型就从 6 个变为了 7 个。</h3><ul><li>Boolean</li><li>Null</li><li>Undefined</li><li>Number</li><li>String</li><li>Symbol (new in ECMAScript 2015)</li><li>BigInt (new in ECMAScript 2019)</li></ul><h2 id="2、可选链操作符"><a href="#2、可选链操作符" class="headerlink" title="2、可选链操作符(?.)"></a>2、可选链操作符(?.)</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">a?.[x]</span><br><span class="line">// 等同于</span><br><span class="line">a == null ? undefined : a[x]</span><br></pre></td></tr></table></figure><h2 id="3、Promise-allSettled"><a href="#3、Promise-allSettled" class="headerlink" title="3、Promise.allSettled"></a>3、Promise.allSettled</h2><p><code>Promise.allSettled</code>跟<code>Promise.all</code>类似, 其参数接受一个Promise的数组, 返回一个新的Promise, 唯一的不同在于, 它不会进行短路, 也就是说当Promise全部处理完成后,我们可以拿到每个Promise的状态, 而不管是否处理成功。</p><h2 id="4、Dynamic-import"><a href="#4、Dynamic-import" class="headerlink" title="4、Dynamic import"></a>4、Dynamic import</h2><p>现在前端打包资源越来越大，前端应用初始化时根本不需要全部加载这些逻辑资源，为了首屏渲染速度更快，很多时候都是动态导入（按需加载）模块，比如懒加载图片等，这样可以帮助您提高应用程序的性能。</p><p>import()可以用于script脚本中，<code>import(module)</code> 函数可以在任何地方调用。它返回一个解析为模块对象的 promise。支持 await 关键字。</p><h2 id="5、globalThis"><a href="#5、globalThis" class="headerlink" title="5、globalThis"></a>5、globalThis</h2><p>globalThis 目的就是提供一种标准化方式访问全局对象，有了 globalThis 后，你可以在任意上下文，任意时刻都能获取到全局对象。</p><p>如果您在浏览器上，globalThis将为window，如果您在Node上，globalThis则将为global。因此，不再需要考虑不同的环境问题。</p><h2 id="6、class的私有变量"><a href="#6、class的私有变量" class="headerlink" title="6、class的私有变量"></a>6、class的私有变量</h2><p>最新提案之一是在类中添加私有变量的方法。我们将使用 # 符号表示类的私有变量。这样就不需要使用闭包来隐藏不想暴露给外界的私有变量。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">class Counter &#123;</span><br><span class="line">  #x = 0;</span><br><span class="line"></span><br><span class="line">  #increment() &#123;</span><br><span class="line">    this.#x++;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  onClick() &#123;</span><br><span class="line">    this.#increment();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">const c = new Counter();</span><br><span class="line">c.onClick(); // 正常</span><br><span class="line">c.#increment(); // 报错</span><br></pre></td></tr></table></figure><p>通过 # 修饰的成员变量或成员函数就成为了私有变量，如果试图在 Class 外部访问，则会抛出异常。</p><h2 id="7、空值合并操作符（-）"><a href="#7、空值合并操作符（-）" class="headerlink" title="7、空值合并操作符（??）"></a>7、空值合并操作符（??）</h2><p>我们在开发过程中，经常会遇到这样场景：变量如果是空值，则就使用默认值，我们是这样实现的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">let c = a ? a : b // 方式1</span><br><span class="line">let c = a || b // 方式2</span><br></pre></td></tr></table></figure><p>这两种方式有个明显的弊端，它都会覆盖所有的假值，如(0, ‘’, false)，这些值可能是在某些情况下有效的输入。</p><p>为了解决这个问题，有人提议创建一个<code>nullish</code>合并运算符，用 ?? 表示。有了它，我们仅在第一项为 null 或 undefined 时设置默认值。</p><h2 id="8、class的static"><a href="#8、class的static" class="headerlink" title="8、class的static"></a>8、class的static</h2><p>它允许类拥有静态字段，类似于大多数OOP语言。静态字段可以用来代替枚举，也可以用于私有字段。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">class Colors &#123;</span><br><span class="line">  // public static 字段</span><br><span class="line">  static red = &#x27;#ff0000&#x27;;</span><br><span class="line">  static green = &#x27;#00ff00&#x27;;</span><br><span class="line"></span><br><span class="line">  // private static 字段</span><br><span class="line">  static #secretColor = &#x27;#f0f0f0&#x27;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">font.color = Colors.red;</span><br><span class="line">font.color = Colors.#secretColor; // 出错</span><br></pre></td></tr></table></figure><h2 id="9、String-prototype-matchAll"><a href="#9、String-prototype-matchAll" class="headerlink" title="9、String.prototype.matchAll"></a>9、String.prototype.matchAll</h2><p><code>matchAll()</code> 是新增的字符串方法，它返回一个包含所有匹配正则表达式的结果及分组捕获组的迭代器。因为返回的是遍历器，所以通常使用<code>for...of</code>循环取出。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">for (const match of &#x27;abcabc&#x27;.matchAll(/a/g)) &#123;</span><br><span class="line">    console.log(match)</span><br><span class="line">&#125;</span><br><span class="line">//[&quot;a&quot;, index: 0, input: &quot;abcabc&quot;, groups: undefined]</span><br><span class="line">//[&quot;a&quot;, index: 3, input: &quot;abcabc&quot;, groups: undefined]</span><br></pre></td></tr></table></figure><p>需要注意，该方法的第一个参数是一个正则表达式对象，如果传的参数不是一个正则表达式对象，则会隐式地使用 new RegExp(obj) 将其转换为一个 RegExp 。另外，RegExp必须是设置了全局模式g的形式，否则会抛出异常 TypeError。</p><p>和match()的区别就在于match()只返回匹配到的对应的值。</p><h2 id="二、ES12新特性（2021）"><a href="#二、ES12新特性（2021）" class="headerlink" title="二、ES12新特性（2021）"></a>二、ES12新特性（2021）</h2><p>2021年3月13日，ES2021 候选提案发布了其最终功能集的版本。如果它能够在今年6月的ECMA 大会上通过，就会成为官方的标准！</p><p>这个候选提案提及到ECMAScript新特性如下所示：</p><ul><li>String.prototype.replaceAll()</li><li>Promise.any</li><li>逻辑运算符和赋值表达式</li><li>数值分隔符</li><li>WeakRef and Finalizers</li></ul><p>这些新的特性已经进入第四阶段且已添加到谷歌 Chrome V8 引擎中。接下来我们来介绍下这些ES2021的新特性吧。</p><h2 id="1、replaceAll"><a href="#1、replaceAll" class="headerlink" title="1、replaceAll()"></a>1、replaceAll()</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">let string = &#x27;hello world, hello ES12&#x27;</span><br><span class="line">string.replace(/hello/g,&#x27;hi&#x27;)    // hi world, hi ES12</span><br><span class="line">string.replaceAll(&#x27;hello&#x27;,&#x27;hi&#x27;)  // hi world, hi ES12</span><br></pre></td></tr></table></figure><p>是对replace的扩充。注意：replaceAll在使用正则表达式的时候，如果非全局匹配(/g)，会抛出异常：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">let string = &#x27;hello world, hello ES12&#x27;</span><br><span class="line">string.replaceAll(/hello/,&#x27;hi&#x27;)</span><br><span class="line"></span><br><span class="line">// Uncaught TypeError: String.prototype.replaceAll called with a non-global</span><br></pre></td></tr></table></figure><h2 id="2、Promise-any"><a href="#2、Promise-any" class="headerlink" title="2、Promise.any()"></a>2、Promise.any()</h2><p>在 ES6 中引入了 Promise.race() 和 Promise.all() 方法，ES2020 加入了 Promise.allSettled()。 ES2021 又增加了一个使 Promise 处理更加容易的方法：Promise.any()</p><p>Promise.any() 接收一个Promise可迭代对象，只要其中的一个 promise 成功，就返回那个已经成功的 promise 。如果可迭代对象中没有一个 promise 成功（即所有的 promise 都失败/拒绝），就返回一个失败的 promise 和AggregateError类型的实例，它是 Error的一个子类，用于把单一的错误集合在一起。</p><p><code>Promise.any()</code>跟<code>Promise.race()</code>方法很像，只有一点不同，就是不会因为某个 Promise 变成rejected状态而结束。</p><h2 id="3、逻辑赋值操作符（-amp-amp-）"><a href="#3、逻辑赋值操作符（-amp-amp-）" class="headerlink" title="3、逻辑赋值操作符（&amp;&amp;=, ||=, ??=）"></a>3、逻辑赋值操作符（&amp;&amp;=, ||=, ??=）</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">var x = 1;</span><br><span class="line">var y = 2;</span><br><span class="line">x &amp;&amp;= y; // 等价于 x &amp;&amp; (x=y)</span><br><span class="line">console.log(x); // 2</span><br></pre></td></tr></table></figure><h2 id="4、数字分隔符"><a href="#4、数字分隔符" class="headerlink" title="4、数字分隔符"></a>4、数字分隔符</h2><p>我们将通过使用_（下划线）字符在数字组之间提供分隔，使读取数值更加容易，提高可读性。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">let x = 100_000; // 100000</span><br></pre></td></tr></table></figure><h2 id="5、WeakRef-and-Finalizers"><a href="#5、WeakRef-and-Finalizers" class="headerlink" title="5、WeakRef and Finalizers"></a>5、WeakRef and Finalizers</h2><p>此功能包含两个高级对象 WeakRef 和 FinalizationRegistry。根据使用情况，这些接口可以单独使用，也可以一起使用。<strong>官方建议不要轻易使用 WeakRef 和 finalizer。</strong>其中一个原因是它们可能不可预测，另一个是它们并没有真正帮 gc 完成工作，实际上可能会垃圾回收的工作更加困难。</p><p>在 JavaScript 中，当你创建了一个创建对象的引用时，这个引用可以防止对象被垃圾收集，也就是说 JavaScript 无法删除对象并释放其内存。只要对该对象的引用一直存在，就可以使这个对象永远存在。</p><p>ES2021 添加了新的类 WeakRefs。允许创建对象的弱引用。这样就能够在跟踪现有对象时不会阻止对其进行垃圾回收。对于缓存和对象映射非常有用。</p><p>必须用 new关键字创建新的 WeakRef ，并把某些对象作为参数放入括号中。当你想读取引用（被引用的对象）时，可以通过在弱引用上调用 deref() 来实现。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const myWeakRef = new WeakRef(&#123;</span><br><span class="line">  name: &#x27;星野&#x27;,</span><br><span class="line">  year: &#x27;25&#x27;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">myWeakRef.deref()</span><br><span class="line">// =&gt; &#123;  name: &#x27;星野&#x27;, year: &#x27;25&#x27; &#125;</span><br><span class="line"></span><br><span class="line">myWeakRef.deref().name</span><br><span class="line">// =&gt; &#x27;星野&#x27;</span><br></pre></td></tr></table></figure><p>与 WeakRef 紧密相连的还有另一个功能，名为 finalizers 或 FinalizationRegistry。这个功能允许你注册一个回调函数，这个回调函数将会在对象被垃圾回收时调用。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 创建 FinalizationRegistry:</span><br><span class="line">const reg = new FinalizationRegistry((val) =&gt; &#123;</span><br><span class="line">  console.log(val)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(() =&gt; &#123;</span><br><span class="line">  // 创建新对象:</span><br><span class="line">  const obj = &#123;&#125;</span><br><span class="line"></span><br><span class="line">  //为 “obj” 对象注册 finalizer：</span><br><span class="line">  //第一个参数：要为其注册 finalizer 的对象。</span><br><span class="line">  //第二个参数：上面定义的回调函数的值。</span><br><span class="line">  reg.register(obj, &#x27;obj has been garbage-collected.&#x27;)</span><br><span class="line">&#125;)()</span><br><span class="line">// 当 &quot;obj&quot; 被垃圾回收时输出：</span><br><span class="line">// &#x27;obj has been garbage-collected.&#x27;</span><br></pre></td></tr></table></figure><p>总而言之，JavaScript 中对象的引用是强引用，WeakMap 和 WeakSet 可以提供部分的弱引用功能，若想在 JavaScript 中实现真正的弱引用，可以通过配合使用 WeakRef 和终结器（Finalizer）来实现。</p><h2 id="三、ES13新特性（2022）"><a href="#三、ES13新特性（2022）" class="headerlink" title="三、ES13新特性（2022）"></a>三、ES13新特性（2022）</h2><h2 id="1、Object-hasOwn"><a href="#1、Object-hasOwn" class="headerlink" title="1、Object.hasOwn()"></a>1、Object.hasOwn()</h2><p>在ES2022之前，可以使用 <code>Object.prototype.hasOwnProperty()</code> 来检查一个属性是否属于对象。</p><p>Object.hasOwn 特性是一种更简洁、更可靠的检查属性是否直接设置在对象上的方法：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const example = &#123;</span><br><span class="line">  property: &#x27;123&#x27;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">console.log(Object.prototype.hasOwnProperty.call(example, &#x27;property&#x27;));</span><br><span class="line">console.log(Object.hasOwn(example, &#x27;property&#x27;));</span><br></pre></td></tr></table></figure><h2 id="2、通过at-来对字符串或数组进行索引"><a href="#2、通过at-来对字符串或数组进行索引" class="headerlink" title="2、通过at()来对字符串或数组进行索引"></a>2、通过<code>at()</code>来对字符串或数组进行索引</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const array = [0,1,2,3,4,5];</span><br><span class="line"></span><br><span class="line">console.log(array[array.length-1]);  // 5</span><br><span class="line">console.log(array.at(-1));  // 5</span><br><span class="line"></span><br><span class="line">console.log(array[array.lenght-2]);  // 4</span><br><span class="line">console.log(array.at(-2));  // 4</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const str = &quot;hello world&quot;;</span><br><span class="line"></span><br><span class="line">console.log(str[str.length - 1]);  // d</span><br><span class="line">console.log(str.at(-1));  // d</span><br></pre></td></tr></table></figure><h2 id="3、error-cause"><a href="#3、error-cause" class="headerlink" title="3、error.cause"></a>3、error.cause</h2><p>在ES13中，<code>new Error()</code>中可以指定导致它的原因：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">function readFiles(filePaths) &#123;</span><br><span class="line">  return filePaths.map(</span><br><span class="line">    (filePath) =&gt; &#123;</span><br><span class="line">      try &#123;</span><br><span class="line">        // ···</span><br><span class="line">      &#125; catch (error) &#123;</span><br><span class="line">        throw new Error(</span><br><span class="line">          `While processing $&#123;filePath&#125;`,</span><br><span class="line">          &#123;cause: error&#125;</span><br><span class="line">        );</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="4、Top-level-await"><a href="#4、Top-level-await" class="headerlink" title="4、Top-level await"></a>4、Top-level await</h2><p>ES2017（ES8）中的 <code>async/await</code>特性仅仅允许在 async 函数内使用 await 关键字，新的提案旨在允许 await 关键字在顶层内容中的使用，例如可以简化动态模块加载的过程：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const strings = await import(`/i18n/$&#123;navigator.language&#125;`);</span><br></pre></td></tr></table></figure><p>这个特性在浏览器控制台中调试异步内容（如 fetch）非常有用，而无需将其包装到异步函数中。</p><p>另一个使用场景是，可以在以异步方式初始化的 ES 模块的顶层使用它(比如建立数据库连接)。当导入这样的“异步模块”时，模块系统将等待它被解析，然后再执行依赖它的模块。这种处理异步初始化方式比当前返回一个初始化promise并等待它解决来得更容易。一个模块不知道它的依赖是否异步。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// db.mjs</span><br><span class="line">export const connection = await createConnection();</span><br><span class="line"></span><br><span class="line">// server.mjs</span><br><span class="line">import &#123; connection &#125; from &#x27;./db.mjs&#x27;;</span><br><span class="line">server.start();</span><br></pre></td></tr></table></figure><p>在此示例中，在<code>server.mjs</code>中完成连接之前不会执行任何操作<code>db.mjs</code>。</p><p>顶级await在以下场景中将非常有用：</p><ul><li><p>动态加载模块</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const strings = await import(`/i18n/$&#123;navigator.language&#125;`);</span><br></pre></td></tr></table></figure></li><li><p>资源初始化</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const connection = await dbConnector();</span><br></pre></td></tr></table></figure></li><li><p>依赖回退</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">let translations;</span><br><span class="line">try &#123;</span><br><span class="line">  translations = await import(&#x27;https://app.fr.json&#x27;);</span><br><span class="line">&#125; catch &#123;</span><br><span class="line">  translations = await import(&#x27;https://fallback.en.json&#x27;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h2 id="5、正则表达式匹配索引"><a href="#5、正则表达式匹配索引" class="headerlink" title="5、正则表达式匹配索引"></a>5、正则表达式匹配索引</h2><p>（1）该特性允许我们利用 d 字符来表示我们想要匹配字符串的开始和结束索引。以前，只能在字符串匹配操作期间获得一个包含提取的字符串和索引信息的数组。在某些情况下，这是不够的。因此，在这个规范中，如果设置标志 <code>/d</code>，将额外获得一个带有开始和结束索引的数组。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const matchObj = /(a+)(b+)/d.exec(&#x27;aaaabb&#x27;);</span><br><span class="line"></span><br><span class="line">console.log(matchObj[1]) // &#x27;aaaa&#x27;</span><br><span class="line">console.log(matchObj[2]) // &#x27;bb&#x27;</span><br></pre></td></tr></table></figure><p>（2）由于 /d 标识的存在，matchObj还有一个属性<code>.indices</code>，它用来记录捕获的每个编号组：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">console.log(matchObj.indices[1])  // [0, 4]</span><br><span class="line">console.log(matchObj.indices[2])  // [4, 6]</span><br></pre></td></tr></table></figure><p>（3）我们还可以使用命名组：</p><p>这里给两个字符匹配分别命名为as和bs，然后就可以通过groups来获取到这两个命名分别匹配到的字符串。</p><p>它们的索引存储在 matchObj.indices.groups 中：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">console.log(matchObj.indices.groups.as);  // [0, 4]</span><br><span class="line">console.log(matchObj.indices.groups.bs);  // [4, 6]</span><br></pre></td></tr></table></figure><p>匹配索引的一个重要用途就是指向语法错误所在位置的解析器。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/JavaScript/">JavaScript</category>
      
      
      <comments>https://blog.helloallen.cn/78e191b0/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Oracle数据库下载安装</title>
      <link>https://blog.helloallen.cn/a7b87617/</link>
      <guid>https://blog.helloallen.cn/a7b87617/</guid>
      <pubDate>Sun, 04 Feb 2024 10:13:25 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="一、数据库下载"><a href="#一、数据库下载" class="headerlink" title="一、数据库下载"></a>一、数据库下载</h2><h2 id="1-进入Oracle官网下载页面"><a href="#1-进入Oracle官网下载页面" class="headerlink" title="1. 进入Oracle官网下载页面"></a>1. 进入Oracle官网下载页面</h2><blockquote><p><a href="https://www.oracle.com/cn/downloads/">https://www.oracle.com/cn/downloads/</a></p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">补充：首次下载可能需要注册/登录用户</span><br></pre></td></tr></table></figure><h2 id="2-选择Database，点击数据库企业标准版"><a href="#2-选择Database，点击数据库企业标准版" class="headerlink" title="2. 选择Database，点击数据库企业标准版"></a>2. 选择Database，点击数据库企业标准版</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041023689.png" alt="img"></p><h2 id="3-选择Oracle-Database-Free，点击Select-your-download-below，进入下载页"><a href="#3-选择Oracle-Database-Free，点击Select-your-download-below，进入下载页" class="headerlink" title="3. 选择Oracle Database Free，点击Select your download below，进入下载页"></a>3. 选择Oracle Database Free，点击Select your download below，进入下载页</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041026357.png" alt="img"></p><h2 id="4-选择适合自己电脑操作系统的版本，点击zip进行下载"><a href="#4-选择适合自己电脑操作系统的版本，点击zip进行下载" class="headerlink" title="4. 选择适合自己电脑操作系统的版本，点击zip进行下载"></a>4. 选择适合自己电脑操作系统的版本，点击zip进行下载</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041027337.png" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041028433.png" alt="img"></p><h2 id="二、数据库安装"><a href="#二、数据库安装" class="headerlink" title="二、数据库安装"></a>二、数据库安装</h2><h2 id="1-解压zip并运行setup-exe"><a href="#1-解压zip并运行setup-exe" class="headerlink" title="1. 解压zip并运行setup.exe"></a>1. 解压zip并运行setup.exe</h2><p>将下载的zip文件解压到一个目录下，该目录最好使用纯英文字符进行命名。并且该目录需要长期存在，即使在Oracle安装成功后也不能删除。然后以管理员身份运行setup.exe。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041029131.png" alt="img"></p><h2 id="2-创建并配置单实例数据库"><a href="#2-创建并配置单实例数据库" class="headerlink" title="2. 创建并配置单实例数据库"></a>2. 创建并配置单实例数据库</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041036775.png" alt="img"></p><h2 id="3-错误：无权限或空间不足错"><a href="#3-错误：无权限或空间不足错" class="headerlink" title="3. 错误：无权限或空间不足错"></a>3. 错误：无权限或空间不足错</h2><p>点击下一步有可能会提示“无法创建目录AppData\Local\Temp，无权限或空间不足”的错误。原因可能是因为原来的环境变量temp和tmp配置目录存在数字或其他特殊字符导致。<br>解决方法：修改temp环境变量。右键开始菜单–系统–高级系统设置–高级–环境变量，找到temp和tmp变量，统一将其目录指向到新的临时目录，如：d:\temp。</p><h2 id="4-系统选择桌面类"><a href="#4-系统选择桌面类" class="headerlink" title="4. 系统选择桌面类"></a>4. 系统选择桌面类</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041037342.png" alt="img"></p><h2 id="5-使用Windows内置账户"><a href="#5-使用Windows内置账户" class="headerlink" title="5. 使用Windows内置账户"></a>5. 使用Windows内置账户</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041044048.png" alt="img"></p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041044677.png" alt="img"></p><h2 id="6-自定义选择安装路径，全局数据库名称，数据库登录口令"><a href="#6-自定义选择安装路径，全局数据库名称，数据库登录口令" class="headerlink" title="6. 自定义选择安装路径，全局数据库名称，数据库登录口令"></a>6. 自定义选择安装路径，全局数据库名称，数据库登录口令</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041049001.png" alt="img"></p><h2 id="7-错误：已存在具有指定标识符的数据库实例"><a href="#7-错误：已存在具有指定标识符的数据库实例" class="headerlink" title="7. 错误：已存在具有指定标识符的数据库实例"></a>7. 错误：已存在具有指定标识符的数据库实例</h2><p>点击下一步如果提示：“[INS-35075] 已存在具有指定标识符的数据库实例”。是因为之前安装过Oracle，没有清除干净。</p><p>解决方法：</p><p>（1）任务管理器右击，选择服务页面，打开服务，停止Oracle相关服务<br>（2）运行regedit，选择HKEY_LOCAL_MACHINE &gt; SOFTWARE &gt; ORACLE，按del键删除这个入口<br>（3）运行regedit，选择HKEY_LOCAL_MACHINE &gt; SYSTEM &gt; CurrentControlSet &gt; Services，滚动这个列表，删除所有Oracle入口</p><p>注意：卸载并清除Oracle后需要重启电脑才会生效。</p><h2 id="8-安装"><a href="#8-安装" class="headerlink" title="8. 安装"></a>8. 安装</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041125065.png" alt="img"></p><h2 id="9-错误：-INS-20802-Oracle-Database-Configuration-Assistant-失败。"><a href="#9-错误：-INS-20802-Oracle-Database-Configuration-Assistant-失败。" class="headerlink" title="9. 错误：[INS-20802] Oracle Database Configuration Assistant 失败。"></a>9. 错误：[INS-20802] Oracle Database Configuration Assistant 失败。</h2><p>安装过程中可能会出现：[INS-20802] Oracle Database Configuration Assistant 失败。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041131233.png"></p><p>解决方法：</p><p>（1）以管理员身份运行 <code>D:\\OracleHome</code> 下 BIN 目录中的 netca.bat</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402042031930.png"></p><p>（2）选第一个“监听程序配置”添加：不成功，提示已经运行。那么选择 监听程序配置“重新配置”，配置成功，然后在oracle安装页面重试即可。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402042033249.png"></p><h2 id="10-安装完成"><a href="#10-安装完成" class="headerlink" title="10. 安装完成"></a>10. 安装完成</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402041237315.png" alt="img"></p><h2 id="三、数据库验证"><a href="#三、数据库验证" class="headerlink" title="三、数据库验证"></a>三、数据库验证</h2><p>cmd进入终端，输入sqlplus，提示输入用户名，口令（默认用户名：system，口令：数据库安装时输入的口令），点击回车，进入数据库输入列，则此时数据库安装完成。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402042036375.png"></p><p>运用sql Developer连接Oracle时：<br>​    用户名：system<br>​    口令：数据库安装时输入的口令<br>​    SID：orcl<br>​    若提示：<code>Listener refused the connection with the following error: ORA-12505, TNS:listener does not currently know of SID given in connect descriptor </code> 错误，则：<br>需要找到解压文件<code>\network\admin</code>内的<code>tnsnames.ora</code>文件，将SERVER的值修改为orcl</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/%E5%90%8E%E7%AB%AF/">后端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/">数据库</category>
      
      
      <comments>https://blog.helloallen.cn/a7b87617/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>维持平衡与不平衡</title>
      <link>https://blog.helloallen.cn/342d88cc/</link>
      <guid>https://blog.helloallen.cn/342d88cc/</guid>
      <pubDate>Fri, 02 Feb 2024 23:31:12 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>有读者问我，《大江大河3》相比较于《繁花》，是不是更能体现90年代，是不是更能学到点什么？</p><p>我很好奇地问，你要学什么？</p><p>这个读者回答，他要学习企业管理。</p><p>如果你真是为了学到点什么，是为了学习企业管理，那无论是宝总还是宋厂长，都是带着滤镜的。你通过他们，只能欣赏影视剧，不可能学到点什么。</p><p><font color=red>因为传播学的基本概念就是足够简单。任何东西一旦复杂了，需要思考了，就没法传播了。</font></p><br /><center><font color=red size=5>01</font></center><center><font face="黑体"><b>任何时候，人们都不会</b></font></center><center><font face="黑体"><b>就当时发生的事情进行深刻地讨论</b></font></center><p>前些天有好几个读者留言，说美国之所以无法禁枪的真正原因，是枪支军火集团为了他们的利益。</p><p>这个说法对不对？</p><p>当然是对的。</p><p>但是有没有意义？</p><p>没有。</p><p><font color=red>任何绝对正确的东西，都没有信息含量的。</font></p><p>两个南方人，讨论兰州，说兰州之所以满大街牛肉面，是因为兰州牛肉利益集团的存在。</p><p>这句话对不对？</p><p>太对了，所以我说是废话。</p><p>如果你因为悟到了这么句废话，就以为自己掌握了真理，跑去兰州创业，卖猪肉面，指望自己变成兰州的猪肉利益集团。</p><p>你会亏得连姥姥都不认得。而且破产前还会仰天痛哭，为什么牛肉利益集团能做到的，我猪肉利益集团就不行呢…….</p><p>网民的智慧也是智慧，你能看到美国的枪支利益集团，能看到兰州的牛肉利益集团，恭喜你，你在网民里已经算聪明的了。</p><p>但这种聪明，也就看看电影电视剧行。现实生活中，没啥用的。</p><p>就像咱们读者问两部电视剧哪部能学习？</p><p>哪部也不值得学习。</p><p>因为<font color=red>任何时候，人们都不会就当时发生的事情进行深刻地讨论，这是做不到的。</font></p><p>你不会和你的儿子深刻地剖析自己，不会剖析你的爸爸，不会剖析你的爷爷，不会的。</p><p>你有可能深刻剖析的，是隔壁老王家的爷爷。</p><p>明白我这意思么？</p><p>你的孩子如果要理解深刻的东西，是不可能通过你来做到的，他得通过隔壁老王。</p><p>所以如果你要学企业管理，你不用看这些，这些一定是用来消遣的，你只能去看隔壁老王。</p><p>比如，你可以看看日本的明治维新。</p><br /><center><font color=red size=5>02</font></center><center><font face="黑体"><b>一件事情的过程一定是复杂的</b></font></center><center><font face="黑体"><b>绝对不会只是简单一句话概括</b></font></center><p>你不用去看日本的史料或者怎么怎么样，不需要的，你只要看我们作为邻居对日本明治维新的研究，就已经足够深刻了，已经足够你成长了。</p><p>日本的明治维新是说明治天皇要学欧美，然后一个农业国就转成工业国了？可不可能上下齐心这么简单一句话？</p><p><strong style="border-bottom: 1px green dashed;">这种只是讲过程，一个过程的发生，一定是伴随着复杂的利益分配，以及各种团体的兴起。</strong></p><p>明治要维新，第一件事就是动蛋糕，动了谁的蛋糕？动了整个武士阶层，包括各地藩主的蛋糕。</p><p>日本的农民是把粮食上交大名的，大名再分配给武士，于是武士和大名之间有人身依附关系。</p><p>各地的藩主大名和德川幕府之间也有人身依附关系，这是一个社会结构。</p><p>现在要打破过去的社会结构，就意味着藩主大名没有办法直接征收粮食，矿产，同时也意味着武士阶层集体下岗。</p><p>那这显然不是一句话的事情，兰州的牛肉利益集团也不是一句话就兴起了。</p><p>确切地说，是日本州岛西部以及九州岛的那些武士们，集体留洋，考察英美俄德各个国家，最后企图制定一套新的游戏制度。</p><p>那么这套新游戏下，谁说了算？谁留洋谁说了算，谁留洋谁被重新任命为管理层。而过去的传统武士，就会失业。</p><p>所以这是利益冲突，留洋武士和没留洋武士之间的冲突，大家争的是话语权。</p><p>最后的结果是战争，你看到很多漫画，描述明治维新时期武士，浪人斩的内容，这些都是在讲述那个时代的矛盾冲突。</p><p>打完了之后，拥有武器的留洋派控制了日本，整个武士阶层消失，大家被迫转型，要么去经商，成为后来的三井三菱财阀社团，要么去从政，进入文官体系。</p><p>在这个阶段，日本的下层是一无所知的。</p><p>种地的还是种地，他根本不会理解什么维新不维新，他无非当初粮食交给藩主大名，现在藩主大名没有了，粮食直接上缴。</p><p>在这个过程中，日本农民的负担更重了，因为两个需要。</p><p>一个是需要工业化筹措启动资金，无论是留洋武士还是传统武士，他们都不事生产，财富只能取自农民。</p><p>另一个是为工业化筹措劳动力，俗称失地农民，农民失去了土地，自然会转化成工厂的劳动力。</p><p>俗称出钱是你，出力的还是你。</p><p>这两件事都OK了，明治维新才开启马达，然后就是你知道的，日本人开始发动侵略了，无论对大清还是日俄战争。</p><p>俗称明治维新的本质就是先达成一致，然后让农民出钱，农民出力，最后农民亲自当兵，到处打打打。</p><p>这个过程，你通过了解明治维新的过程是可以初步理解创业的，如果你要做总经理的话。</p><br /><center><font color=red size=5>03</font></center><center><font face="黑体"><b>对一件事感兴趣，要找现实的参照物</b></font></center><center><font face="黑体"><b>不要靠充满滤镜的电视剧</b></font></center><p>你开一家公司，不可能是为了员工如何如何，虽然马云都是这么讲，员工第一，顾客第二，资方第三。</p><p>但实际上真正执行的时候，不是这样的。</p><p>如果你去看繁花，或者看大江大河，你很容易把做生意理解成过家家。</p><p>宝总的朋友很多，女朋友也很多，他人也很仗义，今天帮帮张三，明天帮帮李四，后天张三李四都帮他。</p><p>所谓的商战就是宝总带着一群人，去打对方带着一群人。</p><p>但实际上，你通过了解明治维新也会清楚，日俄战争开打之前，日本自己走过多少路。</p><p><strong style="border-bottom: 1px green dashed;">首先要明确一件事，就是往哪儿走。</strong></p><p><font color=red>我要做什么。</font></p><p>知道自己这家初创公司要做什么比具体怎么做更重要。</p><p>为此日本派出了过半的精英，去各个先发的工业国考察，去研究人家是怎么做的，以及哪部分自己可以抄，哪部分要改良要本土化。</p><p><strong style="border-bottom: 1px green dashed;">那么接下来第二步就是怎么达成一致。</strong></p><p>很多富二代接班失败，被媒体嘲笑成个人能力不足，实际上跟个人能力毛线关系都没有。</p><p>一家公司能够形成，能够运营，它一定是达成了某种平衡的。</p><p>日本存在了那么多年，一定有它的道理，农民交租给藩主大名，藩主大名给武士发工资，这种现存的结构就是平衡。</p><p><font color=red>你要打破这种平衡，就得形成新平衡。</font></p><p><strong style="border-bottom: 1px green dashed;">你动了别人的蛋糕可以，但是你动完蛋糕之后，一定是要达成新的分配方案的。</strong></p><p>李自成为什么注定失败？从第一阶段就注定了。</p><p>闯王来了不纳粮，这就意味着他是一盘散沙。既然不纳粮，那组织结构怎么形成？没有组织结构，你怎么征召兵员呢？都靠个人主观能动性么？</p><p>那么你看我，我看你，都不主动，李自成焉能不败。</p><p>所以明治维新绝对不是说今年你不给武士纳粮了，明天你就吃饱了，你想太美了，没那好事儿。</p><p>创业也是一样的，你永远不可能拿出一个方案大家都满意，资方满意，客户满意，员工满意，这是不可能的。</p><p>你只能拿出一个方案，让大家都误以为自己会是那个被满意的。</p><p>明白不？误以为。</p><p><strong style="border-bottom: 1px green dashed;">误以为，才有积极性，不满意，才有积极性。</strong></p><p>一定要明白这个道理，都对现状满意了，就没有积极性了，公司也就不可能前进了。</p><p><font color=red>人只有对现状不满，又误以为未来会满意，才会有动力。</font></p><p>一个优秀的企业家，一定是理解这个粗浅道理的。</p><p>你才能驾驭着资方，员工，客户，在不平衡的过程中又勉强维持平衡，你需要不平衡来产生动力，你需要平衡来做刹车，开车不能只有油门没有刹车。</p><p>所以我说，如果你对当老板这么感兴趣，随便找点啥做参照物都能明白，无论是隔壁老张还是隔壁老王。</p><p>唯独不要靠电视剧，包括所谓神剧，那些是消遣娱乐的。</p><div style="color:gray;font-size:0.9em">    来源:<br>    [1] <a href="https://zhuanlan.zhihu.com/p/680944228">《繁花》之后《大江大河》也大结局了</a>(逆旅行人)</div>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/%E4%BB%8E%E5%AE%87%E5%AE%99%E8%B5%B7%E6%BA%90%E5%88%B0%E4%BA%BA%E7%B1%BB%E6%96%87%E6%98%8E/">从宇宙起源到人类文明</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E4%BA%BA%E9%97%B4%E4%B8%96/">人间世</category>
      
      
      <comments>https://blog.helloallen.cn/342d88cc/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>十分钟教会你如何使用VitePress搭建及部署个人博客站点</title>
      <link>https://blog.helloallen.cn/c198a4d6/</link>
      <guid>https://blog.helloallen.cn/c198a4d6/</guid>
      <pubDate>Sun, 14 Jan 2024 21:30:32 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>使用VitePress可以让我们快速搭建一个静态博客网站，这篇文章将带领大家搭建一个基于VitePress的静态博客网站并且部署到GitHub Pages(github提供的静态网页服务)</p><h2 id="快速上手"><a href="#快速上手" class="headerlink" title="快速上手"></a>快速上手</h2><h2 id="1-新建目录并初始化-我的目录名为kittydocs"><a href="#1-新建目录并初始化-我的目录名为kittydocs" class="headerlink" title="1.      新建目录并初始化(我的目录名为kittydocs)"></a>1.      新建目录并初始化(我的目录名为kittydocs)</h2><p>这里我们使用pnpm式，当然yarn，npm都是可以的,如果你没有安装pnpm可以全局安装</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i pnpm -g</span><br></pre></td></tr></table></figure><p>然后初始化</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pnpm init</span><br></pre></td></tr></table></figure><h2 id="2-安装vitepress"><a href="#2-安装vitepress" class="headerlink" title="2.      安装vitepress"></a>2.      安装vitepress</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pnpm i vitepress</span><br></pre></td></tr></table></figure><h2 id="3-package-json添加script"><a href="#3-package-json添加script" class="headerlink" title="3.      package.json添加script"></a>3.      package.json添加script</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&quot;scripts&quot;: &#123;</span><br><span class="line">   &quot;docs:dev&quot;: &quot;vitepress dev docs&quot;,</span><br><span class="line">   &quot;docs:build&quot;: &quot;vitepress build docs&quot;,</span><br><span class="line">   &quot;docs:serve&quot;: &quot;vitepress serve docs&quot;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure><p>这三个脚本分别代表启动本地文档服务，打包文档，启动打包后（dist）服务</p><h2 id="4-创建文档-文档放在docs目录下，新建docs-index-md"><a href="#4-创建文档-文档放在docs目录下，新建docs-index-md" class="headerlink" title="4.      创建文档 文档放在docs目录下，新建docs/index.md"></a>4.      创建文档 文档放在docs目录下，新建docs/index.md</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">## hello juejin</span><br></pre></td></tr></table></figure><p>此时我们的文件结构为</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├─ docs </span><br><span class="line">│  └─ index.md</span><br><span class="line">└─ package.json</span><br></pre></td></tr></table></figure><h2 id="5-启动本地服务文档站点"><a href="#5-启动本地服务文档站点" class="headerlink" title="5.      启动本地服务文档站点"></a>5.      启动本地服务文档站点</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pnpm run docs:dev</span><br></pre></td></tr></table></figure><p>此时便会启动一个<a href="https://link.juejin.cn/?target=http://localhost:3000/">http://localhost:3000/</a> 的服务,默认加载docs/index.md</p><p><img src="data:image/webp;base64,UklGRlgTAABXRUJQVlA4IEwTAABQBwGdASqiBaoCPpFIoU0lpKMiIDSYGLASCWlu4XdmQBq8tG+ulACdkfNH+A7TP7/+PfnX4uPY8n9vB1FPln2Y/ReV3ff8Pf7j1CPZH+p8Mv+57fHXPMC9aPrf+w7/X+j9Bfq/7AH6tf7f1e/33gi0BP6Z/gPVl/qP/Z/p/Pd9SewZ+t3/d7Bn7u+0P+4oC4Q6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDeIAXJ9AFckt9+evRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXiOevRl4elflo4dD39C7HPD0770J0AJ/yqFVIwVZL7lFmZFqrdsuUCOIcik1Bl+XaqNMekvNbiHVUmyYh1VJsmIdVSbJiHVUmyYh1VJsmIdVSbJiHVT5CxAju3ieT8anpxSCmj8ed6NCyPsI569GXiOevRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXe2/V6TT33569GXiOevRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXiOevRl4jnr0ZeI569GXDQ47789ejLxHPXoy8Rz16MvEc9ejLxHPXoy8Rz16MvEc9ejLxHPXo0/sjJZri2lUIAYi9hQbkXcMQBZNzNFgES9NtHze5VMsoaqk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqOQV8euiKRRcZ9r3jYmwxDqqTZMQ6qk2TEOqpNkw0P8dVAKspHjN3nuTdIudaPGbvPcm6Rc60dW/Kdy/SOTJKdDyALQ2eTwyZrbhKyPvV7fqbYPyqTZMQ6qk2TEOqpNkxDqqh1uIdVSbJiHVUmyYh1VJsmIdVSbQMXk099+evRl4jnr0ZeI569GXh6TVLgWbiNFWaKrTKYEn1Y8ClBXaBNccghqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMLGM/6wCvIePAH69obuhDqpwE8+cKeeZO/wE0R9OJ0WEtZiVfIZ7q7JETVS68BkSdMNVSbJiHVUmyYh1VJsmIdVSbJiHVUmyYh1VJsmIdVSbJiHVUxde1LctxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6qk2TEOqpNkxDqqTZMQ6q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" alt="img">到这里一个简单的站点就完成了，当然这肯定是不够的，接下来我们看vitepress的配置</p><h2 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h2><p>在docs目录下创建一个 .vuepress目录，如下结构</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├─ docs</span><br><span class="line">│  ├─ .vitepress</span><br><span class="line">│  │  └─ config.js</span><br><span class="line">│  └─ index.md</span><br><span class="line">└─ package.json</span><br></pre></td></tr></table></figure><p>config.js导出一个js对象</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">export default &#123;</span><br><span class="line">    title: &#x27;kittyui&#x27;, //站点标题</span><br><span class="line">    description: &#x27;一个vue3组件库&#x27;,//mate标签description，多用于搜索引擎抓取摘要</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>此时我们重启服务便可看到</p><p><img src="data:image/webp;base64,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" alt="img"></p><h2 id="导航栏"><a href="#导航栏" class="headerlink" title="导航栏"></a>导航栏</h2><h2 id="1-title和logo"><a href="#1-title和logo" class="headerlink" title="1.      title和logo"></a>1.      title和logo</h2><p>首先看一下title和logo的配置</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">export default &#123;</span><br><span class="line">  themeConfig: &#123;</span><br><span class="line">    siteTitle: &quot;Kitty&quot;,</span><br><span class="line">    logo: &quot;/logo.png&quot;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>其中logo的地址对应的是public下的图片，目录结构如下所示</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├─ docs</span><br><span class="line">│  ├─ .vitepress</span><br><span class="line">│  │  └─ config.js</span><br><span class="line">│  ├─ public</span><br><span class="line">│  │   └─ logo.png</span><br><span class="line">│  └─ index.md</span><br><span class="line">└─ package.json</span><br></pre></td></tr></table></figure><p>这里logo我是用了vue的图标，此时页面效果为</p><p><img src="data:image/webp;base64,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" alt="img"></p><h2 id="2-右侧导航"><a href="#2-右侧导航" class="headerlink" title="2.      右侧导航"></a>2.      右侧导航</h2><p>我们可以在themeConfig.nav配置右侧导航,并且点击可以跳转我们指定页面。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">themeConfig: &#123;</span><br><span class="line">  siteTitle: &quot;Kitty&quot;,</span><br><span class="line">  logo: &quot;/logo.png&quot;,</span><br><span class="line">  nav: [</span><br><span class="line">    &#123; text: &quot;Guide&quot;, link: &quot;/guide/&quot; &#125;,</span><br><span class="line">    &#123; text: &quot;GuideTest&quot;, link: &quot;/guide/test&quot; &#125;,</span><br><span class="line">    &#123; text: &quot;gitee&quot;, link: &quot;https://gitee.com/geeksdidi&quot; &#125;,</span><br><span class="line">  ],</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同时我们在docs下新建guide/index.md和<a href="https://test.md/">test.md</a></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># guild</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># test</span><br></pre></td></tr></table></figure><p>此时我们页面即可展示我们打nva并且支持了跳转本地markdown文件以及外部链接</p><p><img src="data:image/webp;base64,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" alt="img">我们还可以这样嵌套配置，使得导航栏出现下拉选项</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">themeConfig: &#123;</span><br><span class="line">    siteTitle: &quot;Kitty&quot;,</span><br><span class="line">    logo: &quot;/logo.png&quot;,</span><br><span class="line">    nav: [</span><br><span class="line">      &#123; text: &quot;Guide&quot;, link: &quot;/guide/&quot; &#125;,</span><br><span class="line">      &#123; text: &quot;GuideTest&quot;, link: &quot;/guide/test&quot; &#125;,</span><br><span class="line">      &#123; text: &quot;gitee&quot;, link: &quot;https://gitee.com/geeksdidi&quot; &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        text: &quot;Drop Menu&quot;,</span><br><span class="line">        items: [</span><br><span class="line">          &#123; text: &#x27;Item A&#x27;, link: &#x27;/item-1&#x27; &#125;,</span><br><span class="line">          &#123; text: &#x27;Item B&#x27;, link: &#x27;/item-2&#x27; &#125;,</span><br><span class="line">          &#123; text: &#x27;Item C&#x27;, link: &#x27;/item-3&#x27; &#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p><img src="data:image/webp;base64,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" alt="img"></p><p>如果我们想要让下拉选项分组，即中间有条分割线，我们的nav可以这样写</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">nav: [</span><br><span class="line">     &#123; text: &quot;Guide&quot;, link: &quot;/guide/&quot; &#125;,</span><br><span class="line">     &#123; text: &quot;GuideTest&quot;, link: &quot;/guide/test&quot; &#125;,</span><br><span class="line">     &#123; text: &quot;gitee&quot;, link: &quot;https://gitee.com/geeksdidi&quot; &#125;,</span><br><span class="line">     &#123;</span><br><span class="line">       text: &quot;Drop Menu&quot;,</span><br><span class="line">       items: [</span><br><span class="line">         &#123;</span><br><span class="line">           items: [</span><br><span class="line">             &#123; text: &quot;Item A1&quot;, link: &quot;/item-A1&quot; &#125;,</span><br><span class="line">             &#123; text: &quot;Item A2&quot;, link: &quot;/item-A2&quot; &#125;,</span><br><span class="line">           ],</span><br><span class="line">         &#125;,</span><br><span class="line">         &#123;</span><br><span class="line">           items: [</span><br><span class="line">             &#123; text: &quot;Item B1&quot;, link: &quot;/item-B1&quot; &#125;,</span><br><span class="line">             &#123; text: &quot;Item B2&quot;, link: &quot;/item-B2&quot; &#125;,</span><br><span class="line">           ],</span><br><span class="line">         &#125;,</span><br><span class="line">       ],</span><br><span class="line">     &#125;,</span><br><span class="line">   ]</span><br></pre></td></tr></table></figure><p>此时效果为</p><p><img src="data:image/webp;base64,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" alt="img"></p><h2 id="配置社交链接socialLinks"><a href="#配置社交链接socialLinks" class="headerlink" title="配置社交链接socialLinks"></a>配置社交链接socialLinks</h2><p>使用themeConfig.socialLinks可以配置我们的社交链接，目前支持的有</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">type SocialLinkIcon =</span><br><span class="line">  | &#x27;discord&#x27;</span><br><span class="line">  | &#x27;facebook&#x27;</span><br><span class="line">  | &#x27;github&#x27;</span><br><span class="line">  | &#x27;instagram&#x27;</span><br><span class="line">  | &#x27;linkedin&#x27;</span><br><span class="line">  | &#x27;slack&#x27;</span><br><span class="line">  | &#x27;twitter&#x27;</span><br><span class="line">  | &#x27;youtube&#x27;</span><br><span class="line">  | &#123; svg: string &#125;</span><br></pre></td></tr></table></figure><p>配置如下</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">socialLinks: [</span><br><span class="line">      &#123; icon: &quot;github&quot;, link: &quot;https://gitee.com/geeksdidi&quot; &#125;,</span><br><span class="line">      &#123; icon: &quot;twitter&quot;, link: &quot;...&quot; &#125;,</span><br><span class="line">      // You can also add custom icons by passing SVG as string:</span><br><span class="line">      &#123;</span><br><span class="line">        icon: &#123;</span><br><span class="line">          svg: &#x27;&lt;svg role=&quot;img&quot; viewBox=&quot;0 0 24 24&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;title&gt;Dribbble&lt;/title&gt;&lt;path d=&quot;M12...6.38z&quot;/&gt;&lt;/svg&gt;&#x27;,</span><br><span class="line">        &#125;,</span><br><span class="line">        link: &quot;...&quot;,</span><br><span class="line">      &#125;,</span><br><span class="line">    ],</span><br></pre></td></tr></table></figure><p><img src="data:image/webp;base64,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" alt="img"></p><h2 id="侧边栏Sidebar"><a href="#侧边栏Sidebar" class="headerlink" title="侧边栏Sidebar"></a>侧边栏Sidebar</h2><p>侧边栏可以在themeConfig.Sidebar中配置，其实和nav配置差不多</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">sidebar: [</span><br><span class="line">  &#123;</span><br><span class="line">    text: &quot;组件库源码实现&quot;,</span><br><span class="line">    items: [</span><br><span class="line">      &#123;</span><br><span class="line">        text: &quot;组件库环境搭建&quot;,</span><br><span class="line">        link: &quot;/articles/组件库环境搭建&quot;,</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123; text: &quot;gulp的使用&quot;, link: &quot;/articles/gulp的使用&quot; &#125;,</span><br><span class="line">    ],</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    text: &quot;vue教程&quot;,</span><br><span class="line">    items: [</span><br><span class="line">      &#123;</span><br><span class="line">        text: &quot;pina和vuex&quot;,</span><br><span class="line">        link: &quot;/articles/pina和vuex&quot;,</span><br><span class="line">      &#125;,</span><br><span class="line">    ],</span><br><span class="line">  &#125;,</span><br><span class="line">],</span><br></pre></td></tr></table></figure><p>这里我搬运了我掘金上的一些文章放了进去，目录结构如下图</p><p><img src="data:image/webp;base64,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" alt="img"></p><p>页面展示效果如下</p><p><img src="data:image/webp;base64,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" alt="img">不过我们一般不会使用这种方式配置侧边栏，因为这样每个页面都会有侧边栏。我们需要做到仅某些页面才会出现侧边栏。所以我们可以这样配置</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">sidebar: &#123;</span><br><span class="line">  &quot;/articles/&quot;: [</span><br><span class="line">    &#123;</span><br><span class="line">      text: &quot;组件库源码实现&quot;,</span><br><span class="line">      items: [</span><br><span class="line">        &#123;</span><br><span class="line">          text: &quot;组件库环境搭建&quot;,</span><br><span class="line">          link: &quot;/articles/组件库环境搭建&quot;,</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123; text: &quot;gulp的使用&quot;, link: &quot;/articles/gulp的使用&quot; &#125;,</span><br><span class="line">      ],</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      text: &quot;vue教程&quot;,</span><br><span class="line">      items: [</span><br><span class="line">        &#123;</span><br><span class="line">          text: &quot;pina和vuex&quot;,</span><br><span class="line">          link: &quot;/articles/pina和vuex&quot;,</span><br><span class="line">        &#125;,</span><br><span class="line">      ],</span><br><span class="line">    &#125;,</span><br><span class="line">  ],</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><p>sideBar值改成一个对象，对象的key是一个路径，只有包含这个路径的才会出现侧边栏。所以我们将nav的配置中的guild改成博客，同时路径指向我们的articles下的markdown文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">nav: [</span><br><span class="line">      &#123; text: &quot;博客&quot;, link: &quot;/articles/组件库环境搭建&quot; &#125;,</span><br><span class="line">     ]</span><br></pre></td></tr></table></figure><p>此时你会发现进入首页并不会出现sideBar，只有点击博客才会出现侧边栏</p><p><img src="data:image/webp;base64,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" alt="img"></p><h2 id="配置可折叠侧边栏"><a href="#配置可折叠侧边栏" class="headerlink" title="配置可折叠侧边栏"></a>配置可折叠侧边栏</h2><p>配置可折叠侧边栏只需将collapsible设置为true即可,默认初始页面是全部展开页面，如果你需要关闭状态只需要将collapsed设置为true</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line">        &#123;</span><br><span class="line">          text: &quot;vue教程&quot;,</span><br><span class="line">          collapsible: true,</span><br><span class="line">          collapsed:true,</span><br><span class="line">          items: [</span><br><span class="line">            &#123;</span><br><span class="line">              text: &quot;pina和vuex&quot;,</span><br><span class="line">              link: &quot;/articles/pina和vuex&quot;,</span><br><span class="line">            &#125;,</span><br><span class="line">          ],</span><br><span class="line">        &#125;,</span><br><span class="line">...</span><br></pre></td></tr></table></figure><h2 id="首页布局"><a href="#首页布局" class="headerlink" title="首页布局"></a>首页布局</h2><p>首页就是进入我们博客会加载docs/index.md,所以我们需要对其进行一个美化，我们VitePress默认主题提供了一个主页布局</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">layout: home</span><br><span class="line"></span><br><span class="line">hero:</span><br><span class="line">  name: 东方小月的博客</span><br><span class="line">  text: 随便写点啥.</span><br><span class="line">  tagline: 帅气又迷人的小月</span><br><span class="line">  image:</span><br><span class="line">    src: /logo.png</span><br><span class="line">    alt: Kitty</span><br><span class="line">  actions:</span><br><span class="line">    - theme: brand</span><br><span class="line">      text: 快来快来</span><br><span class="line">      link: /articles/组件库环境搭建</span><br><span class="line">    - theme: alt</span><br><span class="line">      text: View on Gitee</span><br><span class="line">      link: https://gitee.com/geeksdidi</span><br><span class="line"></span><br><span class="line">features:</span><br><span class="line">  - icon: ⚡️</span><br><span class="line">    title: 这是一个闪电图标</span><br><span class="line">    details: wawawa</span><br><span class="line">  - icon: 🖖</span><br><span class="line">    title: 这是一个手掌图标</span><br><span class="line">    details: good...</span><br><span class="line">  - icon: 🛠️</span><br><span class="line">    title: 这是一个修理图标</span><br><span class="line">    details: cocococo</span><br><span class="line">---</span><br></pre></td></tr></table></figure><p><img src="data:image/webp;base64,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" alt="img"></p><h2 id=""><a href="#" class="headerlink" title=""></a></h2><h2 id="部署到GitHub-Pages"><a href="#部署到GitHub-Pages" class="headerlink" title="部署到GitHub Pages"></a>部署到GitHub Pages</h2><h2 id="1-新建github仓库"><a href="#1-新建github仓库" class="headerlink" title="1.      新建github仓库"></a>1.      新建github仓库</h2><p>既然要部署到GitHub Pages，你得先在github新建一个仓库，因为要用他的GitHub Pages，所以仓库命名为username.github.io的形式，username是你github的用户名。然后点击设置</p><p><img src="data:image/webp;base64,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" alt="img">选择pages</p><p><img src="data:image/webp;base64,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" alt="img">这里设置根目录/(root),当然也可以选择其它目录,点击保存，如果选择其它目录比如docs，config.js就需要配置一个base</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">export default &#123;</span><br><span class="line">    base:&#x27;/docs/&#x27;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>最后选择一个主题(这里不选择我发现站点不生效,后面把打包后的代码推上来即可,会默认加载index.html)</p><h2 id="2-通过-deploy-sh-部署"><a href="#2-通过-deploy-sh-部署" class="headerlink" title="2.      通过 deploy.sh 部署"></a>2.      通过 <a href="https://deploy.sh/">deploy.sh</a> 部署</h2><p>然后将打包后的dist下的文件推送到你的远程仓库。vitepress官网给我们提供了一个脚本文件deploy.sh，我们只需要改下远程仓库即可</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env sh</span><br><span class="line"></span><br><span class="line"># 忽略错误</span><br><span class="line">set -e</span><br><span class="line"></span><br><span class="line"># 构建</span><br><span class="line">npm run docs:build</span><br><span class="line"></span><br><span class="line"># 进入待发布的目录</span><br><span class="line">cd docs/.vitepress/dist</span><br><span class="line"></span><br><span class="line"># 如果是发布到自定义域名</span><br><span class="line"># echo &#x27;www.example.com&#x27; &gt; CNAME</span><br><span class="line"></span><br><span class="line">git init</span><br><span class="line">git add -A</span><br><span class="line">git commit -m &#x27;deploy&#x27;</span><br><span class="line"></span><br><span class="line"># 如果部署到 https://&lt;USERNAME&gt;.github.io</span><br><span class="line"># git push -f git@github.com:&lt;USERNAME&gt;/&lt;USERNAME&gt;.github.io.git master</span><br><span class="line"></span><br><span class="line"># 如果是部署到 https://&lt;USERNAME&gt;.github.io/&lt;REPO&gt;</span><br><span class="line"># git push -f git@github.com:&lt;USERNAME&gt;/&lt;REPO&gt;.git master:gh-pages</span><br><span class="line"></span><br><span class="line">cd -</span><br></pre></td></tr></table></figure><p>直接执行这个脚本文件，我们的打包后的文件就会被推送到我们的仓库。然后我们就可以直接访问我们的静态博客站点了，如果你想要自定义其它域名的话,可以创建一个组织然后在组织下新建仓库名为organization.github.io的形式(organization是你组织名)然后执行同样的操作即可。具体可以点这里<a href="https://link.juejin.cn/?target=https://docs.github.com/cn/pages/getting-started-with-github-pages/creating-a-github-pages-site">创建 GitHub Pages 站点</a></p><h2 id="3-通过Windows系统下使用的脚本文件部署"><a href="#3-通过Windows系统下使用的脚本文件部署" class="headerlink" title="3.      通过Windows系统下使用的脚本文件部署"></a>3.      通过Windows系统下使用的脚本文件部署</h2><p>上一步我们上传的仅仅是工程的源代码。还需要上传构建成果，才能发布博客网站。我们在工程根目录创建文件bin/autoDeploy.bat，这是一个Windows系统下使用的脚本文件。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">call pnpm docs:build</span><br><span class="line">cd docs/.vitepress/dist</span><br><span class="line"></span><br><span class="line">git init</span><br><span class="line">git add -A</span><br><span class="line">git commit -m &quot;auto construct blog&quot;</span><br><span class="line"></span><br><span class="line">git push -f https://github.com/jzplp/jzplp.github.io.git master:gh-pages</span><br></pre></td></tr></table></figure><p>注意里面的push地址需要改成你自己的。</p><p>文件内容即是我们的构建和发布流程： 1. 构建工程，生成dist，并进入dist目录。 2. 将dist目录中的内容上传至gh-pages分支中。</p><p>如果使用非Windows系统，对该脚本文件后缀名和内容进行适当修改即可。</p><p>我们在package.json的scripts中增加一条命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&quot;deploy:win&quot;: &quot;powershell bin/autoDeploy.bat&quot;</span><br></pre></td></tr></table></figure><p>此时可以执行这条命令，即可完成dist构建包的上传。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pnpm deploy:win</span><br></pre></td></tr></table></figure><h2 id="4-使用GitHub-Actions进行自动构建和发布"><a href="#4-使用GitHub-Actions进行自动构建和发布" class="headerlink" title="4.      使用GitHub Actions进行自动构建和发布"></a>4.      使用GitHub Actions进行自动构建和发布</h2><p>使用上面描述的方法，我们每次写完博客，提交工程代码后，还需要手动构建，更新分支并发布。</p><p>那么有没有方法让每次提交工程代码后，自动构建并发布呢？我们使用GitHub Actions就能做到这一点。而且GitHub还提供了服务器，我们可以把构建过程放到服务器中进行。</p><p>首先创建配置文件，位置.github/workflows/deploy.yml。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">name: algolia</span><br><span class="line">on: </span><br><span class="line">  push:  # 有代码push或者merge到main分支时，才进行下面的操作</span><br><span class="line">    branches: </span><br><span class="line">      - main</span><br><span class="line">jobs:</span><br><span class="line">  deploy:</span><br><span class="line">    runs-on: ubuntu-latest </span><br><span class="line">    steps:</span><br><span class="line">      - name: Checkout</span><br><span class="line">        uses: actions/checkout@v3</span><br><span class="line"></span><br><span class="line">      - name: Install Node.js</span><br><span class="line">        uses: actions/setup-node@v3</span><br><span class="line">        with:</span><br><span class="line">          node-version: 16</span><br><span class="line"></span><br><span class="line">      - uses: pnpm/action-setup@v2  # 配置使用pnpm</span><br><span class="line">        name: Install pnpm</span><br><span class="line">        id: pnpm-install</span><br><span class="line">        with:</span><br><span class="line">          version: 8</span><br><span class="line">          run_install: false</span><br><span class="line">      </span><br><span class="line">      - name: Get pnpm store directory</span><br><span class="line">        id: pnpm-cache</span><br><span class="line">        shell: bash</span><br><span class="line">        run: |</span><br><span class="line">          echo &quot;STORE_PATH=$(pnpm store path)&quot; &gt;&gt; $GITHUB_OUTPUT</span><br><span class="line"></span><br><span class="line">      - uses: actions/cache@v3</span><br><span class="line">        name: Setup pnpm cache</span><br><span class="line">        with:</span><br><span class="line">          path: $&#123;&#123; steps.pnpm-cache.outputs.STORE_PATH &#125;&#125;</span><br><span class="line">          key: $&#123;&#123; runner.os &#125;&#125;-pnpm-store-$&#123;&#123; hashFiles(&#x27;**/pnpm-lock.yaml&#x27;) &#125;&#125;</span><br><span class="line">          restore-keys: |</span><br><span class="line">            $&#123;&#123; runner.os &#125;&#125;-pnpm-store-</span><br><span class="line"></span><br><span class="line">      - name: Install dependencies</span><br><span class="line">        run: pnpm install</span><br><span class="line"></span><br><span class="line">      - name: Build docs</span><br><span class="line">        run: pnpm run docs:build</span><br><span class="line"></span><br><span class="line">      - name: Deploy Files on Ftp Server</span><br><span class="line">        uses: SamKirkland/FTP-Deploy-Action@4.3.3</span><br><span class="line">        with:</span><br><span class="line">         server: &#x27;&#x27; # FTP服务器地址</span><br><span class="line">         username: &#x27;&#x27; # FTP用户名</span><br><span class="line">         password: &#x27;&#x27; # FTP密码</span><br><span class="line">         local-dir: ./docs/.vitepress/dist/ #需要发布内容的路径</span><br><span class="line">         server-dir: ./wwwroot/</span><br><span class="line">         protocol: ftp</span><br><span class="line">         port: 21</span><br></pre></td></tr></table></figure><p>GitHub Actions的环境中提供了很多预置的配置和工具，例如Node.js，pnpm等等，我们直接使用即可。如果你的配置和文中上述流程一致，那么直接复制该文件内容到你的工程即可。之后上传到工程代码GitHub仓库中。如果想了解更多，可以参考<a href="https://link.zhihu.com/?target=https://docs.github.com/zh/actions">GitHub Actions文档</a>以及其他人的配置。</p><p>当然，你如果没有自己的FTP服务器，希望自动部署到Github Pages，配置方法参考：<a href="https://blog.helloallen.cn/2023/12/24/%E4%BD%BF%E7%94%A8Github-Action%E5%AE%9E%E7%8E%B0%E5%85%A8%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2/">使用Github Action实现全自动部署</a></p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Others/">Others</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/">博客搭建</category>
      
      
      <comments>https://blog.helloallen.cn/c198a4d6/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>你想要的【微前端】都在这里了！</title>
      <link>https://blog.helloallen.cn/a38cd327/</link>
      <guid>https://blog.helloallen.cn/a38cd327/</guid>
      <pubDate>Tue, 26 Dec 2023 00:01:42 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><h2 id="1-什么是微前端"><a href="#1-什么是微前端" class="headerlink" title="1.      什么是微前端"></a>1.      什么是微前端</h2><p>微前端提供了一种技术：可以将多个独立的Web应用聚合到一起，提供统一的访问入口。一个微前端应用给用户的感观就是一个完整的应用，但从技术角度上来讲它是由一个个独立的、通过某种方式组合而成的应用。</p><h2 id="2-微前端的特点"><a href="#2-微前端的特点" class="headerlink" title="2.      微前端的特点"></a>2.      微前端的特点</h2><p>目前的微前端框架一般都具有以下三个特点：</p><p>（1）技术栈无关：主框架不限制接入应用的技术栈，子应用具备完全自主权。</p><p>（2）独立性强：独立开发、独立部署，子应用仓库独立。</p><p>（3）状态隔离：运行时每个子应用之间状态隔离。</p><h2 id="3-微前端发展历史"><a href="#3-微前端发展历史" class="headerlink" title="3.      微前端发展历史"></a>3.      微前端发展历史</h2><p>（1）2014年：<code>Martin Fowler</code>和<code>James Lewis</code>共同提出了微服务的概念。微服务的主要思路是将应用分解为小的、互相连接的独立服务，每个微服务完成某个特定功能；每个微服务都有自己的业务逻辑和适配器，不同的微服务可以使用不同的技术去实现，最后使用统一的网关进行调用。</p><p>（2）2016年：<code>Micro frontend</code>一词首次出现在<code>ThoughtWorks Technology Radar</code>上。它将微服务的概念扩展到前端世界，简称其为微前端。</p><p>（3）2018年：第一个微前端工具<code>single-spa</code>在<code>github</code>上开源。</p><p>（4）2019年：基于<code>single-spa</code>的<code>qiankun</code>问世。</p><p>（5）2020年：<code>Module Federation(webpack5)</code>把项目中模块分为本地模块和远程模块，远程模块不属于当前构建。当使用远程模块时，这些异步操作将被放置在远程模块和入口之间的下一个chunk的加载操作中，从而实现微前端的构建。</p><p>（6）2021年：基于 <code>WebComponent</code> 的 <code>micro-app</code> 问世。</p><p>（7）2022年：基于 <code>Web Components + iframe</code> 微前端框架无界（<code>wujie</code>）问世。</p><h2 id="4-如何判断自己的项目需要使用微前端？"><a href="#4-如何判断自己的项目需要使用微前端？" class="headerlink" title="4.      如何判断自己的项目需要使用微前端？"></a>4.      如何判断自己的项目需要使用微前端？</h2><p>（1）项目功能逐渐增多，代码规模庞大，导致代码维护和开发效率低下；</p><p>（2）项目需要集成多个不同技术栈的模块或服务；</p><p>（3）团队成员分散，各自负责开发不同的模块或服务，需要实现独立开发和部署；</p><p>（4）项目需要支持独立的生命周期管理和版本控制；</p><p>（5）需要实现高可用性和弹性伸缩；</p><p>（6）需要实现动态加载和卸载子应用等场景。</p><p>所以呢，觉得如果项目具有上面这些特点，那么可以考虑使用微前端来优化项目架构和提升开发效率。</p><br /><h2 id="微前端框架"><a href="#微前端框架" class="headerlink" title="微前端框架"></a>微前端框架</h2><h2 id="1-iframe"><a href="#1-iframe" class="headerlink" title="1.      iframe"></a>1.      iframe</h2><h3 id="（1）为iframe正名"><a href="#（1）为iframe正名" class="headerlink" title="（1）为iframe正名"></a>（1）为iframe正名</h3><p>任何新技术、新产品都是有一定适用场景的，它可能在当下很流行，但它不一定在任何时候都是最优解。</p><p>最近几年微前端很火，火到有时候项目里面用到了iframe还要偷偷摸摸地藏起来生怕被别人知道了，因为担心被人质疑：你为什么不用微前端方案？直到最近笔者接手一个项目，需要将现有的一个系统整体嵌入到另外一个系统（一共20多个页面），在被微前端坑了几次之后，回过头发现，iframe真香！</p><p>诚然iframe确实存在很多缺点，但是在选择一个方案的时候还是要具体场景具体分析，它可能在当下很流行，但它不一定在任何时候都是最优解：iframe的这些缺点对我来说是否能够接受？它的缺点是否有其它方法可以弥补？使用它到底是利大于弊还是弊大于利？我们需要在优缺点之间找到一个平衡。</p><h3 id="（2）优缺点分析"><a href="#（2）优缺点分析" class="headerlink" title="（2）优缺点分析"></a>（2）优缺点分析</h3><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252243003.png"></p><h3 id="（3）iframe适合的场景"><a href="#（3）iframe适合的场景" class="headerlink" title="（3）iframe适合的场景"></a>（3）iframe适合的场景</h3><p>由于iframe的一些限制，部分场景并不适合用iframe，比如像下面这种iframe只占据页面中间部分区域，由于父页面已经有一个滚动条了，为了避免出现双滚动条，只能动态计算iframe的内容高度赋值给iframe，使得iframe高度完全撑满，但这样带来的问题是弹窗很难处理，如果居中的话一般弹窗都相对的是iframe内容高度而不是屏幕高度，从而导致弹窗可能看不见，如果固定弹窗top又会导致弹窗跟随页面滚动，而且稍有不慎iframe内容高度计算有一点点偏差就会出现双滚动条。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252244542.png"></p><p>所以：</p><ul><li><p>如果页面本身比较简单，是一个没有弹窗、浮层、高度也是固定的纯信息展示页的话，用iframe一般没什么问题；</p></li><li><p>如果页面是包含弹窗、信息提示、或者高度不是固定的话，需要看iframe是否占据了全部的内容区域，如果是像下图这种经典的导航+菜单+内容结构、并且整个内容区域都是iframe，那么可以放心大胆地尝试iframe，否则，需要慎重考虑方案选型。</p></li></ul><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252244319.png"></p><p>为什么一定要满足“iframe占据全部内容区域”这个条件呢？可以想象一下下面这种场景，滚动条出现在页面中间应该大部分人都无法接受：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252245128.png"></p><h3 id="（4）利用-iframe-实现微前端实战"><a href="#（4）利用-iframe-实现微前端实战" class="headerlink" title="（4）利用 iframe 实现微前端实战"></a>（4）利用 iframe 实现微前端实战</h3><p><a href="https://helloallenw.github.io/2023/12/25/iframe-%E5%AE%9E%E7%8E%B0%E5%BE%AE%E5%89%8D%E7%AB%AF/">iframe 实现微前端</a></p><h2 id="2-single-spa"><a href="#2-single-spa" class="headerlink" title="2.      single-spa"></a>2.      single-spa</h2><p><code>single-spa</code>是第一个微前端框架，当前流行的大量框架都是single-spa的上层封装，但是如果作为生产选型，single-spa提供的是较为基础的api，应用在实际项目中需要进行大量封装且入侵性强，使用起来不太方便。但是如果想学习相关技术或者封装一套更灵活的解决方法还是很值得使用的。</p><p>如果想了解更多关于single-spa，请查看：<a href="https://helloallenw.github.io/2023/12/25/%E5%BE%AE%E5%89%8D%E7%AB%AF%EF%BC%88single-spa%EF%BC%89%E7%AE%80%E4%BB%8B/">微前端（single-spa）简介</a></p><h2 id="3-qiankun"><a href="#3-qiankun" class="headerlink" title="3.      qiankun"></a>3.      qiankun</h2><p><code>qiankun</code>是阿里开源的一套框架，基于single-spa的上层封装，社区活跃度较高，在国内的生态较好，中文文档齐全，有大量的先行者铺路，比较适合用于生产环境。</p><h3 id="（1）运行原理"><a href="#（1）运行原理" class="headerlink" title="（1）运行原理"></a>（1）运行原理</h3><p>qiankun 和 single-spa最大的不同，在于single-spa 是基于JS Entry，即通过某一地址引入JS文件来加载整个子应用。 而 qiankun是通过 HTML Entry，规避了JavaScript为了支持缓存而根据文件内容动态生成文件名，造成入口文件无法锁定的问题。</p><p>在qiankun中，当我们拿到了子应用的 HTML 文本时，我们不能直接通过 <code>container.innerHTML = html</code> 方式将文本放到容器内，这样是无法显示的。</p><p>原因是浏览器出于安全考虑，放到页面上的 HTML 如果包含了 JS 脚本，它是不会去执行的。所以我们需要手动处理 script 脚本，qiankun是通过 import-html-entry 包来获取并处理子应用资源的。</p><p>qiankun首先通过URL获取到整个HTML文件，从HTML中解析出HTML，JS和CSS文本。在主应用中创建容器，把HTML更新到容器中。然后动态创建style和script标签，把子应用的css和js赋值在其中，最后把容器放置在主应用中。具体过程如下：</p><ul><li><p>a：qiankun 会用 原生fetch方法，请求微应用的 entry 获取微应用资源，然后通过 response.text 把获取内容转为字符串。</p></li><li><p>b：将 HTML 字符串传入processTpl函数，进行 HTML 模板解析，通过正则匹配 HTML 中对应的 javaScript（内联、外联）、css（内联、外联）、代码注释、entry、ignore 收集并替换，去除 html/head/body 等标签，其他资源保持原样。</p></li><li><p>c：将收集的 styles 外链URL对象通过 fetch 获取 css，并将 css 内容以 <code>&lt;style&gt;</code> 的方式替换到原来 link 标签的位置。</p></li><li><p>d：收集 script 外链对象，对于异步执行的 JavaScript 资源会打上 async 标识 ，会使用 requestIdleCallback 方法延迟执行。</p></li><li><p>e：接下来会创建一个匿名自执行函数包裹住获取到的 js 字符串，最后通过 eval 去创建一个执行上下文执行 js 代码，通过传入 proxy 改变 window 指向，完成 JavaScript 沙箱隔离。</p></li><li><p>f：由于 qiankun 是自执行函数执行微应用的 JavaScript，因此在加载后的微应用中是看不到 JavaScript 资源引用的，只有一个资源被执行替换的标识。</p></li><li><p>g：当一切准备就绪的时候，执行微应用的 JavaScript 代码，渲染出微应用。</p></li></ul><h3 id="（2）局限性"><a href="#（2）局限性" class="headerlink" title="（2）局限性"></a>（2）局限性</h3><p>qiankun不是一个完整的微前端解决方案！！！</p><h4 id="微前端的运行时容器"><a href="#微前端的运行时容器" class="headerlink" title="微前端的运行时容器"></a>微前端的运行时容器</h4><ul><li><p>a：qiankun 所帮你解决的这一块实际上是微前端的运行时容器，这是整个微前端工程化里面其中一个环节。</p></li><li><p>b：从这个角度来讲 qiankun 不算是一个完整的微前端解决方案，而是微前端运行时容器的一个完整解决方案，当你用了 qiankun 之后，你几乎能解决所有的微前端运行时容器的问题，但是更多的一些涉及工程和平台的问题，则需要我们去思考与处理。</p></li><li><p>c：我们的版本管控、配置下发、监控发布，安全检测、等等这些怎么做，都不是 qiankun 作为一个库所能解答的，这些问题得根据具体情况，来选择适合自己的解决方案。</p></li><li><p>d：对于老旧项目的接入，很难做到零成本迁移，在开发的时候要预留足够的踩坑，魔改代码的时间。如果是已经维持几年堆叠的屎山需要做好因为不规范编码，所产生的各种奇怪的兼容性问题，这个时候你甚至会怀疑，“微前端是否真的有必要?”</p></li><li><p>e：微前端的核心不是多技术共存，而是分解复杂度，提升协作效率，支持灵活扩展，能把“一堆复杂的事情”变成“简单的一件事情”，但是也不是无脑使用的，广东话来说“多个香炉多只鬼”，每多一个技术栈都会增加：维护成本，兼容成本，资源开销成本，这些都会无形的拖累生产力。</p></li><li><p>f：基座应用与微应用之间，强烈推荐使用相同的技术栈，相同的技术栈可以实现公共依赖库、UI库等抽离，减少资源开销，提升加载速度，最重要的是：“减少冲突的最好方式就是统一”，通过约束技术栈可以尽可能的减少项目之间的冲突，减少工作量与维护成本。</p></li></ul><h4 id="标准化才能提升生产力"><a href="#标准化才能提升生产力" class="headerlink" title="标准化才能提升生产力"></a>标准化才能提升生产力</h4><ul><li><p>a：混乱的项目会拖累生产效率，同时混乱的微前端也会加剧内耗，所以只有标准化才能提升生产力。</p></li><li><p>b：<strong>解决微前端的接入问题是最简单的，但是微前端接入后的：工程化，应用监控，应用规范，应用管理才是微前端中困难的地方</strong>，如果你只是想简单的嵌入一个应用，我推荐你的使用 <code>iframe</code></p></li></ul><h3 id="（3）微前端（qiankun）实战"><a href="#（3）微前端（qiankun）实战" class="headerlink" title="（3）微前端（qiankun）实战"></a>（3）微前端（qiankun）实战</h3><p>关于qiankun的使用，以及使用过程中的各类问题请查看：<a href="https://helloallenw.github.io/2023/12/25/%E5%BE%AE%E5%89%8D%E7%AB%AF%EF%BC%88qiankun%EF%BC%89%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C/">微前端（qiankun）使用手册</a></p><h2 id="4-MicorApp"><a href="#4-MicorApp" class="headerlink" title="4.      MicorApp"></a>4.      MicorApp</h2><p><code>MicroApp</code>是京东基于类<code>WebComponent</code>进行渲染的微前端框架，不同于目前流行的开源框架，它从组件化的思维实现微前端，旨在降低上手难度、提升工作效率。它是目前市面上接入微前端成本最低的框架，并且提供了JS沙箱、样式隔离、元素隔离、预加载、资源地址补全、插件系统、数据通信等一系列完善的功能。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252246813.png"></p><p>关于microApp实战请查看：<a href="https://helloallenw.github.io/2023/12/25/%E5%BE%AE%E5%89%8D%E7%AB%AF%EF%BC%88micro-app%EF%BC%89%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C/">微前端（micro-app）使用手册</a></p><h2 id="5-无界"><a href="#5-无界" class="headerlink" title="5.      无界"></a>5.      无界</h2><p>无界微前端是腾讯基于 <code>Web Components + iframe</code> 开发的微前端框架，具备成本低、速度快、原生隔离、功能强等一系列优点。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252247546.png"></p><h2 id="6-Module-Federation以及EMP"><a href="#6-Module-Federation以及EMP" class="headerlink" title="6.      Module Federation以及EMP"></a>6.      Module Federation以及EMP</h2><p><code>Module Federation</code>是webpack5中的新特性，主要是用来解决多个应用之间代码共享的问题，可以更加优雅的实现跨应用的代码共享，使用这个方法也可以实现微前端。</p><p>这个方案中有两个主体：Remote和Host，可以把Remote理解为想要引入的子应用，把Host理解为主应用（但是一个应用既可以是Remote也可以是Host，并不矛盾）。</p><p>Module Federation的核心在于ModuleFederationPlugin这个插件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * name: （必须）唯一ID，作为输出的模块名，使用的时通过name/&#123;expose&#125;的方式使用</span><br><span class="line"> * library：（必须）其中这里的name为作为umd的name</span><br><span class="line"> * remotes：（可选）表示作为Host时，去消费哪些Remote</span><br><span class="line"> * exposes：（可选）表示作为Remote时，export哪些属性被消费</span><br><span class="line"> * shared：（可选）优先用Host的依赖，如果Host没有，再用自己的</span><br><span class="line"> */</span><br><span class="line">new ModuleFederationPlugin(&#123;</span><br><span class="line">  name: &quot;App1&quot;,</span><br><span class="line">  library: &#123; type: &quot;var&quot;, name: &quot;App1&quot; &#125;,</span><br><span class="line">  filename: &quot;remoteEntry.js&quot;,</span><br><span class="line">  remotes: &#123;</span><br><span class="line">    app_02: &#x27;App2&#x27;,</span><br><span class="line">    app_03: &#x27;App3&#x27;,</span><br><span class="line">  &#125;,</span><br><span class="line">  exposes: &#123;</span><br><span class="line">    antd: &#x27;./src/antd&#x27;,</span><br><span class="line">    button: &#x27;./src/button&#x27;,</span><br><span class="line">  &#125;,</span><br><span class="line">  shared: [&#x27;react&#x27;, &#x27;react-dom&#x27;],</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>通过以上设置打包之后会生成三种文件：应用主文件：main.js、作为remote时被引用的文件remoteEntry.js和其他的异步加载文件。</p><p>这里通过一个例子简单概括一下其原理：下图是三个项目，在App1中它的remotes是App2和App3，没有exposes，shared是React和ReactDom，它作为host使用了remote的dialog组件和button组件；App2作为host使用了App3的button组件，作为remote导出来dialog组件，在App1中运行时如果需要使用React则会优先把App1中的React导入，这就复用了公共库；App3向外导出了dialog组件，只作为其他项目的remote。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252247350.png"></p><p>这个新特性的提出促进了更多工具的发展，EMP就是以此为基础构建出的一个跨应用共享资源的框架，这个框架优化协作，加速开发的同时还可以保持UI的一致性。</p><h2 id="7-选型"><a href="#7-选型" class="headerlink" title="7.      选型"></a>7.      选型</h2><p>（1）考虑系统需要兼容 ie 浏览器场景：<code>wujie &gt; qianku</code></p><p>（2）接入便捷度考虑：<code>wujie &gt; micro-app &gt; qiankun</code></p><p>（3）框架稳定性 (框架成熟度)：<code>qiankun &gt; micro-app &gt; wujie</code></p><br /><h2 id="微前端意义"><a href="#微前端意义" class="headerlink" title="微前端意义"></a>微前端意义</h2><h2 id="1-化整为零"><a href="#1-化整为零" class="headerlink" title="1.      化整为零"></a>1.      化整为零</h2><p>当下前端领域，单页面应已经成为流行的的项目形态之一，但是随着时间和技术的发展，原本单一的应用具备的功能愈加丰富起来，功能的丰富意味着越来越难以维护，从而变成一个巨石项目。以至于之后改一处而动全身，带来的发版成本也更高。微前端的意义就是将巨石应用进行拆分，化整为零把功能随之解耦，每个部分可以单独进行维护和部署，从而提升团队开发和维护效率。</p><h2 id="2-化零为整"><a href="#2-化零为整" class="headerlink" title="2.      化零为整"></a>2.      化零为整</h2><p>在业务中或多或少会存在一些历史项目，这些项目也会使用不同的框架进行构建，在日常运营中，这些系统已经有固有的用户，但是诸多的应用对于用户来说也是一种成本，为了让旧项目焕发新生，这要求我们在不能抛弃原有项目的同时开发新的功能，把诸多较为零散的入口统一整合起来，从而提高系统的使用率，而微前端就是目前实现这一需求的较好方法。</p><p>综上，微前端不一定是未来发展趋势的收束点，但是它在未来一定会发挥重要作用。</p><br /><h2 id="你真的需要微前端吗？"><a href="#你真的需要微前端吗？" class="headerlink" title="你真的需要微前端吗？"></a>你真的需要微前端吗？</h2><h2 id="1-微前端是「康威定律」在前端架构上的映射"><a href="#1-微前端是「康威定律」在前端架构上的映射" class="headerlink" title="1. 微前端是「康威定律」在前端架构上的映射"></a>1. 微前端是「康威定律」在前端架构上的映射</h2><p>设计系统的架构受制于产生这些设计的组织的沟通结构。 — M.Conway</p><p>康威定律几乎就是微前端（准确来说是微服务架构）的理论基础了。它指出了组织架构越庞大，其系统间沟通成本越高的问题。而解决这一问题的有效手段就是，将大的系统拆分成一个个微小的，可以独立自治的子系统。一旦系统的依赖限制在了内部，功能上更加内聚，对外部的依赖变少，那么就能显著的减少跨系统之间的沟通成本了。</p><p>简单来说，康威定律的指导思想就是：既然沟通是大问题，那么就不要沟通就好了。</p><p>所以本质上，微前端(微服务架构)关注的是如何解决组织和团队间协作带来的工程问题，而不是单纯的某个技术问题。</p><p>qiankun的作者当初面对的问题是有一些系统都是 4年+、代码 20W行+ 的长尾应用，而产品还在持续的集成迭代，既没精力去给他们做技术栈升级，也没动力(兴趣)去跟一个个前应用 owner 沟通了解一些技术细节。这可间接的引出第二个观点。</p><h2 id="2-微前端的假设是，所有大型系统都逃不过熵增定律"><a href="#2-微前端的假设是，所有大型系统都逃不过熵增定律" class="headerlink" title="2. 微前端的假设是，所有大型系统都逃不过熵增定律"></a>2. 微前端的假设是，所有大型系统都逃不过熵增定律</h2><p>这个假设指的是，所有大型系统都将从有序变为无序，他们背后的 codebase 的归宿都将是「屎山」。</p><p>如果不是，那一定是因为这个系统使用的技术栈更新的不够快，参与系统开发的工程师不够多，产品迭代的时间不够长。</p><p>在潜意识里，微前端的采纳者就不相信一个系统会永远健康的迭代下去。因为熵增永远是自然且轻松的，而对抗熵增，则必须有足够的外力介入、足够的成本投入才行。</p><p>这也是为什么，qiankun 的很大一批用户，都是因为要在一批长尾应用上迭代新功能，最后实在搞不动，才会尝试用微前端的方案来解决了。</p><p>基于此，微前端很多时候是「悲观主义工程师」在工程上的妥协，是一种防御性，有时候甚至是「掩耳盗铃」式的架构策略。</p><p>当然在理想状态下，对于一个有追求的工程师而言，所有的技术问题都应该是被正面修复、正确治理的，而不是起手就来一个 workaround。但同时所有的软件工程原则也都会告诉我们，不遗余力、不计成本的去优化、解决一个技术问题是不可取的，尤其是在这个问题的投入产出比不高的情况下。</p><p>微前端倡导的不是消极的、投降主义的去回避系统中的历史遗留问题，而是告诉我们，很多时候我们可以通过分而治之的手段，让「上帝的归上帝，凯撒的归凯撒」。</p><h2 id="3-满足以下几点，你可能就不需要微前端"><a href="#3-满足以下几点，你可能就不需要微前端" class="headerlink" title="3.       满足以下几点，你可能就不需要微前端"></a>3.       满足以下几点，你可能就不需要微前端</h2><p>基于以上两个观点，我们可以概括出，存在以下场景时，你可能就不需要微前端：</p><p>（1）你/你的团队 具备系统内所有架构组件的话语权</p><p>（2）简单来说就是，系统里的所有组件都是由一个小的团队开发的。你/你的团队 有足够动力去治理、改造这个系统中的所有组件</p><p>（3）直接改造存量系统的收益大于新老系统混杂带来的问题。系统及组织架构上，各部件之间本身就是强耦合、自洽、不可分离的</p><p>（4）系统本身就是一个最小单元的「架构量子」，拆分的成本高于治理的成本。极高的产品体验要求，对任何产品交互上的不一致零容忍。不允许交互上不一致的情况出现，这基本上从产品上否决了渐进式升级的技术策略</p><h2 id="4-满足以下几点，你才确实可能需要微前端"><a href="#4-满足以下几点，你才确实可能需要微前端" class="headerlink" title="4.       满足以下几点，你才确实可能需要微前端"></a>4.       满足以下几点，你才确实可能需要微前端</h2><p>（1）系统本身是需要集成和被集成的 一般有两种情况：</p><ul><li><p>a. 旧的系统不能下，新的需求还在来。</p></li><li><p>b. 没有一家商业公司会同意工程师以单纯的技术升级的理由，直接下线一个有着一定用户的存量系统的。而你大概又不能简单通过 iframe 这种「靠谱的」手段完成新功能的接入，因为产品说需要「弹个框弹到中间」你的系统需要有一套支持动态插拔的机制。</p></li></ul><p>（2）这个机制可以是一套精心设计的插件体系，但一旦出现接入应用或被接入应用年代够久远、改造成本过高的场景，可能后面还是会过渡到各种微前端的玩法。系统中的部件具备足够清晰的服务边界</p><p>通过微前端手段划分服务边界，将复杂度隔离在不同的系统单元中，从而避免因熵增速度不一致带来的代码腐化的传染，以及研发节奏差异带来的工程协同上的问题。还是那个老生常谈的理念，没有银弹，架构本身就是各种 trade–off。</p><p>大部分时候，一个「流行」的东西，你都无法阻止不需要它的人去使用它。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/a38cd327/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>微前端（qiankun）使用手册</title>
      <link>https://blog.helloallen.cn/554fb506/</link>
      <guid>https://blog.helloallen.cn/554fb506/</guid>
      <pubDate>Mon, 25 Dec 2023 23:40:11 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>本文中主应用采用<code>vue2</code>构建，微应用采用<code>vue2</code>、<code>vue3</code>、<code>react</code>构建。其中主应用和微应用都采用<code>webpack</code>打包，并且主应用路由模式选择了<code>History</code>（该模式需要服务端支持），微应用路由模式采用<code>History</code>、<code>Hash</code>。</p><p>如果在项目采用<code>vite</code>构建的前提下需要使用<code>qiankun</code>，请查看文档<a href="https://helloallenw.github.io/2023/12/25/%E5%BE%AE%E5%89%8D%E7%AB%AFqiankun%E6%8E%A5%E5%85%A5Vite%E6%9E%84%E5%BB%BA%E7%9A%84%E5%AD%90%E5%BA%94%E7%94%A8/">《微前端qiankun接入Vite构建的子应用》</a>。</p><p>如果主应用路由模式需要使用<code>hash</code>，请查看文档<a href="https://helloallenw.github.io/2023/12/25/%E5%BE%AE%E5%89%8D%E7%AB%AF%EF%BC%88qiankun%EF%BC%89Hash%E8%B7%AF%E7%94%B1%E5%AE%9E%E8%B7%B5/">《微前端（qiankun）Hash路由实践》</a>。</p><br /><h2 id="创建主应用"><a href="#创建主应用" class="headerlink" title="创建主应用"></a>创建主应用</h2><h2 id="1-安装qiankun"><a href="#1-安装qiankun" class="headerlink" title="1.安装qiankun"></a>1.安装<code>qiankun</code></h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">`yarn add qiankun` 或者 `npm i qiankun -S`</span><br></pre></td></tr></table></figure><h2 id="2-注册微应用"><a href="#2-注册微应用" class="headerlink" title="2. 注册微应用"></a>2. 注册微应用</h2><p>在入口文件<code>main.js</code>中注册所有微应用并启动<code>qiankun</code>。</p><figure class="highlight plaintext"><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><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line">import &#123; registerMicroApps, start, addGlobalUncaughtErrorHandler, initGlobalState &#125; from &#x27;qiankun&#x27;</span><br><span class="line"></span><br><span class="line">// 1. 定义所有微应用</span><br><span class="line">const apps = [</span><br><span class="line">  &#123;</span><br><span class="line">    // 必须与子应用注册名字相同</span><br><span class="line">    name: &#x27;micro-app-vue2&#x27;,</span><br><span class="line">    // 入口路径，开发时为子应用所启本地服务，上线时为子应用线上路径</span><br><span class="line">    entry: &#x27;//localhost:3003&#x27;,</span><br><span class="line">    // 子应用挂载的节点</span><br><span class="line">    container: &#x27;#micro-app-vue2&#x27;,</span><br><span class="line">    // 当访问路由为 /micro-app-vue2 时加载子应用</span><br><span class="line">    activeRule: &#x27;/micro-app-vue2&#x27;,</span><br><span class="line">    // 主应用向子应用传递参数</span><br><span class="line">    props: &#123;</span><br><span class="line">        msg: &quot;我是来自主应用的值&quot;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    name: &#x27;micro-app-vue3&#x27;,</span><br><span class="line">    entry: &#x27;//localhost:3001&#x27;,</span><br><span class="line">    container: &#x27;#micro-app-vue3&#x27;,</span><br><span class="line">    activeRule: &#x27;/micro-app-vue3&#x27;</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    name: &#x27;micro-app-react&#x27;,</span><br><span class="line">    entry: &#x27;//localhost:4001&#x27;,</span><br><span class="line">    container: &#x27;#micro-app-react&#x27;,</span><br><span class="line">    activeRule: &#x27;/micro-app-react&#x27;</span><br><span class="line">  &#125;</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">// 2. 微应用生命周期</span><br><span class="line">// qiankun暴露了五个生命周期钩子：beforeLoad、beforeMount、afterMount 、beforeUnmount和afterUnmount，这五个钩子可以在主应用中注册子应用时使用。</span><br><span class="line">const microAppLifCycles = &#123;</span><br><span class="line">  beforeLoad: [ // 全局的微应用生命周期钩子，子应用加载前</span><br><span class="line">    app =&gt; &#123;</span><br><span class="line">      console.log(&#x27;子应用加载-beforeLoad&#x27;, app)</span><br><span class="line">      return Promise.resolve()</span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  beforeMount: [ // 全局的微应用生命周期钩子，子应用挂载前</span><br><span class="line">    app =&gt; &#123;</span><br><span class="line">      console.log(&#x27;2-beforeMount&#x27;, app)</span><br><span class="line">      return Promise.resolve()</span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  afterMount: [ // 全局的微应用生命周期钩子，子应用挂载后</span><br><span class="line">    app =&gt; &#123;</span><br><span class="line">      console.log(&#x27;3-afterMount&#x27;, app)</span><br><span class="line">      return Promise.resolve()</span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  beforeUnmount: [</span><br><span class="line">    app =&gt; &#123;</span><br><span class="line">      console.log(&#x27;4-beforeUnmount&#x27;, app)</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 3. 注册微应用的基础配置信息（第二个参数可选）</span><br><span class="line">registerMicroApps(apps, microAppLifCycles)</span><br><span class="line"></span><br><span class="line">// 4. 添加全局的未捕获异常处理器</span><br><span class="line">addGlobalUncaughtErrorHandler((event) =&gt; &#123;</span><br><span class="line">  const &#123; message: msg &#125; = event</span><br><span class="line">  if (msg &amp;&amp; msg.includes(&#x27;died in status LOADING_SOURCE_CODE&#x27;)) &#123;</span><br><span class="line">    console.error(&#x27;微应用加载失败，请检查应用是否可运行&#x27;, event)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">// 5. 启动微应用</span><br><span class="line">start(&#123;</span><br><span class="line">  prefetch: true, // 是否开启预加载</span><br><span class="line">  sandbox: &#123;</span><br><span class="line">    experimentalStyleIsolation: true // 实验性的样式隔离</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>关于预加载微应用<code>prefetch</code>的属性说明：</p><p>（1）配置为 true 则会在第一个微应用 mount 完成后开始预加载其他微应用的静态资源</p><p>（2）配置为 all 则主应用 start 后即开始预加载所有微应用静态资源</p><p>（3）配置为 string[] 则会在第一个微应用 mounted 后开始加载数组内的微应用资源</p><p>（4）配置为 function 则可完全自定义应用的资源加载时机 (首屏应用及次屏应用)</p><p>当微应用信息注册完之后，一旦浏览器的 url 发生变化，便会自动触发 qiankun 的匹配逻辑，所有 activeRule 规则匹配上的微应用就会被挂载到指定的 container 中，同时依次调用微应用暴露出的生命周期钩子。</p><h2 id="3-创建微应用SFC"><a href="#3-创建微应用SFC" class="headerlink" title="3.创建微应用SFC"></a>3.创建微应用SFC</h2><p>每个微应用使用一个对应的单文件组件进行挂载，并在mounted中进行判断如果未开启qiankun则进行开启。</p><p>该处以<code>microAppVue2</code>组件为例，其它组件只需要修改id和组件name。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">   &lt;!-- 这个id需要和注册微应用中的container的值对应 --&gt;</span><br><span class="line">  &lt;div id=&quot;micro-app-vue2&quot;&gt;&lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import &#123; start &#125; from &#x27;qiankun&#x27;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &#x27;microAppVue2&#x27;,</span><br><span class="line">  components: &#123;&#125;,</span><br><span class="line">  mounted () &#123;</span><br><span class="line">    if (!window.qiankunStarted) &#123;</span><br><span class="line">      window.qiankunStarted = true</span><br><span class="line">      start(&#123;</span><br><span class="line">        prefetch: true, // 是否开启预加载</span><br><span class="line">        sandbox: &#123;</span><br><span class="line">          experimentalStyleIsolation: true // 实验性的样式隔离</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="4-路由配置"><a href="#4-路由配置" class="headerlink" title="4.路由配置"></a>4.路由配置</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import Vue from &#x27;vue&#x27;</span><br><span class="line">import VueRouter from &#x27;vue-router&#x27;</span><br><span class="line">Vue.use(VueRouter)</span><br><span class="line"></span><br><span class="line">const routes = [</span><br><span class="line">  &#123;</span><br><span class="line">    // 这个path需要和注册微应用中的activeRule的值对应</span><br><span class="line">    path: &#x27;/micro-app-vue2&#x27;,</span><br><span class="line">    component: () =&gt; import(&#x27;@/views/microAppVue2/index.vue&#x27;)</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    path: &#x27;/micro-app-vue3&#x27;,</span><br><span class="line">    component: () =&gt; import(&#x27;@/views/microAppVue3/index.vue&#x27;)</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    path: &#x27;/micro-app-react&#x27;,</span><br><span class="line">    component: () =&gt; import(&#x27;@/views/microAppReact/index.vue&#x27;)</span><br><span class="line">  &#125;</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">const router = new VueRouter(&#123;</span><br><span class="line">  // 选择history模式时，需要设置base，这样在访问路由时会自动带上项目的基路径</span><br><span class="line">  mode: &#x27;history&#x27;,</span><br><span class="line">  base: process.env.BASE_URL,</span><br><span class="line">  routes</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">export default router</span><br></pre></td></tr></table></figure><h2 id="5-主应用代理微应用的接口地址"><a href="#5-主应用代理微应用的接口地址" class="headerlink" title="5.主应用代理微应用的接口地址"></a>5.主应用代理微应用的接口地址</h2><p>在使用 qiankun 微前端框架时，主应用可以通过配置代理来转发子应用的接口请求。这样可以解决跨域问题和统一管理接口访问。</p><p>首先，在主应用的配置文件中（例如 <code>webpack.config.js</code>）添加以下代码：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const &#123; createProxyMiddleware &#125; = require(&#x27;http-proxy-middleware&#x27;);</span><br><span class="line"></span><br><span class="line">module.exports = &#123;</span><br><span class="line">  // ...其他配置</span><br><span class="line"></span><br><span class="line">  devServer: &#123;</span><br><span class="line">    // ...其他 devServer 配置项</span><br><span class="line"></span><br><span class="line">    // 添加代理配置</span><br><span class="line">    proxy: &#123;</span><br><span class="line">      &#x27;/api&#x27;: &#123;</span><br><span class="line">        target: &#x27;http://子应用的接口地址&#x27;,</span><br><span class="line">        changeOrigin: true,</span><br><span class="line">        pathRewrite: &#123;</span><br><span class="line">          &#x27;^/api&#x27;: &#x27;&#x27;, // 如果子应用接口有基础路径，需要进行重写</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>上述代码中，将 <code>/api</code> 路径下的请求转发到了子应用的接口地址，并进行了域名跨域处理。你可以根据实际情况修改目标地址和路径重写规则。</p><p>然后，在微应用中调用接口时，使用相对于主应用的 <code>/api</code> 路径作为前缀，例如：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">fetch(&#x27;/api/users&#x27;)</span><br><span class="line">  .then(response =&gt; response.json())</span><br><span class="line">  .then(data =&gt; console.log(data))</span><br><span class="line">  .catch(error =&gt; console.error(error));</span><br></pre></td></tr></table></figure><p>这样就能将请求发送给子应用的接口地址，并成功获取响应数据。</p><p>注意：以上示例是基于 <code>webpack-dev-server</code> 进行配置的，在生产环境部署时需要根据实际情况配置代理服务器。 </p><br /><h2 id="创建微应用"><a href="#创建微应用" class="headerlink" title="创建微应用"></a>创建微应用</h2><p><code>vue2</code>、<code>vue3</code>和<code>react</code>的配置由于框架不同而在代码上有些微区别（比如<code>vue2</code>创建实例是<code>new vue</code>，<code>vue3</code>是<code>createApp</code>），但整体<code>qiankun</code>的配置步骤和配置内容相同。此处不做区分，以下仅以<code>vue2</code>为例：</p><h2 id="1-修改配置文件"><a href="#1-修改配置文件" class="headerlink" title="1.修改配置文件"></a>1.修改配置文件</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// vue.config.js</span><br><span class="line"></span><br><span class="line">// 1. package.json中name的值必须和主应用中注册微应用的name的值对应</span><br><span class="line">const packageName = require(&#x27;./package.json&#x27;).name;</span><br><span class="line">module.exports = &#123;</span><br><span class="line">    configureWebpack: &#123;</span><br><span class="line">        // 2. 打包方式改造</span><br><span class="line">        output: &#123;</span><br><span class="line">            library: packageName,</span><br><span class="line">            // 这里设置为umd意思是在 AMD 或 CommonJS 的 require 之后可访问。</span><br><span class="line">            libraryTarget: &quot;umd&quot;,</span><br><span class="line">            // webpack用来异步加载chunk的JSONP 函数。</span><br><span class="line">            jsonpFunction: `webpackJsonp_$&#123;packageName&#125;`,</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">    devServer: &#123;</span><br><span class="line">        port: &quot;3003&quot;,</span><br><span class="line">        disableHostCheck: true, // 关闭主机检查，使微应用可以被 fetch</span><br><span class="line">        headers: &#123;</span><br><span class="line">            // 3. 因为qiankun内部请求都是fetch来请求资源，所以子应用必须允许跨域    &quot;Access-Control-Allow-Origin&quot;: &quot;*&quot;,</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>为什么 <code>qiankun</code> 要求子应用打包为 <code>umd</code> 库格式呢？</p><p>主要是为了主应用能够拿到子应用在 入口文件 导出的 生命钩子函数，这也是主应用和子应用之间通信的关键。</p><p><code>umd</code>全称是<code>UniversalModuleDefinition</code>，是一种通用模块定义格式，通常用在前端模块化开发中。</p><p>由于不同的模块化规范定义不同，为了让各种规范的模块可以通用，在不同的环境下都可以正常运行，就出现了umd这个通用格式。</p><p>umd 格式是一种既可以在浏览器环境下使用，也可以在 node 环境下使用的格式。它将 <code>CommonJS</code>、<code>AMD</code>以及普通的全局定义模块三种模块模式进行了整合。</p><h2 id="2-修改publicPath"><a href="#2-修改publicPath" class="headerlink" title="2.修改publicPath"></a>2.修改publicPath</h2><p>src目录下新建<code>public-path.js</code>，用于处理打包后静态资源的路径问题。内容如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">if(window.__POWERED_BY_QIANKUN__) &#123;</span><br><span class="line">  // eslint-disable-next-line no-undef</span><br><span class="line">  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-路由配置"><a href="#3-路由配置" class="headerlink" title="3.路由配置"></a>3.路由配置</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import Vue from &#x27;vue&#x27;</span><br><span class="line">import Router from &#x27;vue-router&#x27;</span><br><span class="line">import HelloWorld from &#x27;@/components/HelloWorld&#x27;</span><br><span class="line"> </span><br><span class="line">Vue.use(Router)</span><br><span class="line"> </span><br><span class="line">export default new Router(&#123;</span><br><span class="line">  // 1. 设置history模式</span><br><span class="line">  mode: &#x27;history&#x27;,</span><br><span class="line">  // 2. 设置base，值和主应用中的activeRule保持一致</span><br><span class="line">  base: window.__POWERED_BY_QIANKUN__ ? &quot;/micro-app-vue2&quot; : &quot;/&quot;,</span><br><span class="line">  routes</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>当使用<code>vue-router v4.x</code>时，是通过<code>createRouter</code>的方式实例化<code>router</code>，设置<code>histroy</code>和<code>base</code>通过如下方式：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 1. Hash路由设置方法，hash不需要设置base</span><br><span class="line">history: createWebHashHistory(), </span><br><span class="line"></span><br><span class="line">// 2. 设置 History 路由时必须添加base</span><br><span class="line">// history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? &#x27;/micro-app-vue3-vite&#x27; : &#x27;/&#x27;),</span><br></pre></td></tr></table></figure><p>当微应用为<code>History</code>时，主应用的<code>router/index.js</code>中必须多添加一项路由配置：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// ...</span><br><span class="line">&#123;</span><br><span class="line">    hidden: true,</span><br><span class="line">    name: &#x27;microAppVue2&#x27;,</span><br><span class="line">    // 匹配微应用的路由</span><br><span class="line">    path: &#x27;/micro-app-vue2/*&#x27;,</span><br><span class="line">    component: () =&gt; import(&#x27;@/views/microAppVue2/index.vue&#x27;)</span><br><span class="line">&#125;,</span><br><span class="line">// ...</span><br></pre></td></tr></table></figure><h2 id="4-入口文件修改"><a href="#4-入口文件修改" class="headerlink" title="4.入口文件修改"></a>4.入口文件修改</h2><p>修改入口文件<code>main.js</code>，修改内容如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 1. 顶部引入public-path</span><br><span class="line">import &#x27;./public-path&#x27;</span><br><span class="line">import Vue from &#x27;vue&#x27;</span><br><span class="line">import App from &#x27;./App&#x27;</span><br><span class="line">import router from &#x27;./router&#x27;</span><br><span class="line"></span><br><span class="line">Vue.config.productionTip = false</span><br><span class="line"></span><br><span class="line">// 2. 定义一个Vue实例</span><br><span class="line">let instance = null</span><br><span class="line"></span><br><span class="line">// 3. 渲染方法</span><br><span class="line">function render(props = &#123;&#125;) &#123;</span><br><span class="line">  const &#123; container &#125; = props</span><br><span class="line">  instance = new Vue(&#123;</span><br><span class="line">    router,</span><br><span class="line">    render: (h) =&gt; h(App)</span><br><span class="line">  &#125;).$mount(container ? container.querySelector(&#x27;#app&#x27;) : &#x27;#app&#x27;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 4. 判断是否在qiankun环境下，非qiankun环境下独立运行</span><br><span class="line">if (!window.__POWERED_BY_QIANKUN__) &#123;</span><br><span class="line">  render()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 5. 暴露qiankun生命周期钩子</span><br><span class="line">export async function bootstrap() &#123;&#125;</span><br><span class="line">export async function mount(props) &#123;</span><br><span class="line">  render(props);</span><br><span class="line">&#125;</span><br><span class="line">export async function unmount() &#123;</span><br><span class="line">  instance.$destroy();</span><br><span class="line">  instance.$el.innerHTML = &#x27;&#x27;;</span><br><span class="line">  instance = null;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>项目在迁移成子应用时，需要在入口文件配合<code>qiankun</code>来做一些改动，而这些改动有可能影响子应用的独立运行。为了解决子应用也能独立运行的问题，<code>qiankun</code>注入了一个变量：<code>window.__POWERED_BY_QIANKUN__</code>，这样就可以判断当前应用是否在独立运行。</p><p>但是变量需要在运行时动态的注入，那么该变量设置的位置就需要考虑清楚，<code>qiankun</code>选择在<code>single-spa</code>提供的生命周期前进行变量的注入，在<code>beforeLoad</code>和<code>beforeMount</code>中把变量置为<code>true</code>，在<code>beforeUnmount</code>中把变量置为<code>false</code>。</p><p>和<code>single-spa</code>一样，<code>qiankun</code>子应用的接入必须暴露三个生命周期：</p><p>（1）Bootstrap：只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。</p><p>（2）Mount：应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法。</p><p>（3）Unmount：应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例。</p><br /><h2 id="主应用和微应用通信"><a href="#主应用和微应用通信" class="headerlink" title="主应用和微应用通信"></a>主应用和微应用通信</h2><h2 id="1-主应用中注册全局状态"><a href="#1-主应用中注册全局状态" class="headerlink" title="1.主应用中注册全局状态"></a>1.主应用中注册全局状态</h2><p>在入口文件<code>main.js</code>中定义并监听全局状态</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; initGlobalState &#125; from &#x27;qiankun&#x27;</span><br><span class="line"></span><br><span class="line">// 定义全局状态，并返回通信方法，建议在主应用使用，微应用通过 props 获取通信方法</span><br><span class="line">const &#123; onGlobalStateChange, setGlobalState &#125; = initGlobalState(&#123;</span><br><span class="line">  user: &#x27;qiankun&#x27;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">// 在当前应用监听全局状态，有变更触发 callback</span><br><span class="line">onGlobalStateChange((value, prev) =&gt; console.log(&#x27;[onGlobalStateChange - main]:&#x27;, value + prev))</span><br><span class="line"></span><br><span class="line">// 按一级属性设置全局状态,微应用中只能修改已存在的一级属性</span><br><span class="line">setGlobalState(&#123;</span><br><span class="line">  ignore: &#x27;master&#x27;,</span><br><span class="line">  user: &#123;</span><br><span class="line">    name: &#x27;master&#x27;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="2-微应用中监听并修改"><a href="#2-微应用中监听并修改" class="headerlink" title="2.微应用中监听并修改"></a>2.微应用中监听并修改</h2><p>在入口文件<code>main.js</code>中添加如下配置：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 微应用通过 props 获取通信方法</span><br><span class="line">function storeTest(props) &#123;</span><br><span class="line">  props.onGlobalStateChange &amp;&amp;</span><br><span class="line">    props.onGlobalStateChange(</span><br><span class="line">      (value, prev) =&gt; console.log(`[onGlobalStateChange - $&#123;props.name&#125;]:`, value, prev),</span><br><span class="line">      true,</span><br><span class="line">    );</span><br><span class="line">  props.setGlobalState &amp;&amp;</span><br><span class="line">    props.setGlobalState(&#123;</span><br><span class="line">      ignore: props.name,</span><br><span class="line">      user: &#123;</span><br><span class="line">        name: props.name,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export async function mount(props) &#123;</span><br><span class="line">  storeTest(props);</span><br><span class="line">  // 挂载到子应用，方便使用</span><br><span class="line">  instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;</span><br><span class="line">  instance.config.globalProperties.$setGlobalState = props.setGlobalState;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>以上通信过程如下：</p><p>（1）主应用里面先<code>initGlobalState</code></p><p>（2）主应用监听<code>onGlobalStateChange</code></p><p>（3）主应用去修改<code>setGlobalState</code></p><p> &emsp;&emsp;（3.1）主应用监听到并执行回调</p><p>​    &emsp;&emsp;（3.2）子应用监听到并执行回调</p><p>（4）子应用监听<code>onGlobalStateChange</code></p><p>（5）子应用去修改<code>setGlobalState</code></p><p>​    &emsp;&emsp;（5.1）主应用监听到并执行回调</p><p>​    &emsp;&emsp;（5.2）子应用监听到并执行回调</p><br /><h2 id="qiankun-功能拓展"><a href="#qiankun-功能拓展" class="headerlink" title="qiankun 功能拓展"></a>qiankun 功能拓展</h2><h2 id="1-如何封装主应用和微应用中的共同的组件"><a href="#1-如何封装主应用和微应用中的共同的组件" class="headerlink" title="1.如何封装主应用和微应用中的共同的组件"></a>1.如何封装主应用和微应用中的共同的组件</h2><p>在微前端架构中，主应用和子应用可能会共享一些组件，为了实现组件的共享和封装，可以采用以下方法：</p><p>（1）封装为独立的 npm 包：将共享的组件封装为独立的 npm 包，并发布到私有或公共的 npm 仓库中。主应用和子应用都可以通过 npm 安装该组件，并在需要的地方引入和使用。</p><p>（2）Git 仓库依赖：将共享组件放置在一个独立的 Git 仓库中，并通过 Git 仓库的依赖关系来引入组件。主应用和子应用可以通过 Git 仓库的 URL 或路径来引入共享组件。</p><p>（3）Git Submodule：如果主应用和子应用都在同一个 Git 仓库下，可以使用 <code>Git Submodule</code> 的方式来引入共享组件。将共享组件作为子模块添加到主应用和子应用的仓库中。</p><p>（4）本地引用：如果主应用和子应用处于同一个代码仓库中，可以直接通过相对路径引入共享组件。将共享组件放置在一个独立的目录下，并通过相对路径引用。</p><p>（5）将公共依赖打包为umd格式，并在qiankun的global对象上注册，使得其他子应用可以通过global对象来访问公共依赖。例如：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 1. 在主应用中注册公共依赖</span><br><span class="line">import React from &#x27;react&#x27;;</span><br><span class="line">import ReactDOM from &#x27;react-dom&#x27;;</span><br><span class="line">import MyComponent from &#x27;my-component&#x27;;</span><br><span class="line"></span><br><span class="line">window.MyComponent = MyComponent;</span><br><span class="line"></span><br><span class="line">// 2. 在子应用中使用公共依赖</span><br><span class="line">import React from &#x27;react&#x27;;</span><br><span class="line">import ReactDOM from &#x27;react-dom&#x27;;</span><br><span class="line">import &#123; useEffect &#125; from &#x27;react&#x27;;</span><br><span class="line"></span><br><span class="line">const &#123; MyComponent &#125; = window;</span><br></pre></td></tr></table></figure><p>无论选择哪种方式，关键是要保持共享组件的独立性和可维护性。确保共享组件的代码和样式与具体的主应用和子应用解耦，避免出现冲突和依赖混乱的情况。同时，建议对共享组件进行版本管理，以便在更新和维护时能够更好地控制和追踪变更。</p><p>在微前端架构中，可以通过合适的方式引入共享组件，使主应用和子应用可以共享和复用组件，提高开发效率和代码质量。</p><h2 id="2-子应用调用其他子应用组件"><a href="#2-子应用调用其他子应用组件" class="headerlink" title="2.子应用调用其他子应用组件"></a>2.子应用调用其他子应用组件</h2><h3 id="（1）vue子应用调用React子应用中的组件"><a href="#（1）vue子应用调用React子应用中的组件" class="headerlink" title="（1）vue子应用调用React子应用中的组件"></a>（1）vue子应用调用React子应用中的组件</h3><p>可以先在主应用中通过 <code>registerMicroApps</code> 方法注册好所有的子应用，并在主应用中管理子应用之间的通信。然后，可以在需要使用其他子应用组件的子应用中通过 <code>loadMicroApp</code> 方法异步加载对应的子应用并获取到对应子应用的实例，从而使用其提供的组件。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; loadMicroApp &#125; from &#x27;qiankun&#x27;;</span><br><span class="line"></span><br><span class="line">const loadReactApp = () =&gt; loadMicroApp(&#123;</span><br><span class="line">    name: &#x27;reactApp&#x27;,</span><br><span class="line">    entry: &#x27;//localhost:8082&#x27;,</span><br><span class="line">    container: &#x27;#react&#x27;,</span><br><span class="line">    activeRule: &#x27;/react&#x27;,</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">// 在需要使用 ReactApp 中的组件的 VueApp 组件中异步加载 ReactApp，并使用其提供的组件</span><br><span class="line">const VueApp = &#123;</span><br><span class="line">  template: `</span><br><span class="line">    &lt;div&gt;</span><br><span class="line">      &lt;h1&gt;VueApp&lt;/h1&gt;</span><br><span class="line">      &lt;react-component /&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  `,</span><br><span class="line">  mounted() &#123;</span><br><span class="line">    // 异步加载ReactApp并获取其实例，然后通过getComponent方法获取到了ReactApp中提供的ReactComponent组件，并将其转换为Vue组件供VueApp使用</span><br><span class="line">    loadReactApp().then(app =&gt; &#123;</span><br><span class="line">      const ReactComponent = app.getComponent(&#x27;ReactComponent&#x27;);</span><br><span class="line">      Vue.component(&#x27;react-component&#x27;, &#123;</span><br><span class="line">        template: `&lt;div&gt;&lt;ReactComponent /&gt;&lt;/div&gt;`,</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="（2）React子应用中调用Vue子应用的组件"><a href="#（2）React子应用中调用Vue子应用的组件" class="headerlink" title="（2）React子应用中调用Vue子应用的组件"></a>（2）React子应用中调用Vue子应用的组件</h3><figure class="highlight plaintext"><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">import &#123; loadMicroApp, getGlobalState &#125; from &#x27;qiankun&#x27;;</span><br><span class="line"></span><br><span class="line">function App() &#123;</span><br><span class="line">  const [vueComponent, setVueComponent] = useState(null);</span><br><span class="line"></span><br><span class="line">  useEffect(() =&gt; &#123;</span><br><span class="line">    // React子应用中，加载Vue子应用并获取其组件</span><br><span class="line">    const vueApp = loadMicroApp(&#123;</span><br><span class="line">      name: &#x27;vue3&#x27;,</span><br><span class="line">      entry: &#x27;//localhost:8081&#x27;,</span><br><span class="line">      container: &#x27;#vue3&#x27;,</span><br><span class="line">      activeRule: &#x27;/vue3&#x27;,</span><br><span class="line">      props: &#123; name: &#x27;vue-app&#x27; &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    vueApp.onGlobalStateChange((state, prev) =&gt; &#123;</span><br><span class="line">      console.log(&#x27;[React] Vue global state changed: &#x27;, state);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    vueApp</span><br><span class="line">      .loadPromise.then(() =&gt; &#123;</span><br><span class="line">        const vueInstance = vueApp.bootstrap();</span><br><span class="line">        setVueComponent(vueInstance.$children[0]);</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">    return () =&gt; vueApp.unmount();</span><br><span class="line">  &#125;, []);</span><br><span class="line"></span><br><span class="line">  return (</span><br><span class="line">    &lt;div&gt;</span><br><span class="line">      &lt;h1&gt;React App&lt;/h1&gt;</span><br><span class="line">      &lt;hr /&gt;</span><br><span class="line">      &lt;h2&gt;Vue App Component:&lt;/h2&gt;</span><br><span class="line">      &#123;vueComponent &amp;&amp; (</span><br><span class="line">        &lt;div&gt;</span><br><span class="line">          &lt;p&gt;&#123;vueComponent.message&#125;&lt;/p&gt;</span><br><span class="line">          &lt;button onClick=&#123;() =&gt; vueComponent.handleClick()&#125;&gt;Click me!&lt;/button&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      )&#125;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export default App;</span><br></pre></td></tr></table></figure><h3 id="（3）传递参数"><a href="#（3）传递参数" class="headerlink" title="（3）传递参数"></a>（3）传递参数</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import React from &#x27;react&#x27;;</span><br><span class="line">import &#123; render, hydrate &#125; from &#x27;react-dom&#x27;;</span><br><span class="line">import &#123; registerMicroApps, start &#125; from &#x27;qiankun&#x27;;</span><br><span class="line">import App from &#x27;./App&#x27;;</span><br><span class="line"></span><br><span class="line">// 注册子应用</span><br><span class="line">registerMicroApps([...]);</span><br><span class="line"></span><br><span class="line">// 启动 qiankun</span><br><span class="line">start();</span><br><span class="line"></span><br><span class="line">// 在 App 组件中调用其他子应用的组件</span><br><span class="line">function App() &#123;</span><br><span class="line">  return (</span><br><span class="line">    &lt;div&gt;</span><br><span class="line">      &#123;/* 调用 Vue 子应用的组件 */&#125;</span><br><span class="line">      &lt;div&gt;</span><br><span class="line">        &#123;/* 在调用时，可以将需要传递的参数放在props对象中，然后作为第二个参数传递给render方法 */&#125;</span><br><span class="line">        &#123;render(&#x27;vue3&#x27;, &#123; name: &#x27;Tom&#x27; &#125;, &#123; container: &#x27;#vue-container&#x27; &#125;)&#125;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  );</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 渲染根组件</span><br><span class="line">hydrate(&lt;App /&gt;, document.getElementById(&#x27;root&#x27;));</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">    &lt;div&gt;</span><br><span class="line">        &lt;h2&gt;Vue Component&lt;/h2&gt;</span><br><span class="line">        &lt;p&gt;Hello, &#123;&#123; name &#125;&#125;!&lt;/p&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">    name: &#x27;VueComponent&#x27;,</span><br><span class="line">    // 直接使用</span><br><span class="line">    props: &#123;</span><br><span class="line">        name: &#123;</span><br><span class="line">            type: String,</span><br><span class="line">            required: true,</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h2 id="3-CSS-沙箱"><a href="#3-CSS-沙箱" class="headerlink" title="3.      CSS 沙箱"></a>3.      CSS 沙箱</h2><p>css隔离主要分为两种，一种是父子之间的隔离，另一种是子子之间的隔离。子应用之间的隔离，qiankun中并没有特别的提出，本质上就是在子应用加载时把其相应的样式加载进来，在卸载时进行移除即可。而父子之间的隔离在qiankun种有两种实现方法。</p><h3 id="（1）strictStyleIsolation-Shadow-DOM"><a href="#（1）strictStyleIsolation-Shadow-DOM" class="headerlink" title="（1）strictStyleIsolation: Shadow DOM"></a>（1）<code>strictStyleIsolation: Shadow DOM</code></h3><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251853360.png"></p><p>第一种是严格样式隔离，核心是<code>Shadow DOM</code>。它可以让一个<code>dom</code>拥有自己的“影子”DOM树，这个DOM树不能在主文档中被任意访问，可以拥有局部样式规则，天然实现了样式隔离，如上图所示，被代理的dom节点称为<code>shadow host</code>，<code>shadow tree</code>中的根节点称为<code>shadow root</code>。</p><p>比如我们常用的<code>&lt;video&gt;</code>标签，一个标签就实现了一个简易的播放器，但其实它是由一些看不到的dom封装而成的，这里就是使用了<code>shadow DOM</code>。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251858049.png"></p><p>现在先来模拟一下父子的样式污染问题，在下面的demo中子应用的样式设置成所有字体颜色为红色，使得父元素和子元素所有的文字都为红色。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;div&gt;</span><br><span class="line">    &lt;h5&gt;父元素&lt;/h5&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line"></span><br><span class="line">&lt;div id=&quot;app1&quot;&gt;</span><br><span class="line">    &lt;style&gt;</span><br><span class="line">    *&#123;</span><br><span class="line">        color:red;</span><br><span class="line">     &#125;</span><br><span class="line">    &lt;/style&gt;</span><br><span class="line">    &lt;h5&gt;子元素&lt;/h5&gt;</span><br><span class="line">    &lt;p class=&quot;title&quot;&gt;一行文字&lt;/p&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure><p>使用严格样式隔离解决一下这个问题：获取到子应用的根节点，然后打开影子模式，把原来的dom结构赋值到代理的影子根节点中，然后清空原来的dom结构。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">function openShadow(domNode) &#123;</span><br><span class="line">    var shadow = domNode.attachShadow(&#123; mode: &quot;open&quot; &#125;);</span><br><span class="line">    shadow.innerHTML = domNode.innerHTML;</span><br><span class="line">    domNode.innerHTML = &quot;&quot;;</span><br><span class="line">&#125;</span><br><span class="line">var bodyNode = document.getElementById(&quot;app1&quot;);</span><br><span class="line">openShadow(bodyNode);</span><br></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251915695.png"></p><h3 id="（2）experimentalStyleIsolation"><a href="#（2）experimentalStyleIsolation" class="headerlink" title="（2）experimentalStyleIsolation"></a>（2）<code>experimentalStyleIsolation</code></h3><p>第二种父子样式隔离是实验性样式隔离 ，即通过运行时修改CSS选择器来实现子应用间的样式隔离。</p><p>下面也是一个模拟污染的demo，可以看到主应用和子应用有重名的选择器，子应用在后面，所以父样式被覆盖，造成了污染。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;head&gt;</span><br><span class="line">    &lt;style&gt;</span><br><span class="line">        p.title &#123;</span><br><span class="line">            color:red;</span><br><span class="line">        &#125;</span><br><span class="line">    &lt;/style&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line"></span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;p class=&quot;title&quot;&gt;父应用&lt;/p&gt;</span><br><span class="line">&lt;div id=&quot;data-qiankun-A&quot;&gt;</span><br><span class="line">    &lt;style&gt;</span><br><span class="line">        p.title &#123;</span><br><span class="line">            color:blue;</span><br><span class="line">        &#125;</span><br><span class="line">    &lt;/style&gt;</span><br><span class="line">    &lt;p class=&quot;title&quot;&gt;子应用&lt;/p&gt;</span><br><span class="line">&lt;/div&gt;</span><br><span class="line">&lt;/body&gt;</span><br></pre></td></tr></table></figure><p>这里首先获取到子应用，然后通过正则匹配其中的所有<code>&lt;style&gt;</code>标签，给每一个标签加上前缀，从而缩小其样式应用的范围。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">function scopeCss(styleNode, prefix) &#123;</span><br><span class="line">  const css = ruleStyle(styleNode.sheet.cssRules[0], prefix);</span><br><span class="line">  styleNode.textContent = css;</span><br><span class="line">&#125;</span><br><span class="line">function ruleStyle(rule, prefix) &#123;</span><br><span class="line">  const rootSelectorRE = /((?:[^\w\-.#]|^)(body|html|:root))/gm;</span><br><span class="line">  let &#123; cssText &#125; = rule;</span><br><span class="line">  // 绑定选择器, a,span,p,div &#123; ... &#125;</span><br><span class="line">  cssText = cssText.replace(/^[\s\S]+&#123;/, (selectors) =&gt;</span><br><span class="line">    selectors.replace(/(^|,\n?)([^,]+)/g, (item, p, s) =&gt; &#123;</span><br><span class="line">      // 绑定 div,body,span &#123; ... &#125;</span><br><span class="line">      if (rootSelectorRE.test(item)) &#123;</span><br><span class="line">        return item.replace(rootSelectorRE, (m) =&gt; &#123;</span><br><span class="line">          // 不要丢失有效字符 如 body,html or *:not(:root)</span><br><span class="line">          const whitePrevChars = [&quot;,&quot;, &quot;(&quot;];</span><br><span class="line">          if (m &amp; amp;&amp; amp; whitePrevChars.includes(m[0])) &#123;</span><br><span class="line">            return `$&#123;m[0]&#125;$&#123;prefix&#125;`;</span><br><span class="line">          &#125;</span><br><span class="line">          // 用前缀替换根选择器</span><br><span class="line">          return prefix;</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">    return `$&#123;p&#125;$&#123;prefix&#125; $&#123;s.replace(/^ */, &quot;&quot;)&#125;`;</span><br><span class="line">    &#125;)</span><br><span class="line">  );</span><br><span class="line">  return cssText;</span><br><span class="line">&#125;</span><br><span class="line">var container = document.getElementById(&quot;data-qiankun-A&quot;);</span><br><span class="line">var styleNode = container.getElementsByTagName(&quot;style&quot;)[0];</span><br><span class="line">scopeCss(styleNode, &quot;#data-qiankun-A&quot;)</span><br></pre></td></tr></table></figure><p>效果如下图所示，可以看到子应用的<code>&lt;style&gt;</code>标签中的选择器都加上了前缀，使父应用的颜色保持原有的红色，子应用的颜色是新设置的蓝色。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251921345.png"></p><h2 id="4-JS-沙箱"><a href="#4-JS-沙箱" class="headerlink" title="4. JS 沙箱"></a>4. JS 沙箱</h2><p>js隔离是另一个在微前端中需要关注的问题，qiankun中有三种js隔离的做法。</p><h3 id="（1）SnapshotSandbox"><a href="#（1）SnapshotSandbox" class="headerlink" title="（1）SnapshotSandbox"></a>（1）<code>SnapshotSandbox</code></h3><p>第一种是快照沙箱，先来看一下具体demo:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">let sandbox = new SnapshotSandbox();</span><br><span class="line">var a = &#x27;主应用A&#x27;;</span><br><span class="line">var c = &#x27;主应用C&#x27;;</span><br><span class="line">console.log(&#x27;主应用原来的Window:&#x27;, a, c);</span><br><span class="line">function beforeMounted() &#123;</span><br><span class="line">  sandbox.active();</span><br><span class="line">  console.log(&quot;加载子应用前&quot;);</span><br><span class="line">&#125;</span><br><span class="line">function beforeUnMounted() &#123;</span><br><span class="line">  sandbox.inactive();</span><br><span class="line">  console.log(&quot;卸载子应用前&quot;);</span><br><span class="line">&#125;</span><br><span class="line">function app1() &#123;</span><br><span class="line">  beforeMounted();</span><br><span class="line">  window.a = &#x27;app1A&#x27;;//修改</span><br><span class="line">  window.c = null;//删除</span><br><span class="line">  window.d = &#x27;app1D&#x27;;//新增</span><br><span class="line">  console.log(&quot;子应用的Window:&quot;, window.a, window.c, window.d);</span><br><span class="line">  beforeUnMounted();</span><br><span class="line">&#125;</span><br><span class="line">app1();</span><br><span class="line">console.log(&#x27;主应用现在的Window:&#x27;, a, c, d);</span><br></pre></td></tr></table></figure><p>主应用中声明两个变量a和c，分别赋值主应用A和主应用C，然后加载子应用之后对全局变量ac进行修改，并且新增d，最后卸载时再打印acd，可以在左图看到主应用的变量被污染了。</p><p>这时候开启沙箱再运行一遍，可以在右图看到主应用被恢复回来了，解决了变量污染的问题。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251923414.png"></p><p>沙箱快照的核心思想如下：在子应用挂在前对当前主应用的全局变量保存，然后恢复之前的子应用环境，在子应用运行期间则正常get和set，在卸载时保存当前变量恢复主应用变量，整个过程类似于中断和中断恢复。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251923066.png"></p><p>具体代码可参考这个demo，但这里也有一个比较明显的缺点就是每次切换时需要去遍历window，这种做法会有较大的时间消耗。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">class SnapshotSandbox &#123;</span><br><span class="line">  () &#123;</span><br><span class="line">    this.proxy = window; //window属性</span><br><span class="line">    this.modifyPropsMap = &#123;&#125;; //记录在window上的修改</span><br><span class="line">  &#125;</span><br><span class="line">  active() &#123;//激活</span><br><span class="line">    this.windowSnapshot = &#123;&#125;; //快照</span><br><span class="line">    for (const prop in window) &#123;</span><br><span class="line">      if (window.hasOwnProperty(prop)) &#123;</span><br><span class="line">        this.windowSnapshot[prop] = window[prop]</span><br><span class="line">      &#125;</span><br><span class="line">      Object.keys(this.modifyPropsMap).forEach(p =&gt; &#123;</span><br><span class="line">        window[p] = this.modifyPropsMap[p]</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  inactive() &#123;//卸载</span><br><span class="line">    for (const prop in window) &#123;</span><br><span class="line">      if (window.hasOwnProperty(prop)) &#123;</span><br><span class="line">        if (window[prop] != this.windowSnapshot[prop]) &#123;</span><br><span class="line">          this.modifyPropsMap[prop] = window[prop];</span><br><span class="line">          window[prop] = this.windowSnapshot[prop];</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="（2）legacySandBox"><a href="#（2）legacySandBox" class="headerlink" title="（2）legacySandBox"></a>（2）<code>legacySandBox</code></h3><p>第二种则是legacy沙箱，下面的demo比上一个稍微复杂一点。主要是加载了两次子应用，并且每次改变的变量值不同。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">let &#123; sandbox, fakeWindow &#125; = new legacySandBox();</span><br><span class="line">var a = &#x27;主应用A&#x27;;</span><br><span class="line">var c = &#x27;主应用C&#x27;;</span><br><span class="line"></span><br><span class="line">console.log(&#x27;主应用原来的Window:&#x27;, a, c);</span><br><span class="line">function beforeMounted() &#123;</span><br><span class="line">  sandbox.active();</span><br><span class="line">  console.log(&quot;加载子应用前&quot;);</span><br><span class="line">&#125;</span><br><span class="line">function beforeUnMounted() &#123;</span><br><span class="line">  sandbox.inactive();</span><br><span class="line">  console.log(&quot;卸载子应用前&quot;);</span><br><span class="line">&#125;</span><br><span class="line">function app1(win = window) &#123;//这里使用了fakeWindow作为window</span><br><span class="line">  beforeMounted();</span><br><span class="line">  if (win.a === &#x27;app1A&#x27;) &#123;</span><br><span class="line">    win.a = &#x27;app1A-2&#x27;;</span><br><span class="line">    win.c = &#x27;2&#x27;;</span><br><span class="line">    win.d = &#x27;app1D-2&#x27;;</span><br><span class="line">    console.log(&quot;子应用第二次加载Window:&quot;,</span><br><span class="line">      win.a, win.c, win.d);</span><br><span class="line">  &#125; else &#123;</span><br><span class="line">    win.a = &#x27;app1A&#x27;;//修改</span><br><span class="line">    win.c = null;//删除</span><br><span class="line">    win.d = &#x27;app1D&#x27;;//新增</span><br><span class="line">    console.log(&quot;子应用第一次加载Window:&quot;,</span><br><span class="line">      win.a, win.c, win.d);</span><br><span class="line">  &#125;</span><br><span class="line">  beforeUnMounted();</span><br><span class="line">&#125;</span><br><span class="line">app1(fakeWindow); console.log(&#x27;主应用现在的1Window:&#x27;, a, c, d);</span><br><span class="line">app1(fakeWindow); console.log(&#x27;主应用现在的2Window:&#x27;, a, c, d);</span><br></pre></td></tr></table></figure><p>左图显示的是主应用被污染的结果，右图是打开沙箱之后解决污染的结果。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251928129.png"></p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251929334.png"></p><p><code>legacy</code>沙箱的主要原理是使用了ES6中的Proxy，把原来的window代理到<code>fakeWindow</code>上，这样就不用遍历整个window去应用和恢复环境了。除此之外，它还在沙箱内部设置了三个变量池：<code>addedPropsMapinSandbox</code>用于存放子应用运行期间新增的全局变量，用于在卸载子应用的时候删除；<code>modifiedPropsOrginalMapInSandbox</code>用于存放子应用运行期间修改的全局变量，用于卸载时进行恢复；<code>currentUpdatedPropsValueMap</code>用于存放子应用运行期间所有变化的变量，这样可以在加载子应用时恢复其上一次的环境。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251929997.png"></p><p>下面是具体实现的沙箱demo：      </p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">class legacySandBox &#123;</span><br><span class="line">  () &#123;</span><br><span class="line">    this.addedPropsMapInSandbox = new Map();//记录子应用运行期间新增的key</span><br><span class="line">    this.modifiedPropsOriginalValueMapInSandbox = new Map();//记录子应用运行期间修改的key</span><br><span class="line">    this.currentUpdatedPropsValueMap = new Map();//记录子应用运行期间的值</span><br><span class="line">    this.sandboxRunning = false;</span><br><span class="line">    const _this = this;</span><br><span class="line">    const fakeWindow = new Proxy(window, &#123;</span><br><span class="line">      set(_, p, value) &#123;</span><br><span class="line">        if (_this.sandboxRunning) &#123;</span><br><span class="line">          if (!window.hasOwnProperty(p)) &#123;</span><br><span class="line">            _this.addedPropsMapInSandbox.set(p, value);</span><br><span class="line">          &#125; else if (!_this.modifiedPropsOriginalValueMapInSandbox.has(p)) &#123;</span><br><span class="line">            const originalValue = window[p];</span><br><span class="line">            _this.modifiedPropsOriginalValueMapInSandbox.set(p, originalValue);</span><br><span class="line">          &#125;</span><br><span class="line">          _this.currentUpdatedPropsValueMap.set(p, value);</span><br><span class="line">          window[p] = value;</span><br><span class="line">          return true;</span><br><span class="line">        &#125;</span><br><span class="line">        return true;</span><br><span class="line">      &#125;,</span><br><span class="line">      get(_, p) &#123;</span><br><span class="line">        if (p === &quot;top&quot; || p === &quot;window&quot; || p === &quot;self&quot;) &#123;</span><br><span class="line">          return proxy;</span><br><span class="line">        &#125;</span><br><span class="line">        return window[p];</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    return &#123; sandbox: this, fakeWindow &#125;;</span><br><span class="line">  &#125;</span><br><span class="line">  active() &#123;//激活</span><br><span class="line">    if (!this.sandboxRunning) &#123;</span><br><span class="line">      this.currentUpdatedPropsValueMap.forEach((v, p) =&gt; this.setWindowProp(p, v));</span><br><span class="line">    &#125;</span><br><span class="line">    this.sandboxRunning = true;</span><br><span class="line">  &#125;</span><br><span class="line">  inactive() &#123;//卸载</span><br><span class="line">    this.modifiedPropsOriginalValueMapInSandbox.forEach((v, p) =&gt; this.setWindowProp(p, v));</span><br><span class="line">    this.addedPropsMapInSandbox.forEach((v, p) =&gt; this.setWindowProp(p, undefined, true));</span><br><span class="line">    this.sandboxRunning = false;</span><br><span class="line">  &#125;</span><br><span class="line">  setWindowProp(p, v) &#123;</span><br><span class="line">    window[p] = v;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="（3）ProxySandbox"><a href="#（3）ProxySandbox" class="headerlink" title="（3）ProxySandbox"></a>（3）<code>ProxySandbox</code></h3><p>第二种沙箱的实现对于单例模式来说已经比较完善了，但是不适用于多例模式，即同时有多个子应用在运行期间的时候，qiankun针对这个问题提出来<code>proxySandbox</code>。</p><p><code>proxySandbox</code>依然是使用proxy代理window，但不同的是对于每个子应用都代理了一个<code>fakeWindow</code>，这样在查找变量的时候在本地的<code>fakeWindow</code>上查找，如果没有找到就到主应用的window上查找，而修改时只修改本地的<code>fakeWindow</code>，不会影响到其他的应用，在最终卸载时把<code>fakeWindow</code>删除即可。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251930626.png"></p><h2 id="5-其他功能"><a href="#5-其他功能" class="headerlink" title="5.其他功能"></a>5.其他功能</h2><p>其他功能比如“旧项目路由接入改造”、“微应用和路由之间如何<code>Keep alive</code>”、“<code>webStorage</code>应用之间的使用”、“资源共享”、“微应用内存溢出问题”、“同一路由多应用共存”等功能见<a href="https://juejin.cn/post/7069566144750813197#heading-46">《万字长文-落地微前端 qiankun 理论与实践指北》</a></p><br /><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h2 id="1-qiankun官方统计的常见问题"><a href="#1-qiankun官方统计的常见问题" class="headerlink" title="1.qiankun官方统计的常见问题"></a>1.qiankun官方统计的常见问题</h2><p><a href="https://qiankun.umijs.org/zh/faq">官方问题汇总</a></p><h2 id="2-子应用静态资源加载失败问题"><a href="#2-子应用静态资源加载失败问题" class="headerlink" title="2.子应用静态资源加载失败问题"></a>2.子应用静态资源加载失败问题</h2><p>说明：子应用的静态资源引用时都是相对路径，当子应用放入到基座中后，通过主应用url访问时，静态资源的请求域名默认会使用主应用的，所以导致静态资源全部加载失败。</p><p>常规情况可以通过以下前两点解决这个问题：</p><p>（1）使用 <code>webpack</code> 运行时 <code>publicPath</code>配置<code>qiankun</code> 将会在微应用 <code>bootstrap</code> 之前注入一个运行时的 <code>publicPath</code> 变量，你需要做的是在微应用的 <code>entry js</code> 的顶部添加如下代码：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;</span><br></pre></td></tr></table></figure><p>关于运行时 <code>publicPath</code> 的技术细节，可以参考 <code>webpack</code> 文档。</p><p><code>runtime publicPath</code> 主要解决的是微应用动态载入的 脚本、样式、图片 等地址不正确的问题。</p><p>（2）使用 <code>webpack</code> 静态 <code>publicPath</code>配置 你需要将你的 <code>webpack publicPath</code> 配置设置成一个绝对地址的 url，比如在开发环境可能是：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  output: &#123;</span><br><span class="line">    publicPath: `//localhost:$&#123;port&#125;`,</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>（3）对于vite构建的子应用，上述两种方法可能失效，可尝试如下设置origin方法：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">export default defineConfig(&#123;</span><br><span class="line">  // ...</span><br><span class="line">  server: &#123;</span><br><span class="line">    host: &#x27;localhost&#x27;,</span><br><span class="line">    port: 5174,</span><br><span class="line">    origin: &#x27;http://localhost:5174&#x27;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="3-解决切换路由时报错"><a href="#3-解决切换路由时报错" class="headerlink" title="3.      解决切换路由时报错"></a>3.      解决切换路由时报错</h2><p><code>[Vue Router warn]: Error with push/replace State DOMException: Failed to execute ‘replaceState’ on ‘History’: A history state object with URL ‘http://localhost:8080undefined/’ cannot be created in a document with origin ‘http://localhost:8080’ and URL ‘http://localhost:8080/mypage1/’.</code></p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">router.beforeEach((to, from, next) =&gt; &#123;</span><br><span class="line">  if (!window.history.state.current) window.history.state.current = to.fullPath;</span><br><span class="line">  if (!window.history.state.back) window.history.state.back = from.fullPath;</span><br><span class="line">  // 手动修改history的state</span><br><span class="line">  return next();</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="4-微应用不是直接跟路由关联或是有需要手动触发子应用加载的场景该怎么做？"><a href="#4-微应用不是直接跟路由关联或是有需要手动触发子应用加载的场景该怎么做？" class="headerlink" title="4.微应用不是直接跟路由关联或是有需要手动触发子应用加载的场景该怎么做？"></a>4.微应用不是直接跟路由关联或是有需要手动触发子应用加载的场景该怎么做？</h2><p>这时候qiankun提供了一个 <code>loadMicroApp</code> 的方法进行子应用的手动加载，本质上是利用<code>single-spa</code>的<code>mountRootParcel api</code>来实现的。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; loadMicroApp &#125; from &#x27;qiankun&#x27;;</span><br><span class="line">loadMicroApp(</span><br><span class="line">&#123;</span><br><span class="line">    name: &#x27;app&#x27;,</span><br><span class="line">    entry: &#x27;//localhost:7100&#x27;,</span><br><span class="line">    container: &#x27;#Container&#x27;,</span><br><span class="line">&#125; );</span><br></pre></td></tr></table></figure><p>使用<code>loadMircoApp</code>还需要在子应用中暴露<code>update</code>钩子。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 增加 update 钩子以便主应用手动更新微应用</span><br><span class="line">export async function update(props) &#123;</span><br><span class="line">    renderPatch(props);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-CSS-样式污染问题"><a href="#5-CSS-样式污染问题" class="headerlink" title="5.CSS 样式污染问题"></a>5.CSS 样式污染问题</h2><p>在微应用为vite时，样式问题是重灾区。由于没有沙箱，样式也不能进行隔离，由于前文提到的css加载的方式都是全局在主应用上生效的，所以全局上css互相影响的概率就很大，并且子应用使用的和主应用使用的组件库都是Element 或 Ant Design系列的，一些类名都是一致，这种情况下如果还按照之前的开发习惯直接控制组件对应的类名样式，大概率会出现互相层叠污染的情况，这时就需要一些开发规范和工程化的手段来设置样式。</p><p>以下以Ant Design为例，说明如何引入prefix来解决样式冲突问题，当然<code>ElementPlus</code>中也支持设置 <code>prefix</code>：</p><p>（1）<code>Ant Design</code>修改<code>prefix</code></p><p>从工程化的角度可以解决多个<code>ant design</code>组件库同时使用的样式污染问题，qiankun官方也有提供该解决方案，就是通过<code>ant-desigtn</code>注入<code>prefix</code>，拿<code>ant-desigin-vue</code>来说：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;a-config-provider prefix-cls=&quot;custom&quot;&gt;</span><br><span class="line">    &lt;my-app /&gt;</span><br><span class="line">  &lt;/a-config-provider&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure><p>这样实际使用的ant的类名都是以<code>.custom-xxx</code>的类名了</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251937737.png"></p><p>上图所见这样实现的自定义类名可以做到多份ant的css引入类名重复的问题。</p><p>当然如果自定义类名的话可以在less构建时注入相同的<code>prefix</code>，让全局的less存在相同的一个前缀变量，实际修改<code>.ant-xxx</code>类似的类名时需要替换<code>.ant</code>为相应的注入的<code>prefix</code>变量：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// vite.config.js</span><br><span class="line">export default () =&gt; &#123;</span><br><span class="line">  return &#123;</span><br><span class="line">      css: &#123;</span><br><span class="line">      preprocessorOptions: &#123;</span><br><span class="line">        less: &#123;</span><br><span class="line">          modifyVars: &#123;</span><br><span class="line">            // 这里可以注入全局的less变量，通过注入的变量名称去实际业务样式修改的地方拼接prefix变量</span><br><span class="line">            &#x27;ant-prefix&#x27;: &#x27;custom&#x27;, // 这里注入的prefix如上文提到&lt;a-config-provider prefix-cls=&quot;custom&quot;&gt; 需要一致，以便一致</span><br><span class="line">          &#125;,</span><br><span class="line">          javascriptEnabled: true,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>通过上面的<code>vite</code>配置注入的<code>ant-prefix</code>这样可以在实际的样式中拼接使用：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">.@&#123;ant-prefix&#125; &#123;</span><br><span class="line">  .@&#123;ant-prefix&#125;-col &#123;</span><br><span class="line">    width: 100%;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这样构建出来的样式修改也是<code>.custom-xxx</code>的类名，可以达到修改自己的ant组件样式还不影响其他ant的项目UI。</p><p>（2）手动隔离子应用的样式</p><p>上文的方式解决了UI框架级别的css污染，同时我们自己的全局样式配置也会有一些css样式：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">input:-webkit-autofill &#123;</span><br><span class="line">  -webkit-box-shadow: 0 0 0 1000px white inset !important;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">:-webkit-autofill &#123;</span><br><span class="line">  transition: background-color 5000s ease-in-out 0s !important;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">a:focus,</span><br><span class="line">a:active,</span><br><span class="line">button,</span><br><span class="line">div,</span><br><span class="line">svg,</span><br><span class="line">span,</span><br><span class="line">label &#123;</span><br><span class="line">  outline: none !important;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">a &#123;</span><br><span class="line">  color: #51ffff !important;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这种情况需要我们手动进行隔离，我们可以在挂载的根节点元素上设置<code>vite</code>注入的<code>less</code>变量<code>ant-prefix</code>相同的类名，然后如下配置：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">.@&#123;ant-prefix&#125; &#123;</span><br><span class="line">  input:-webkit-autofill &#123;</span><br><span class="line">    -webkit-box-shadow: 0 0 0 1000px white inset !important;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  :-webkit-autofill &#123;</span><br><span class="line">    transition: background-color 5000s ease-in-out 0s !important;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  a:focus,</span><br><span class="line">  a:active,</span><br><span class="line">  button,</span><br><span class="line">  div,</span><br><span class="line">  svg,</span><br><span class="line">  span,</span><br><span class="line">  label &#123;</span><br><span class="line">    outline: none !important;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  a &#123;</span><br><span class="line">    color: #51ffff !important;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>通过如上的包裹实现手动样式隔离，子应用设置的全局样式只作用于自己，不会影响到其他的项目。</p><h2 id="6-CSS样式没被插入到页面中去"><a href="#6-CSS样式没被插入到页面中去" class="headerlink" title="6.CSS样式没被插入到页面中去"></a>6.CSS样式没被插入到页面中去</h2><p>qiankun的一个<a href="https://link.juejin.cn/?target=https://github.com/umijs/qiankun/issues/264">bug</a></p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251939061.png"></p><p>如上图qiankun的issue中确实有跟我遇到一样的问题，这个问题原因可能是qiankun的问题，也可能是qiankun主应用配置的问题，但是我作为第三方接入并没有权限去调整对方的主应用配置，只能自己排查去从子应用去解决。</p><p>这个问题大概是我构建完的HTML Entry中样式是通过link标签引入的，同时还有一些我的第三方直接引入的css：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;head&gt;</span><br><span class="line">  &lt;link rel=&quot;styleSheet&quot; href=&quot;/resouce/assets/xxx.css&quot; /&gt;</span><br><span class="line">  &lt;link rel=&quot;styleSheet&quot; href=&quot;/resouce/assets/vonder.xxxx.css&quot; /&gt;</span><br><span class="line">  &lt;link rel=&quot;styleSheet&quot; href=&quot;/resouce/assets/index.xxxx.css&quot; /&gt;</span><br><span class="line">&lt;/head&gt;</span><br></pre></td></tr></table></figure><p>上文介绍的这种情况通过<code>import-html-entry</code>解析会通过fetch请求回来，但是奇怪的是并不会插入到主应用中，fetch的类型也不是styleSheet，这样虽然资源请求回来了但是css样式并不会生效，通过排查发现如果是通过javascript动态插入的link,主应用则会正确插入css使样式生效：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">   var i = document.createElement(&#x27;link&#x27;);</span><br><span class="line">   i.rel = &#x27;stylesheet&#x27;;</span><br><span class="line">   i.href = ip:port/path/to/css.css;</span><br><span class="line">   document.head.appendChild(i); </span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>以上的代码会被解析并正确执行，插入到主应用中，使之生效。</p><p>上面我们发现的一个qiankun加载css的问题，导致入口的css样式并不生效，也找到了方法去解决，开始的想法是在HTML Entry中用javascript脚本来将入口中的link标签转换为动态插入的javascript的代码，但是很遗憾由于打包后的css路径带有hash是动态的不能直接写死创建哪些link标签，动态获取link标签在主应用执行的时候会误伤主应用以及其他的子应用的link标签，所以这样并未达到预期.</p><p>那思路就转换为是否能通过工程化的思维来通过脚本的方式来处理，在生成<code>HTML Entry</code>时将拿到的link动态转换成上文提到代码，同时前文也分析过<code>vite-plugin-qainkun</code>的实现，就想是不是可以通过vite插件的方式来对Index.html生成时做一些文章</p><ul><li><p>可以把link标签对应的css资源转换成style标签</p></li><li><p>可以像上文提到的通过javascript动态插入link把原来的link标签remove掉</p></li></ul><p>最终选择了第二种方式来进行实现，当然这之前还需要一些vite插件编写的<a href="https://link.juejin.cn/?target=https://cn.vitejs.dev/guide/api-plugin.html">基础知识</a>,这里就不再赘述，以后有机会单独写一篇关于这些构建工具插件开发的文章。</p><p>好了，现在通过参考vite-plugin-qiankun和vite插件的基本知识，结合自己的需求确定了我们只需要在插件的transformIndexHtml钩子方法中对Index.html进行脚本开发：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// vite-plugin-css-importtransform.js</span><br><span class="line">import cheerio from &#x27;cheerio&#x27;; // 插件需要安装cheerio来操作html（cheerio的一些api与jquery一致，node爬虫中会比较常用这个库）</span><br><span class="line">export default function cssImportPlugin() &#123;</span><br><span class="line">  return &#123;</span><br><span class="line">    name: &#x27;transform-css-import&#x27;,</span><br><span class="line">    transformIndexHtml: (html) =&gt; &#123; // 该钩子函数里面可以拿到构建时的html字符串</span><br><span class="line">      const $ = cheerio.load(html); // 载入然后可以像jquery一样控制html的各个标签了</span><br><span class="line">      const links = $(&#x27;head link[rel=styleSheet]&#x27;); // 拿到link css的标签然后转换</span><br><span class="line">      links.each(function (i, link) &#123;</span><br><span class="line">        $(&#x27;head&#x27;).append(`&lt;script&gt; </span><br><span class="line">          var i$&#123;i&#125; = document.createElement(&#x27;link&#x27;);</span><br><span class="line">          i$&#123;i&#125;.rel = &#x27;stylesheet&#x27;;</span><br><span class="line">          i$&#123;i&#125;.href = &#x27;$&#123;$(link).attr(&#x27;href&#x27;)&#125;&#x27;;</span><br><span class="line">          document.head.appendChild(i$&#123;i&#125;);</span><br><span class="line">         &lt;/script&gt;`);</span><br><span class="line">      &#125;);</span><br><span class="line">      links.remove(); // 把原有的link删掉</span><br><span class="line">      return $.html(); // 返回html字符串</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面的插件逻辑比较简单，当然使用也比较简单，不需要传入什么参数</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// vite.config.js</span><br><span class="line">import qiankun from &#x27;vite-plugin-qiankun&#x27;;</span><br><span class="line">import cssImportPlugin from &#x27;./vite-plugin-css-import-transform&#x27;;</span><br><span class="line"></span><br><span class="line">export default () =&gt; &#123;</span><br><span class="line">  return &#123;</span><br><span class="line">    plugins: [</span><br><span class="line">      qiankun(&#x27;子应用标识&#x27;， &#123;</span><br><span class="line">        // 其他的一些配置</span><br><span class="line">      &#125;),</span><br><span class="line">      cssImportPlugin(), // 引入自定义的vite插件并使用</span><br><span class="line">    ]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>通过插件构建后的HTMl Entry就变成了这样：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251940053.png"></p><p>至此也解决了实际中<code>HTML Entry</code>引入css样式不生效的问题。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/554fb506/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>微前端qiankun接入Vite构建的子应用</title>
      <link>https://blog.helloallen.cn/6e3761bf/</link>
      <guid>https://blog.helloallen.cn/6e3761bf/</guid>
      <pubDate>Mon, 25 Dec 2023 23:35:26 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="存在问题"><a href="#存在问题" class="headerlink" title="存在问题"></a>存在问题</h2><p>qiankun官方暂未有文档表明已经支持Vite，所以直接用普通方式接入vite构建的子应用时会出现如下问题：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251700488.png"></p><br /><h2 id="原因分析"><a href="#原因分析" class="headerlink" title="原因分析"></a>原因分析</h2><h2 id="1-开发模式："><a href="#1-开发模式：" class="headerlink" title="1. 开发模式："></a>1. 开发模式：</h2><p>在开发环境下，如果我们使用 vite 来构建 vue3 子应用，基于vite的构建机制，会在子应用的 html 的入口文件的 script 标签上携带 <code>type=module</code>。而我们知道qiankun父应用引入子应用，本质上是将html做为入口文件，并通过<code>import-html-entry</code>这个库去加载子应用所需要的资源列表JS、CSS，然后通过eval直接执行，而基于vite构建的JS中import、export并没有被转码（vite是基于浏览器支持的 <code>ESM import</code>特性实现的 bundless，通过利用浏览器进行模块间依赖加载，而不需要在编译时进行。），会导致直接报错（不允许在非 <code>type=module</code> 的 script 里面使用 import）</p><h2 id="2-生产模式："><a href="#2-生产模式：" class="headerlink" title="2. 生产模式："></a>2. 生产模式：</h2><p>生产模式下，因为没有诸如webpack中支持运行时publicPath,也就是<code>__webpack_public_path__</code>，换句话说就是vite不支持运行时publicPath，其主要作用是用来解决微应用动态载入的脚本、样式、图片等地址不正确的问题。</p><br /><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>有一款开源插件：<code>vite-plugin-qiankun</code>，通过这个插件可以在qiankun下解决上述两种模式的问题，同时保留了vite构建模块的优势。</p><h2 id="1-创建主应用"><a href="#1-创建主应用" class="headerlink" title="1. 创建主应用"></a>1. 创建主应用</h2><p>（1）安装qiankun</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install qiankun</span><br></pre></td></tr></table></figure><p>（2）新建<code>src/qiankun/index.js</code>文件，进行单独的抽离</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; registerMicroApps, start &#125; from &#x27;qiankun&#x27;</span><br><span class="line">registerMicroApps([</span><br><span class="line">    &#123;</span><br><span class="line">        // 必须与子应用注册名字相同</span><br><span class="line">        name: &#x27;vue-app&#x27;,</span><br><span class="line">        // 入口路径，开发时为子应用所启本地服务，上线时为子应用线上路径</span><br><span class="line">        entry: &#x27;http://127.0.0.1:5174&#x27;, </span><br><span class="line">        // 子应用挂载的节点</span><br><span class="line">        container: &#x27;#vue-app-container&#x27;,</span><br><span class="line">        // 当访问路由为 /micro-vue 时加载子应用</span><br><span class="line">        activeRule: &#x27;/micro-vue&#x27;, </span><br><span class="line">        // 主应用向子应用传递参数</span><br><span class="line">        props: &#123;</span><br><span class="line">            msg: &quot;我是来自主应用的值-vue&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">        name: &#x27;react-app&#x27;,</span><br><span class="line">        entry: &#x27;http://127.0.0.1:5175&#x27;,</span><br><span class="line">        container: &#x27;#react-app-container&#x27;,</span><br><span class="line">        activeRule: &#x27;/micro-react&#x27;,</span><br><span class="line">        props: &#123;</span><br><span class="line">            msg: &quot;我是来自主应用的值-react&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">])</span><br><span class="line">start()</span><br></pre></td></tr></table></figure><p>（3）在<code>main.js</code>中导入</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">import &quot;./qiankun&quot;</span><br></pre></td></tr></table></figure><p>（4）在<code>App.vue</code>挂载子应用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;vue-app-container&quot; /&gt;</span><br><span class="line">&lt;div id=&quot;react-app-container&quot; /&gt;</span><br></pre></td></tr></table></figure><h2 id="2-创建子应用-micro-vue-app-（vue3-vite）"><a href="#2-创建子应用-micro-vue-app-（vue3-vite）" class="headerlink" title="2.创建子应用 micro-vue-app （vue3 + vite）"></a>2.创建子应用 micro-vue-app （vue3 + vite）</h2><p>qiankun目前是不支持vite的，需要借助插件完成</p><p>（1） 安装插件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install vite-plugin-qiankun</span><br></pre></td></tr></table></figure><p>（2）修改<code>vite.config.js</code></p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; defineConfig &#125; from &#x27;vite&#x27;</span><br><span class="line">import vue from &#x27;@vitejs/plugin-vue&#x27;</span><br><span class="line">import qiankun from &#x27;vite-plugin-qiankun&#x27;</span><br><span class="line"></span><br><span class="line">export default defineConfig(&#123;</span><br><span class="line">  plugins: [</span><br><span class="line">    vue(),</span><br><span class="line">    qiankun(&#x27;vue-app&#x27;, &#123; // 子应用名字，与主应用注册的子应用名字保持一致</span><br><span class="line">      useDevMode: true</span><br><span class="line">    &#125;)</span><br><span class="line">  ],</span><br><span class="line">  server: &#123;</span><br><span class="line">    origin: &#x27;http://localhost:5174&#x27;, // 解决静态资源加载404问题</span><br><span class="line">    host: &#x27;localhost&#x27;,</span><br><span class="line">    port: 5174</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>（3）修改<code>main.js</code></p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; createApp &#125; from &#x27;vue&#x27;</span><br><span class="line">import App from &#x27;./App.vue&#x27;</span><br><span class="line">import &#123; store &#125; from &#x27;./store&#x27;</span><br><span class="line"></span><br><span class="line">import &#123; renderWithQiankun, qiankunWindow &#125; from &#x27;vite-plugin-qiankun/dist/helper&#x27;</span><br><span class="line"></span><br><span class="line">let instance = null;</span><br><span class="line">const initQianKun = () =&gt; &#123;</span><br><span class="line">    renderWithQiankun(&#123;</span><br><span class="line">        mount(props) &#123;</span><br><span class="line">            render(props.container)</span><br><span class="line">            //  可以通过props读取主应用的参数：msg</span><br><span class="line">            // 监听主应用传值</span><br><span class="line">            props.onGlobalStateChange((res) =&gt; &#123;</span><br><span class="line">                store.count = res.count</span><br><span class="line">                console.log(res.count)</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;,</span><br><span class="line">        bootstrap() &#123; &#125;,</span><br><span class="line">        unmount() &#123;</span><br><span class="line">            instance.unmount()</span><br><span class="line">            instance._instance = null</span><br><span class="line">            instance = null</span><br><span class="line">        &#125;,</span><br><span class="line">        update() &#123; &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">const render = (container) =&gt; &#123;</span><br><span class="line">    if (instance) return;</span><br><span class="line">    // 如果是在主应用的环境下就挂载主应用的节点，否则挂载到本地</span><br><span class="line">    // 注意：这边需要避免 id（app） 重复导致子应用挂载失败</span><br><span class="line">    const appDom = container ? container.querySelector(&quot;#app&quot;) : &quot;#app&quot;</span><br><span class="line">    instance = createApp(App)</span><br><span class="line">    instance.mount(appDom)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 判断当前应用是否在主应用中</span><br><span class="line">qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()</span><br></pre></td></tr></table></figure><p>（4）修改route文件，采用hash模式</p><p>qiankun官方是以<code>window.__POWERED_BY_QIANKUN__</code>来判断当前是否为qiankun环境下，而该插件引用之后是通过<code>qiankunWindow.__POWERED_BY_QIANKUN__</code>来判断。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; createWebHashHistory &#125; from &#x27;vue-router&#x27;</span><br><span class="line">import &#123; qiankunWindow &#125; from &#x27;vite-plugin-qiankun/dist/helper&#x27;</span><br><span class="line">const router = createRouter(&#123;</span><br><span class="line">    // 值和主应用中的activeRule保持一致    </span><br><span class="line">    history: createWebHashHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? &#x27;/vueApp&#x27; : &#x27;/&#x27;),     </span><br><span class="line">    routes: routes </span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="3-创建子应用-micor-react-app-（react18-vite）"><a href="#3-创建子应用-micor-react-app-（react18-vite）" class="headerlink" title="3.创建子应用 micor-react-app （react18 + vite）"></a>3.创建子应用 micor-react-app （react18 + vite）</h2><p>和vue配置一样，但是会报错：</p><p>解决方法：在 <code>vite.config.js</code> 中删除<code>react()</code></p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; defineConfig &#125; from &#x27;vite&#x27;</span><br><span class="line">import react from &#x27;@vitejs/plugin-react&#x27;</span><br><span class="line">import qiankun from &#x27;vite-plugin-qiankun&#x27;</span><br><span class="line"></span><br><span class="line">export default defineConfig(&#123;</span><br><span class="line">  plugins: [</span><br><span class="line">    // 在开发模式下需要把react()关掉</span><br><span class="line">    // https://github.com/umijs/qiankun/issues/1257</span><br><span class="line">    // react(),</span><br><span class="line">    qiankun(&#x27;react-app&#x27;, &#123;// 子应用名字，与主应用注册的子应用名字保持一致</span><br><span class="line">      useDevMode: true</span><br><span class="line">    &#125;)</span><br><span class="line">  ],</span><br><span class="line">  server: &#123;</span><br><span class="line">    port: &#x27;5175&#x27;,</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>完整代码见<a href="https://github.com/HelloAllenW/qiankun-demo-vite">Demo</a></p><br /><h2 id="可能存在的其他问题"><a href="#可能存在的其他问题" class="headerlink" title="可能存在的其他问题"></a>可能存在的其他问题</h2><ol><li><p>插件<code>vite-plugin-qiankun</code>在生产模式下依旧不支持<code>publicPath</code>, 需要将<code>vite.config.js</code>中<code>base</code>配置写死。导致多环境部署不便捷。无法像在webpack结合<code>window.INJECTED_PUBLIC_PATH_BY_QIANKUN</code> + <code>publicpath</code>来解决。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251709635.png"></p></li><li><p>关于<code>vue3 + vite + typescript</code>项目中出现 <code>“Error: The package &quot;@esbuild/win32-x64&quot; could not be found, and is needed by esbuild.” </code>的错误。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251711450.png"></p><p>在运行dev之前先运行<code>·node node_modules/esbuild/install.js</code>命令来解决esbuild安装问题。然后再启动项目，发现已经能正常运行。</p></li></ol>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/6e3761bf/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>微前端（qiankun）Hash路由实践</title>
      <link>https://blog.helloallen.cn/eab5c6de/</link>
      <guid>https://blog.helloallen.cn/eab5c6de/</guid>
      <pubDate>Mon, 25 Dec 2023 23:32:44 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>qiankun官方demo用的是history方式的路由，我们知道history需要后端配合，否则线上环境刷新会404。那么今天我们就研究下如何将主应用改为hash模式。</p><br /><h2 id="关于路由"><a href="#关于路由" class="headerlink" title="关于路由"></a>关于路由</h2><h2 id="1-存在问题"><a href="#1-存在问题" class="headerlink" title="1.存在问题"></a>1.存在问题</h2><p>在采用 hash 路由模式的话，主应用路由会有 <code>/#/ </code>的前缀，比如主应用的 resource 组件路由：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://localhost:8889/#/resource</span><br></pre></td></tr></table></figure><p>假设 history 路由模式下子应用的注册信息为：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  name: &#x27;live&#x27;,</span><br><span class="line">  entry: &#x27;//localhost:7102&#x27;,</span><br><span class="line">  container: &#x27;#subapp-viewport&#x27;,</span><br><span class="line">  activeRule: &#x27;/live&#x27;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>此时 qiankun 只有命中 url 为<code>http://localhost:8889/live</code>才会加载子应用。</p><p>此处假设使用的路由切换代码为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">this.$router.push(&#123;</span><br><span class="line">  path: &#x27;/live&#x27;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>那么现在切换的 url 是 <code>http://localhost:8889/#/live</code>，显然不能匹配 <code>/live</code>，所以加载子应用失败。我们需要修改一下子应用注册的 <code>activeRule</code>，使得匹配 hash 路由模式。</p><h2 id="2-解决方案"><a href="#2-解决方案" class="headerlink" title="2.解决方案"></a>2.解决方案</h2><p>为了区分开主应用的自身模块与子应用的路由区别，子应用的路由增加 <code>/micro</code> 前缀，比如<code> /micro/live</code> 是子应用的路由。</p><p>那么 hash 路由模式下子应用的注册信息变成：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  name: &#x27;live&#x27;,</span><br><span class="line">  entry: &#x27;//localhost:7102&#x27;,</span><br><span class="line">  container: &#x27;#subapp-viewport&#x27;,</span><br><span class="line">  activeRule: &#x27;/#/micro/live&#x27;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>路由切换代码修改为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">this.$router.push(&#123;</span><br><span class="line">  path: &#x27;/micro/live&#x27;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>这样的话，主应用路由切换后的 url 就能命中子应用的 activeRule 了。</p><p>同时，子应用也需要将路由模式设置为 hash 模式，否则，会出现在子应用切换自身路由时，改变主应用 hash 路由的情况。比如子应用切换自身路由 <code>/about</code>，此时 url 会变成 <code>http://localhost:8889/about/#/micro/live</code>，导致路由命中失败。我们期望的 url 是 <code>http://localhost:8889/#/micro/live/about</code>。</p><p>所以，为了兼容主应用的 hash 模式路由，子应用也需要设置为 hash 模式的路由，最终结果是实现子应用路由与子应用注册在主应用的 activeRule 的一致性。</p><p>下面会分别对主应用与子应用进行配置。</p><br /><h2 id="配置子应用"><a href="#配置子应用" class="headerlink" title="配置子应用"></a>配置子应用</h2><p>子应用是常规 vue 项目，需要做调整的的是路由配置文件 <code>/router.index.js</code> 以及入口文件 <code>main.js</code>。</p><h2 id="1-路由增加前缀"><a href="#1-路由增加前缀" class="headerlink" title="1.路由增加前缀"></a>1.路由增加前缀</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// router/index.js</span><br><span class="line"></span><br><span class="line">let prefix = &#x27;&#x27;</span><br><span class="line"></span><br><span class="line">// 判断是 qiankun 环境则增加路由前缀</span><br><span class="line">if(window.__POWERED_BY_QIANKUN__)&#123;</span><br><span class="line">  prefix = &#x27;/micro/live&#x27;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">const routes = [</span><br><span class="line">  &#123;</span><br><span class="line">    path: prefix + &#x27;/&#x27;,</span><br><span class="line">    name: &#x27;home&#x27;,</span><br><span class="line">    component: Home,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    path: prefix +&#x27;/about&#x27;,</span><br><span class="line">    name: &#x27;about&#x27;,</span><br><span class="line">    component: About</span><br><span class="line">  &#125;,</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h2 id="2-在路由跳转前添加前缀，保证和router中配置的path匹配上"><a href="#2-在路由跳转前添加前缀，保证和router中配置的path匹配上" class="headerlink" title="2. 在路由跳转前添加前缀，保证和router中配置的path匹配上"></a>2. 在路由跳转前添加前缀，保证和router中配置的path匹配上</h2><figure class="highlight plaintext"><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">// main.js</span><br><span class="line"></span><br><span class="line">let router = null;</span><br><span class="line">let instance = null;</span><br><span class="line"></span><br><span class="line">function render(props = &#123;&#125;) &#123;</span><br><span class="line">  const &#123; container &#125; = props;</span><br><span class="line">  router = new VueRouter(&#123;</span><br><span class="line">    // 1. 默认为 hash 路由模式</span><br><span class="line">    // base: window.__POWERED_BY_QIANKUN__ ? &#x27;/micro/live&#x27; : &#x27;/&#x27;,</span><br><span class="line">    // mode: &#x27;history&#x27;,</span><br><span class="line">    routes,</span><br><span class="line">  &#125;)</span><br><span class="line"></span><br><span class="line">  // 2. 判断 qiankun 环境则进行路由拦截，判断跳转路由是否有 /micro/live 开头前缀，没有则加上</span><br><span class="line">  if(window.__POWERED_BY_QIANKUN__)&#123;</span><br><span class="line">    router.beforeEach((to, from, next) =&gt; &#123;</span><br><span class="line">      if(!to.path.includes(&#x27;/micro&#x27;))&#123;</span><br><span class="line">        next(&#123;</span><br><span class="line">          path: &#x27;/micro/live&#x27; + to.path</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;else&#123;</span><br><span class="line">        next()</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  instance = new Vue(&#123;</span><br><span class="line">    router,</span><br><span class="line">    store,</span><br><span class="line">    render: h =&gt; h(App),</span><br><span class="line">  &#125;).$mount(container ? container.querySelector(&#x27;#app&#x27;) : &#x27;#app&#x27;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br /><h2 id="配置主应用"><a href="#配置主应用" class="headerlink" title="配置主应用"></a>配置主应用</h2><h2 id="1-修改注册微应用时的路由匹配规则"><a href="#1-修改注册微应用时的路由匹配规则" class="headerlink" title="1. 修改注册微应用时的路由匹配规则"></a>1. 修改注册微应用时的路由匹配规则</h2><p>因为主应用采用的是 hash 路由模式，qiankun 需要命中路由的话，activeRule 需要带上 <code>/#/</code> 前缀。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// App.vue</span><br><span class="line"></span><br><span class="line">const apps = [</span><br><span class="line">  // ...</span><br><span class="line">  &#123;</span><br><span class="line">    name: &#x27;live&#x27;,</span><br><span class="line">    entry: &#x27;//localhost:7101&#x27;,</span><br><span class="line">    container: &#x27;#subapp-viewport&#x27;,</span><br><span class="line">    activeRule: &#x27;/#/micro/live&#x27;,</span><br><span class="line">  &#125;,</span><br><span class="line">  // ...</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">registerMicroApps(apps)</span><br></pre></td></tr></table></figure><h2 id="2-增加路由"><a href="#2-增加路由" class="headerlink" title="2.增加路由"></a>2.增加路由</h2><p>使得主应用对于<code>/micrApp/dev</code>和<code>/micrApp/dev/about</code>匹配到的是同一个路由组件。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// router/index.js</span><br><span class="line"></span><br><span class="line">// ...</span><br><span class="line">&#123;</span><br><span class="line">    path: `/micrApp/live`,// 匹配微应用跳转</span><br><span class="line">    component: () =&gt; import(&#x27;@/views/prod/index&#x27;),</span><br><span class="line">    name: &#x27;dev&#x27;,</span><br><span class="line">&#125;</span><br><span class="line">&#123;</span><br><span class="line">    path: `/micrApp/live/:micrAppRoute`,// 匹配微应用内的路由跳转，vue-router v3.x需要使用 /micrApp/live/* 方式匹配</span><br><span class="line">    hidden:true,</span><br><span class="line">    component: () =&gt; import(&#x27;@/views/prod/index&#x27;),</span><br><span class="line">    name: &#x27;live&#x27;</span><br><span class="line">&#125;</span><br><span class="line">// ...</span><br></pre></td></tr></table></figure><p>现在，当url变化时，首先会进入qiankun的匹配规则中，匹配到 <code>/#/micro/live</code> 时，会加载微应用到节点。同时，主应用的vue-router匹配到<code>/micrApp/live</code>路由后会跳转到对应的路由组件；然后微应用的vue-router匹配后会展示相应的微应用路由。</p><p>当微应用内部的<code>&lt;router-link to=&quot;/about&quot;&gt;</code>被点击时，首先微应用跳转路由前会加上<code>/micro/live</code>前缀，所以就是往 <code>/micro/live/about </code>跳转，匹配到about路由；然后在主应用的vue-router中匹配到 <code>/micro/live/:microRoute</code>路由，保持主应用路由为同一个路由组件。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/eab5c6de/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>微前端（micro-app）使用手册</title>
      <link>https://blog.helloallen.cn/ea44f6b1/</link>
      <guid>https://blog.helloallen.cn/ea44f6b1/</guid>
      <pubDate>Mon, 25 Dec 2023 23:22:19 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p><code>micro-app</code> 是借鉴了 <code>Web Component</code> 的思想，通过 <code>Custom Element</code> 结合自定义的 <code>Shadow Dom</code>，将微前端封装成一个类 <code>Web Component</code> 组件，从而实现微前端的组件化渲染。并且由于自定义 <code>Shadow Dom</code> 的隔离特性，<code>micro-app</code> 不需要像 <code>single-spa</code> 和 <code>qiankun</code> 一样要求子应用修改渲染逻辑并暴露出方法，也不需要修改 <code>Webpack</code> 配置，是目前市面上接入微前端成本最低的方案。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312251945684.png"></p><br /><h2 id="快速上手"><a href="#快速上手" class="headerlink" title="快速上手"></a>快速上手</h2><h2 id="主应用"><a href="#主应用" class="headerlink" title="主应用"></a>主应用</h2><p>主应用不限技术栈，只需引入 <code>micro-app</code>、配置子应用路由并启动 <code>micro-app</code> 即可。这里以 <code>Vue3</code> 框架为例。</p><h3 id="安装-micro-app"><a href="#安装-micro-app" class="headerlink" title="安装 micro-app"></a>安装 micro-app</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">yarn add @micro-zoe/micro-app</span><br><span class="line"></span><br><span class="line">pnpm add @micro-zoe/micro-app</span><br><span class="line"></span><br><span class="line">npm i @micro-zoe/micro-app</span><br></pre></td></tr></table></figure><h3 id="启动-micro-app"><a href="#启动-micro-app" class="headerlink" title="启动 micro-app"></a>启动 micro-app</h3><p>在应用入口引入并启动 <code>micro-app</code>。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">import microApp from &#x27;@micro-zoe/micro-app&#x27;</span><br><span class="line"></span><br><span class="line">microApp.start()</span><br></pre></td></tr></table></figure><h3 id="嵌入子应用"><a href="#嵌入子应用" class="headerlink" title="嵌入子应用"></a>嵌入子应用</h3><p>创建 Vue 页面（如 <code>src/views/SubApp.vue</code>）用于承载子应用。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;micro-app name=&#x27;sub-app&#x27; url=&#x27;http://localhost:8381/&#x27; baseroute=&#x27;/sub-app&#x27;&gt;&lt;/micro-app&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br></pre></td></tr></table></figure><p><code>&lt;micro-app&gt;</code> 组件配置说明：</p><ol><li><p>name: 子应用名称。必须以字母开头，且不可以带有除中划线和下划线外的特殊符号，每个 name 都对应一个应用，当多个应用同时渲染时，name 不可以重复。</p></li><li><p>url: 子应用地址。会被自动补全，如 <code>http://localhost:3000/index.html</code>。</p></li><li><p>baseroute: 主应用分配给子应用的基础路由。</p></li><li><p><a href="https://zeroing.jd.com/docs.html#/zh-cn/configure">查看更多子应用配置</a></p></li></ol><h3 id="配置子应用路由"><a href="#配置子应用路由" class="headerlink" title="配置子应用路由"></a>配置子应用路由</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; createRouter, createWebHistory &#125; from &#x27;vue-router&#x27;</span><br><span class="line"></span><br><span class="line">const router = createRouter(&#123;</span><br><span class="line">  history: createWebHistory(import.meta.env.BASE_URL),</span><br><span class="line">  routes: [</span><br><span class="line">    ...,</span><br><span class="line">    &#123;</span><br><span class="line">      path: &#x27;/sub-app/*&#x27;,</span><br><span class="line">      component: () =&gt; import(&#x27;../views/SubApp.vue&#x27;)</span><br><span class="line">    &#125;,</span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">export default router</span><br></pre></td></tr></table></figure><p>path 是子应用路由地址。非严格匹配，<code>/sub-app/*</code> 都指向 <code>SubApp</code> 页面。使用 <code>vue-router@4.x</code> 时写法为：<code>&#39;/sub-app/:page*&#39;</code>。</p><h2 id="Vue2-Webpack-子应用"><a href="#Vue2-Webpack-子应用" class="headerlink" title="Vue2 + Webpack 子应用"></a>Vue2 + Webpack 子应用</h2><h3 id="设置基础路由"><a href="#设置基础路由" class="headerlink" title="设置基础路由"></a>设置基础路由</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const router = new VueRouter(&#123;</span><br><span class="line">  mode: &quot;history&quot;,</span><br><span class="line">  routes,</span><br><span class="line">  base: window.__MICRO_APP_BASE_ROUTE__ || process.env.BASE_URL,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="配置跨域支持"><a href="#配置跨域支持" class="headerlink" title="配置跨域支持"></a>配置跨域支持</h3><p>修改 <code>vue.config.js</code> 配置跨域支持。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const &#123; defineConfig &#125; = require(&quot;@vue/cli-service&quot;);</span><br><span class="line"></span><br><span class="line">module.exports = defineConfig(&#123;</span><br><span class="line">  ...,</span><br><span class="line">  devServer: &#123;</span><br><span class="line">    headers: &#123;</span><br><span class="line">      &quot;Access-Control-Allow-Origin&quot;: &quot;*&quot;,</span><br><span class="line">    &#125;,</span><br><span class="line">    ...,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="Vue3-Vite-子应用"><a href="#Vue3-Vite-子应用" class="headerlink" title="Vue3 + Vite 子应用"></a>Vue3 + Vite 子应用</h2><p>在嵌入 <code>Vite</code> 子应用时，<code>micro-app</code> 的功能只负责渲染，其它的行为由应用自行决定，这包括如何防止样式、JavaScript 变量、元素的冲突。</p><h3 id="子应用的修改"><a href="#子应用的修改" class="headerlink" title="子应用的修改"></a>子应用的修改</h3><h4 id="1-添加自定义插件"><a href="#1-添加自定义插件" class="headerlink" title="1.      添加自定义插件"></a>1.      添加自定义插件</h4><p>（1）新建插件 <code>vite-plugin-micro-app.js</code></p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import fs from &#x27;fs&#x27;</span><br><span class="line">import path from &#x27;path&#x27;</span><br><span class="line"></span><br><span class="line">function VitePluginMicroApp() &#123;</span><br><span class="line">  let basePath = &#x27;&#x27;</span><br><span class="line">  return &#123;</span><br><span class="line">    name: &#x27;vite:micro-app&#x27;,</span><br><span class="line">    apply: &#x27;build&#x27;,</span><br><span class="line">    configResolved(config) &#123;</span><br><span class="line">      basePath = `$&#123;config.base&#125;$&#123;config.build.assetsDir&#125;/`</span><br><span class="line">    &#125;,</span><br><span class="line">    writeBundle(options, bundle) &#123;</span><br><span class="line">      for (const chunkName in bundle) &#123;</span><br><span class="line">        if (!Object.prototype.hasOwnProperty.call(bundle, chunkName)) &#123;</span><br><span class="line">          continue</span><br><span class="line">        &#125;</span><br><span class="line">        const chunk = bundle[chunkName]</span><br><span class="line">        if (!chunk.fileName?.endsWith(&#x27;.js&#x27;) &amp;&amp; !chunk.fileName?.endsWith(&#x27;.ts&#x27;)) &#123;</span><br><span class="line">          continue</span><br><span class="line">        &#125;</span><br><span class="line">        chunk.code = chunk.code.replace(/(from|import\()(\s*[&#x27;&quot;])(\.\.?\/)/g, (all, $1, $2, $3) =&gt;</span><br><span class="line">          all.replace($3, new URL($3, basePath))</span><br><span class="line">        )</span><br><span class="line">        const fullPath = path.join(options.dir, chunk.fileName)</span><br><span class="line">        fs.writeFileSync(fullPath, chunk.code)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export default VitePluginMicroApp</span><br></pre></td></tr></table></figure><p>（2）导入插件并配置公共资源基础路径</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import microAppPlugin from &#x27;./vite-plugin-micro-app&#x27;</span><br><span class="line"></span><br><span class="line">export default defineConfig(&#123;</span><br><span class="line">  ...,</span><br><span class="line">  base: &#x27;/vue3-app/&#x27;,</span><br><span class="line">  plugins: [vue(), microAppPlugin()],</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h4 id="2-修改容器元素-id"><a href="#2-修改容器元素-id" class="headerlink" title="2.      修改容器元素 id"></a>2.      修改容器元素 id</h4><p>（1）修改 <code>index.html</code> 中容器元素的 id 值</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;body&gt;</span><br><span class="line">  &lt;div id=&quot;my-vite-app&quot;&gt;&lt;/div&gt;</span><br><span class="line">&lt;/body&gt;</span><br></pre></td></tr></table></figure><p>（2）使用新的 id 渲染</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">createApp(App).mount(&#x27;#my-vite-app&#x27;)</span><br></pre></td></tr></table></figure><p>当多个vite子应用同时渲染时，必须修改容器元素的id值，确保每个子应用容器元素id的唯一性，否则无法正常渲染。</p><h4 id="3-路由"><a href="#3-路由" class="headerlink" title="3.      路由"></a>3.      路由</h4><p>推荐基座使用 <code>history</code> 路由，Vite 子应用使用 hash 路由，避免一些可能出现的问题。</p><p>子应用如果是 Vue3，在初始化时路由时，<code>createWebHashHistory</code> 不要传入参数，如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const router = createRouter(&#123;</span><br><span class="line">  ...,</span><br><span class="line">  history: createWebHashHistory(),</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h4 id="4-静态资源"><a href="#4-静态资源" class="headerlink" title="4.      静态资源"></a>4.      静态资源</h4><p>图片等静态资源需要使用绝对地址，可以使用 <code>new URL(&#39;../assets/logo.png&#39;, import.meta.url).href</code> 等方式获取资源的全链接地址。</p><h3 id="主应用的修改"><a href="#主应用的修改" class="headerlink" title="主应用的修改"></a>主应用的修改</h3><h4 id="1-关闭沙箱并使用内联-script-模式"><a href="#1-关闭沙箱并使用内联-script-模式" class="headerlink" title="1.      关闭沙箱并使用内联 script 模式"></a>1.      关闭沙箱并使用内联 script 模式</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;micro-app</span><br><span class="line">  name=&#x27;child-name&#x27;</span><br><span class="line">  url=&#x27;http://localhost:3001/basename/&#x27;</span><br><span class="line">  disableSandbox // 关闭沙箱</span><br><span class="line">  inline // 使用内联script模式</span><br><span class="line">&gt;</span><br></pre></td></tr></table></figure><h4 id="2-处理子应用静态资源"><a href="#2-处理子应用静态资源" class="headerlink" title="2.      处理子应用静态资源"></a>2.      处理子应用静态资源</h4><p>写一个简易的插件，对开发环境的子应用进行处理，补全静态资源路径。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">microApp.start(&#123;</span><br><span class="line">  plugins: &#123;</span><br><span class="line">    modules: &#123;</span><br><span class="line">      // appName 即子应用的 name</span><br><span class="line">      appName: [&#123;</span><br><span class="line">        loader(code) &#123;</span><br><span class="line">          if (import.meta.env.MODE !== &#x27;development&#x27;) &#123;</span><br><span class="line">            return code</span><br><span class="line">          &#125;</span><br><span class="line">          // 这里 basename 需要和子应用vite.config.js中base的配置保持一致</span><br><span class="line">          code = code.replace(/(from|import)(\s*[&#x27;&quot;])(\/basename\/)/g, all =&gt; &#123;</span><br><span class="line">            return all.replace(&#x27;/basename/&#x27;, &#x27;子应用域名/basename/&#x27;)</span><br><span class="line">          &#125;)</span><br><span class="line">          return code</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="React-子应用"><a href="#React-子应用" class="headerlink" title="React 子应用"></a>React 子应用</h2><h3 id="设置基础路由-1"><a href="#设置基础路由-1" class="headerlink" title="设置基础路由"></a>设置基础路由</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">ReactDOM.render(</span><br><span class="line">  &lt;React.StrictMode&gt;</span><br><span class="line">    &lt;BrowserRouter basename=&#123;window.__MICRO_APP_BASE_ROUTE__ || &quot;/&quot;&#125;&gt;</span><br><span class="line">      &lt;App /&gt;</span><br><span class="line">    &lt;/BrowserRouter&gt;</span><br><span class="line">  &lt;/React.StrictMode&gt;,</span><br><span class="line">  document.getElementById(&quot;root&quot;)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3 id="配置跨域支持-1"><a href="#配置跨域支持-1" class="headerlink" title="配置跨域支持"></a>配置跨域支持</h3><h4 id="1-安装-react-app-rewired-customize-cra-依赖"><a href="#1-安装-react-app-rewired-customize-cra-依赖" class="headerlink" title="1.      安装 react-app-rewired customize-cra 依赖"></a>1.      安装 <code>react-app-rewired customize-cra</code> 依赖</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">yarn add -D react-app-rewired customize-cra</span><br><span class="line"></span><br><span class="line">pnpm add -D react-app-rewired customize-cra</span><br><span class="line"></span><br><span class="line">npm i -D react-app-rewired customize-cra</span><br></pre></td></tr></table></figure><h4 id="2-应用根目录添加-config-overrides-js-文件"><a href="#2-应用根目录添加-config-overrides-js-文件" class="headerlink" title="2.      应用根目录添加 config-overrides.js 文件"></a>2.      应用根目录添加 <code>config-overrides.js</code> 文件</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const &#123; overrideDevServer &#125; = require(&quot;customize-cra&quot;);</span><br><span class="line"></span><br><span class="line">module.exports = &#123;</span><br><span class="line">  devServer: overrideDevServer((config) =&gt; (&#123;</span><br><span class="line">    ...config,</span><br><span class="line">    headers: &#123;</span><br><span class="line">      &quot;Access-Control-Allow-Origin&quot;: &quot;*&quot;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;)),</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h4 id="3-修改-package-json"><a href="#3-修改-package-json" class="headerlink" title="3.      修改 package.json"></a>3.      修改 <code>package.json</code></h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">-   &quot;start&quot;: &quot;react-scripts start&quot;,</span><br><span class="line">+   &quot;start&quot;: &quot;react-app-rewired start&quot;,</span><br><span class="line">-   &quot;build&quot;: &quot;react-scripts build&quot;,</span><br><span class="line">+   &quot;build&quot;: &quot;react-app-rewired build&quot;,</span><br></pre></td></tr></table></figure><br /><h2 id="应用间通信"><a href="#应用间通信" class="headerlink" title="应用间通信"></a>应用间通信</h2><p><code>micro-app</code> 提供了一套灵活的数据通信机制，方便主应用和子应用之间的数据传输。</p><p>正常情况下，主应用和子应用之间的通信是绑定的，主应用只能向指定的子应用发送数据，子应用只能向基座发送数据，这种方式可以有效的避免数据污染，防止多个子应用之间相互影响。</p><p>同时 <code>micro-app</code> 也提供了全局通信，方便跨应用之间的数据通信。</p><h2 id="主应用向子应用发送数据"><a href="#主应用向子应用发送数据" class="headerlink" title="主应用向子应用发送数据"></a>主应用向子应用发送数据</h2><p>主应用向子应用发送数据有两种方式。</p><h3 id="1-通过-data-属性发送数据"><a href="#1-通过-data-属性发送数据" class="headerlink" title="1.      通过 data 属性发送数据"></a>1.      通过 data 属性发送数据</h3><p>使用 <micro-app> 组件的 data 给子应用发送数据，此时只接受对象类型，数据变化时会自动重新发送。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;micro-app name=&quot;my-app&quot; url=&quot;http://localhost:8381/&quot; baseroute=&quot;/my-app&quot; :data=&quot;data&quot; /&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script setup lang=&quot;ts&quot;&gt;</span><br><span class="line">const data = &#123; msg: &#x27;通过 data 发送给子应用的数据&#x27; &#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="2-手动发送数据"><a href="#2-手动发送数据" class="headerlink" title="2.      手动发送数据"></a>2.      手动发送数据</h3><p>手动发送数据需要通过 name 指定接受数据的子应用，此值和 <micro-app> 元素中的 name 一致。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 发送数据给子应用 my-app，setData第二个参数只接受对象类型</span><br><span class="line">microApp.setData(&#x27;my-app&#x27;, &#123; msg: &#x27;手动发送给子应用的数据&#x27; &#125;)</span><br></pre></td></tr></table></figure><h2 id="子应用接收主应用发送的数据"><a href="#子应用接收主应用发送的数据" class="headerlink" title="子应用接收主应用发送的数据"></a>子应用接收主应用发送的数据</h2><p>micro-app 会向子应用注入名称为 microApp 的全局对象，子应用通过这个对象有两种方式获取来自主应用的数据。</p><h3 id="1-直接获取"><a href="#1-直接获取" class="headerlink" title="1. 直接获取"></a>1. 直接获取</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 获取主应用下发的 data 数据</span><br><span class="line">const data = window.microApp.getData()</span><br></pre></td></tr></table></figure><h3 id="2-绑定监听函数"><a href="#2-绑定监听函数" class="headerlink" title="2.      绑定监听函数"></a>2.      绑定监听函数</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">function dataListener(data) &#123;</span><br><span class="line">  console.log(&#x27;来自主应用的数据&#x27;, data)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 绑定监听函数，监听函数只有在数据变化时才会触发</span><br><span class="line"> * dataListener: 绑定函数</span><br><span class="line"> * autoTrigger: 在初次绑定监听函数时如果有缓存数据，是否需要主动触发一次，默认为 false</span><br><span class="line"> * !!!重要说明: 因为子应用是异步渲染的，而基座发送数据是同步的，</span><br><span class="line"> * 如果在子应用渲染结束前主应用发送数据，则在绑定监听函数前数据已经发送，在初始化后不会触发绑定函数，</span><br><span class="line"> * 但这个数据会放入缓存中，此时可以设置 autoTrigger 为 true 主动触发一次监听函数来获取数据。</span><br><span class="line"> */</span><br><span class="line">window.microApp.addDataListener(dataListener: Function, autoTrigger?: boolean)</span><br><span class="line"></span><br><span class="line">// 解绑监听函数</span><br><span class="line">window.microApp.removeDataListener(dataListener: Function)</span><br><span class="line"></span><br><span class="line">// 清空当前子应用的所有绑定函数(全局数据函数除外)</span><br><span class="line">window.microApp.clearDataListener()</span><br></pre></td></tr></table></figure><h2 id="子应用向主应用发送数据"><a href="#子应用向主应用发送数据" class="headerlink" title="子应用向主应用发送数据"></a>子应用向主应用发送数据</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// dispatch只接受对象作为参数</span><br><span class="line">window.microApp.dispatch(&#123; msg: &#x27;子应用发送的数据&#x27; &#125;)</span><br></pre></td></tr></table></figure><h2 id="主应用接收子应用发送的数据"><a href="#主应用接收子应用发送的数据" class="headerlink" title="主应用接收子应用发送的数据"></a>主应用接收子应用发送的数据</h2><p>主应用获取来自子应用的数据有三种方式。</p><h3 id="1-直接获取数据"><a href="#1-直接获取数据" class="headerlink" title="1.      直接获取数据"></a>1.      直接获取数据</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 获取指定子应用发送的数据</span><br><span class="line">const childData = microApp.getData(appName)</span><br></pre></td></tr></table></figure><h3 id="2-监听-datachange-事件"><a href="#2-监听-datachange-事件" class="headerlink" title="2.      监听 datachange 事件"></a>2.      监听 datachange 事件</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;micro-app name=&quot;my-app&quot; url=&quot;http://localhost:8381/&quot; baseroute=&quot;/my-app&quot; @datachange=&quot;handleDataChange&quot; /&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script setup lang=&quot;ts&quot;&gt;</span><br><span class="line">function handleDataChange(data: any) &#123;</span><br><span class="line">  console.log(data);</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="3-绑定监听函数"><a href="#3-绑定监听函数" class="headerlink" title="3.      绑定监听函数"></a>3.      绑定监听函数</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">function dataListener(data) &#123;</span><br><span class="line">  console.log(&#x27;来自子应用的数据&#x27;, data)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 绑定监听函数</span><br><span class="line"> * appName: 应用名称</span><br><span class="line"> * dataListener: 绑定函数</span><br><span class="line"> * autoTrigger: 在初次绑定监听函数时如果有缓存数据，是否需要主动触发一次，默认为false</span><br><span class="line"> */</span><br><span class="line">microApp.addDataListener(appName: string, dataListener: Function, autoTrigger?: boolean)</span><br><span class="line"></span><br><span class="line">// 解绑监听my-app子应用的函数</span><br><span class="line">microApp.removeDataListener(appName: string, dataListener: Function)</span><br><span class="line"></span><br><span class="line">// 清空所有监听appName子应用的函数</span><br><span class="line">microApp.clearDataListener(appName: string)</span><br></pre></td></tr></table></figure><h2 id="全局数据通信"><a href="#全局数据通信" class="headerlink" title="全局数据通信"></a>全局数据通信</h2><p>全局数据通信会向主应用和所有子应用发送数据，在跨应用通信的场景中适用。</p><h3 id="1-发送全局数据"><a href="#1-发送全局数据" class="headerlink" title="1.      发送全局数据"></a>1.      发送全局数据</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// setGlobalData 只接受对象作为参数</span><br><span class="line">microApp.setGlobalData(&#123; msg: &#x27;全局数据&#x27; &#125;)</span><br></pre></td></tr></table></figure><h3 id="2-获取全局数据"><a href="#2-获取全局数据" class="headerlink" title="2.      获取全局数据"></a>2.      获取全局数据</h3><p>（1）直接获取数据</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const globalData = window.microApp.getGlobalData()</span><br></pre></td></tr></table></figure><p>（2）绑定监听函数</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const dataListener = data =&gt; &#123;</span><br><span class="line">  console.log(data)</span><br><span class="line">&#125;</span><br><span class="line">microApp.addGlobalDataListener(dataListener, true)</span><br></pre></td></tr></table></figure><h2 id="关闭沙箱后的通信方式"><a href="#关闭沙箱后的通信方式" class="headerlink" title="关闭沙箱后的通信方式"></a>关闭沙箱后的通信方式</h2><p>沙箱关闭后，子应用默认的通信功能失效，此时可以通过手动注册通信对象实现一致的功能。</p><h3 id="1-注册方式：在主应用中为子应用初始化通信对象"><a href="#1-注册方式：在主应用中为子应用初始化通信对象" class="headerlink" title="1.      注册方式：在主应用中为子应用初始化通信对象"></a>1.      注册方式：在主应用中为子应用初始化通信对象</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import &#123; EventCenterForMicroApp &#125; from &#x27;@micro-zoe/micro-app&#x27;</span><br><span class="line"></span><br><span class="line">// 注意：每个子应用根据 appName 单独分配一个通信对象</span><br><span class="line">window.eventCenterForAppxx = new EventCenterForMicroApp(appName)</span><br></pre></td></tr></table></figure><h3 id="2-子应用通信方式："><a href="#2-子应用通信方式：" class="headerlink" title="2.      子应用通信方式："></a>2.      子应用通信方式：</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 直接获取数据</span><br><span class="line">const data = window.eventCenterForAppxx.getData()</span><br><span class="line"></span><br><span class="line">function dataListener(data) &#123;</span><br><span class="line">  console.log(&#x27;来自主应用的数据&#x27;, data)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 绑定监听函数</span><br><span class="line"> * dataListener: 绑定函数</span><br><span class="line"> * autoTrigger: 在初次绑定监听函数时如果有缓存数据，是否需要主动触发一次，默认为 false</span><br><span class="line"> */</span><br><span class="line">window.eventCenterForAppxx.addDataListener(dataListener: Function, autoTrigger?: boolean)</span><br><span class="line"></span><br><span class="line">// 解绑监听函数</span><br><span class="line">window.eventCenterForAppxx.removeDataListener(dataListener: Function)</span><br><span class="line"></span><br><span class="line">// 清空当前子应用的所有绑定函数(全局数据函数除外)</span><br><span class="line">window.eventCenterForAppxx.clearDataListener()</span><br><span class="line"></span><br><span class="line">// 子应用向主应用发送数据，只接受对象作为参数</span><br><span class="line">window.eventCenterForAppxx.dispatch(&#123; msg: &#x27;子应用发送的数据&#x27; &#125;)</span><br></pre></td></tr></table></figure><br /><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h2 id="1-webpack-public-path-无效，静态资源路径错误。"><a href="#1-webpack-public-path-无效，静态资源路径错误。" class="headerlink" title="1.      __webpack_public_path__ 无效，静态资源路径错误。"></a>1.      <code>__webpack_public_path__</code> 无效，静态资源路径错误。</h2><p>将 public-path.js 的导入语句放在应用入口文件的第一行。</p><h2 id="2-TypeScript-cannot-find-name-webpack-public-path-。"><a href="#2-TypeScript-cannot-find-name-webpack-public-path-。" class="headerlink" title="2.      TypeScript cannot find name __webpack_public_path__。"></a>2.      <code>TypeScript cannot find name __webpack_public_path__</code>。</h2><p>在 src 目录新增 <code>global.d.ts</code> 文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">declare let __webpack_public_path__: string;</span><br><span class="line"></span><br><span class="line">interface Window &#123;</span><br><span class="line">  __MICRO_APP_BASE_ROUTE__: string;</span><br><span class="line">  __MICRO_APP_PUBLIC_PATH__: string;</span><br><span class="line">  __MICRO_APP_ENVIRONMENT__: boolean;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-React18-子应用首次进入展示空白，再次进入正常。"><a href="#3-React18-子应用首次进入展示空白，再次进入正常。" class="headerlink" title="3.      React18 子应用首次进入展示空白，再次进入正常。"></a>3.      <code>React18</code> 子应用首次进入展示空白，再次进入正常。</h2><p>在 <code>React18</code> 项目中使用 <code>@rescripts/cli</code> 修改 Webpack 配置可能会导致 micro-app 首次进入 React18 子应用时展示空白。</p><p>将 <code>@rescripts/cli</code> 替换为 <code>react-app-rewired customize-cra</code> 即可。</p><p><code>configuration.output has an unknown property ‘jsonpFunction’.</code></p><p>将 <code>output.jsonpFunction</code> 更名为 <code>output.chunkLoadingGlobal</code>。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// jsonpFunction: `webpackJsonp_$&#123;name&#125;`,</span><br><span class="line">chunkLoadingGlobal: `webpackJsonp_$&#123;name&#125;`,</span><br></pre></td></tr></table></figure><h2 id="4-子应用内部路由跳转后无法切换到主应用或其他子应用且路由栈异常。"><a href="#4-子应用内部路由跳转后无法切换到主应用或其他子应用且路由栈异常。" class="headerlink" title="4.      子应用内部路由跳转后无法切换到主应用或其他子应用且路由栈异常。"></a>4.      子应用内部路由跳转后无法切换到主应用或其他子应用且路由栈异常。</h2><p>（1）Vue 通过路由守卫更新 state</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">router.afterEach(() =&gt; &#123;</span><br><span class="line">  // Vue2</span><br><span class="line">  Object.assign(history.state, &#123; current: location.pathname &#125;);</span><br><span class="line">  // Vue3</span><br><span class="line">  Object.assign(history.state, &#123;</span><br><span class="line">    current: history.state.current === &#x27;/&#x27; ? &#x27;/&#x27; : `$&#123;location.pathname&#125;$&#123;location.hash&#125;`</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>（2）React 通过轮询监听路由变化更新 state</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">function listenRouterChange(callback: () =&gt; void) &#123;</span><br><span class="line">  let oldHref = window.location.href;</span><br><span class="line">  const loop = () =&gt; &#123;</span><br><span class="line">    window.requestAnimationFrame(() =&gt; &#123;</span><br><span class="line">      if (window.location.href !== oldHref) &#123;</span><br><span class="line">        oldHref = window.location.href;</span><br><span class="line">        callback();</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        loop();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;;</span><br><span class="line">  loop();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">listenRouterChange(() =&gt; &#123;</span><br><span class="line">  Object.assign(window.history.state, &#123; current: window.location.pathname &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/ea44f6b1/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>微前端（single-spa）简介</title>
      <link>https://blog.helloallen.cn/28fe053e/</link>
      <guid>https://blog.helloallen.cn/28fe053e/</guid>
      <pubDate>Mon, 25 Dec 2023 23:15:18 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><code>single-spa</code>是一个用于前端微服务化的<code>JavaScript</code>前端解决方案。<code>single-spa</code>的核心就是定义了一套协议。协议包含主应用的配置信息和子应用的生命周期，通过这套协议，主应用可以方便的知道在什么情况下激活哪个子应用。</p><br /><h2 id="配置信息"><a href="#配置信息" class="headerlink" title="配置信息"></a>配置信息</h2><h2 id="1-主应用配置"><a href="#1-主应用配置" class="headerlink" title="1.      主应用配置"></a>1.      主应用配置</h2><p>在<code>single-spa</code>中的配置信息也称为：<code>Root Config</code>，如下就是具体的配置项。需要配置子应用的名称，加载方式以及加载时机。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    name: &quot;subApp1&quot;, // 子应用的名称</span><br><span class="line">    app: () =&gt; // 告诉主应用如何加载子应用的代码，</span><br><span class="line">    System.import(&quot;/a/b/subAPP/code&quot;),</span><br><span class="line">    activeWhen: &quot;/subApp1&quot;,  // 告诉主应用何时激活子应用</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>single-spa</code>提供<code>registerApplication</code>将子应用的信息注册到主应用中。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">singleSpa.registerApplication(</span><br><span class="line">&#123;</span><br><span class="line">    name: &#x27;appName&#x27;,</span><br><span class="line">    app: () =&gt; System.import(&#x27;appName&#x27;),</span><br><span class="line">    activeWhen: &#x27;/appName&#x27;,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>在上面的代码中<code>System.import</code>让人比较在意，这是什么呢？</p><p>这个问题要从主应用如何加载子应用说起，在<code>single-spa</code>中子应用要实现生命周期函数，然后导出给主应用使用。关键就是这个“导出”的实现，这涉及到JavaScript的模块化问题，即需要把子应用打包成一个包含生命周期的模块，让主应用引入。</p><h2 id="2-JavaScript的模块化，如何在页面中引入模块？"><a href="#2-JavaScript的模块化，如何在页面中引入模块？" class="headerlink" title="2.      JavaScript的模块化，如何在页面中引入模块？"></a>2.      JavaScript的模块化，如何在页面中引入模块？</h2><p>JavaScript的模块化就是将JavaScript程序拆分为可按需导入的单独模块的机制。Node.js已经提供这个能力很长时间了，还有很多的Javascript库和框架已经开始了模块的使用（例如CommonJS和基于AMD的其他模块系统 如RequireJS，以及最新的Webpack和Babel）。目前最新的浏览器也开始原生支持模块功能。</p><h3 id="（1）在-lt-script-gt-标签上添加type-“module”来实现导入导出"><a href="#（1）在-lt-script-gt-标签上添加type-“module”来实现导入导出" class="headerlink" title="（1）在&lt;script&gt;标签上添加type=“module”来实现导入导出"></a>（1）在<code>&lt;script&gt;</code>标签上添加<code>type=“module”</code>来实现导入导出</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;!doctype html&gt;</span><br><span class="line">&lt;script type=&quot;module&quot;&gt;</span><br><span class="line">    import &#123;test&#125; from &#x27;./test.js&#x27;;</span><br><span class="line">    document.body.innerHTML = test(&#x27;1111&#x27;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="（2）实现import-axios-from-‘axios’还需要借助于importmap"><a href="#（2）实现import-axios-from-‘axios’还需要借助于importmap" class="headerlink" title="（2）实现import axios from ‘axios’还需要借助于importmap"></a>（2）实现<code>import axios from ‘axios’</code>还需要借助于<code>importmap</code></h3><p>第一点虽然可以实现导入，但是每次import都要写入固定的地址，或者在不同的script中多次引入时就要重复书写，这样造成代码的冗余，所以这里可以使用importmap，使变量名和其相应的地址一一映射，允许控制js的import语句或import()表达式获取的库的url，并允许在非导入上下文中重用这个映射，这样就不用重复书写地址了。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;script type=&quot;importmap&quot;&gt;</span><br><span class="line">&#123;</span><br><span class="line">    &quot;imports&quot;:  &#123;</span><br><span class="line">        &quot;lodash&quot;: &quot;/node_modules/lodash/lodash.js&quot;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;script type=&quot;module&quot;&gt;</span><br><span class="line">    import &#123;hello&#125; from &#x27;lodash&#x27;;</span><br><span class="line">    document.body.innerHTML = hello(&#x27;John&#x27;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="（3）SystemJS"><a href="#（3）SystemJS" class="headerlink" title="（3）SystemJS"></a>（3）SystemJS</h3><p><code>import maps</code>的兼容性不好，所以想在生产环境下使用还是需要一些兼容实现方案，<code>SystemJS</code>就是解决这个问题的。</p><p><code>systemjs</code>是一个模块加载器，和<code>requirejs</code>类似，<code>systemjs</code>参考<code>import maps</code>规范实现了自己的alias（类似<code>requirejs-paths</code>或者<code>webpack alias</code>）。具体用法在下面的demo中。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;script src=&quot;https://cdn.bootcss.com/systemjs/6.2.6/system.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">// 通过systemjs来引入别的文件</span><br><span class="line">System.import(&#x27;./test.js&#x27;);</span><br><span class="line">// systemjs也支持通过下面的方式定义资源 ，用来给资源定义一个key</span><br><span class="line">&lt;script type=&quot;systemjs-importmap&quot;&gt;</span><br><span class="line">&#123;</span><br><span class="line">    &quot;imports&quot;:  &#123;</span><br><span class="line">        &quot;vue&quot;: &quot;https://cdn.bootcss.com/vue/2.6.11/vue.js&quot;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">// 直接通过名称引用</span><br><span class="line">System.import(&#x27;vue&#x27;);</span><br></pre></td></tr></table></figure><h2 id="3-总结一下single-spa是如何通过以上方法加载子应用的："><a href="#3-总结一下single-spa是如何通过以上方法加载子应用的：" class="headerlink" title="3.      总结一下single-spa是如何通过以上方法加载子应用的："></a>3.      总结一下<code>single-spa</code>是如何通过以上方法加载子应用的：</h2><p>在主应用中注册子应用的配置信息，主应用运行时根据配置信息去请求子应用的<code>manifest.json</code>配置文件，这个文件中是子应用打包出的入口js和js文件的依赖关系，主应用通过动态的构造script标签去加载这些js文件，这里就完成了其注册过程。</p><p>这样在主应用检测路由命中子应用的规则之后就会触发其渲染函数，把子应用挂载到相应的dom下。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252221306.png"></p><br /><h2 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h2><p><code>single-spa</code>的另一个关键点就是生命周期，子应用生命周期包含<code>bootstrap，mount，unmount</code>三个回调函数。主应用在管理子应用的时候，通过子应用暴露的生命周期函数来实现子应用的启动和卸载。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252222250.png"></p><ol><li><p>load：当应用匹配路由时就会加载脚本（非函数，只是一种状态）。</p></li><li><p>bootstrap：应用内容首次挂载到页面前调用。</p></li><li><p>Mount：当主应用判定需要激活这个子应用时会调用, 实现子应用的挂载、页面渲染等逻辑。</p></li><li><p>unmount：当主应用判定需要卸载这个子应用时会调用, 实现组件卸载、清理事件监听等逻辑。</p></li><li><p>unload：非必要函数，一般不使用。unload之后会重新启动bootstrap流程。</p></li></ol><br /><h2 id="缺陷"><a href="#缺陷" class="headerlink" title="缺陷"></a>缺陷</h2><p>通过以上两点的分析，大致了解了一下sing-spa的主要思想，但是single-spa毕竟是第一个微前端框架，他也有一定的缺点。</p><ol><li><p>single-spa的文档略显凌乱，概念也比较多，在初次学习时上手难度较高。</p></li><li><p>single-spa是通过js文件去加载子应用，当文件名是乱码名时，每次子应用更新，父应用要更新引入配置文件，更新多项目时比较麻烦。</p></li><li><p>single-spa本身缺少js隔离和css隔离，虽然现在已经可以引入其他的包去解决，但是并没有做到开箱即用的程度。</p></li></ol><p>所以在基本了解其思路之后，我们可以不妨看一下其他的方案比如qiankun都是如何实现和优化的。</p><br /><h2 id="实战"><a href="#实战" class="headerlink" title="实战"></a>实战</h2><ol><li><p><a href="https://zh-hans.single-spa.js.org/docs/getting-started-overview">官方文档</a></p></li><li><p><a href="https://zhuanlan.zhihu.com/p/463654743">single-spa 从入门到精通</a></p></li></ol>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/28fe053e/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>iframe 实现微前端</title>
      <link>https://blog.helloallen.cn/c99665c4/</link>
      <guid>https://blog.helloallen.cn/c99665c4/</guid>
      <pubDate>Mon, 25 Dec 2023 23:04:02 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>下面以一个实际案例来详细介绍如果通过<code>iframe</code>将一个线上在运行的系统接入到另外一个系统，实现微前端的全过程。</p><p>以笔者前段时间刚完成的ACP（全称Alibaba.com Pay，阿里巴巴国际站旗下一站式全球收款平台，下称A系统）接入生意贷（下称B系统）为例，已知：</p><ul><li><p>ACP和生意贷都是MPA页面；</p></li><li><p>ACP系统在此之前没有接入其他系统的先例，生意贷是第一个；</p></li><li><p>生意贷作为被接入系统，本次需要接入的一共有20多个页面，且服务端包含大量业务逻辑以及跳转控制，有些页面想看看长什么样子都非常困难，需要在Node层mock大量接口；</p></li><li><p>接入时需要做功能删减，部分接口入参需要调整；</p></li><li><p>生意贷除了接入到ACP系统中，之前还接入过AMES系统，本次接入需要兼容这部分历史逻辑；</p></li></ul><p>我们希望的效果：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252225782.png"></p><p>假设我们新增一个页面 <code>/fin/base.html?entry=xxx</code> 作为我们A系统承接B系统的地址，A系统有类似如下代码：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">class App extends React.Component &#123;</span><br><span class="line">    state = &#123;</span><br><span class="line">        currentEntry: decodeURIComponent(iutil.getParam(&#x27;entry&#x27;) || &#x27;&#x27;) || &#x27;&#x27;,</span><br><span class="line">    &#125;;</span><br><span class="line">    render() &#123;</span><br><span class="line">        return &lt;div&gt;</span><br><span class="line">            &lt;iframe id=&quot;microFrontIframe&quot; src=&#123;this.state.currentEntry&#125;/&gt;</span><br><span class="line">        &lt;/div&gt;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br /><h2 id="隐藏原系统导航菜单"><a href="#隐藏原系统导航菜单" class="headerlink" title="隐藏原系统导航菜单"></a>隐藏原系统导航菜单</h2><p>因为是接入到另外一个系统，所以需要将原系统的菜单和导航等都通过一个类似<code>hideLayout</code>的参数去隐藏。</p><br /><h2 id="前进后退处理"><a href="#前进后退处理" class="headerlink" title="前进后退处理"></a>前进后退处理</h2><p>需要特别注意的是，iframe页面内部的跳转虽然不会让浏览器地址栏发生变化，但是却会产生一个看不见的<code>history记录</code>，也就是点击前进或后退按钮（<code>history.forward()</code>或<code>history.back()</code>）可以让iframe页面也前进后退，但是地址栏无任何变化。</p><p>所以准确来说前进后退无需我们做任何处理，我们要做的就是让浏览器地址栏同步更新即可。</p><p>如果要禁用浏览器的上述默认行为，一般只能在iframe跳转时通知父页面更新整个<code>&lt;iframe /&gt;</code>DOM节点。</p><br /><h2 id="URL的同步更新"><a href="#URL的同步更新" class="headerlink" title="URL的同步更新"></a>URL的同步更新</h2><p>让URL同步更新需要处理2个问题，一个是什么时候去触发更新的动作，一个是URL更新的规律，即父页面的URL地址（A系统）与iframe的URL地址（B系统）映射关系的维护。</p><p>保证URL同步更新功能正常需要满足这3种情况：</p><ul><li><p>case1: 页面刷新，iframe能够加载正确页面；</p></li><li><p>case2: 页面跳转，浏览器地址栏能够正确更新；</p></li><li><p>case3: 点击浏览器的前进或后退，地址栏和iframe都能够同步变化；</p></li></ul><h2 id="1-什么时候更新URL地址"><a href="#1-什么时候更新URL地址" class="headerlink" title="1.什么时候更新URL地址"></a>1.什么时候更新URL地址</h2><p>首先想到的肯定是在iframe加载完发送一个通知给父页面，父页面通过<code>history.replaceState</code>去更新URL。</p><p>为什么不是<code>history.pushState</code>呢？因为前面提到过，浏览器默认会产生一条历史记录，我们只需要更新地址即可，如果用pushState会产生2条记录。</p><p>B系统：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line">var postMessage = function(type, data) &#123;</span><br><span class="line">    if (window.parent !== window) &#123;</span><br><span class="line">        window.parent.postMessage(&#123;</span><br><span class="line">            type: type,</span><br><span class="line">            data: data,</span><br><span class="line">        &#125;, &#x27;*&#x27;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">// 为了让URL地址尽早地更新，这段代码需要尽可能前置，例如可以直接放在document.head中</span><br><span class="line">postMessage(&#x27;afterHistoryChange&#x27;, &#123; url: location.href &#125;);</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>A系统：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">window.addEventListener(&#x27;message&#x27;, e =&gt; &#123;</span><br><span class="line">    const &#123; data, type &#125; = e.data || &#123;&#125;;</span><br><span class="line">    if (type === &#x27;afterHistoryChange&#x27; &amp;&amp; data?.url) &#123;</span><br><span class="line">        // 这里先采用一个兜底的URL承接任意地址</span><br><span class="line">        const entry = `/fin/base.html?entry=$&#123;encodeURIComponent(data.url)&#125;`;</span><br><span class="line">        // 地址不一样才需要更新</span><br><span class="line">        if (location.pathname + location.search !== entry) &#123;</span><br><span class="line">            window.history.replaceState(null, &#x27;&#x27;, entry);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="2-优化URL的更新速度"><a href="#2-优化URL的更新速度" class="headerlink" title="2.      优化URL的更新速度"></a>2.      优化URL的更新速度</h2><p>按照上面的方法实现后可以发现，URL虽然可以更新但是速度有点慢，点击跳转后一般需要等待7-800毫秒地址栏才会更新，有点美中不足。可以把地址栏的更新在“跳转后”基础之上再加一个“跳转前”。为此我们必须有一个全局的<code>beforeRedirect</code>钩子，先不考虑它的具体实现：</p><p>B系统：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">function beforeRedirect(href) &#123;</span><br><span class="line">    postMessage(&#x27;beforeHistoryChange&#x27;, &#123; url: href &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>A系统：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">window.addEventListener(&#x27;message&#x27;, e =&gt; &#123;</span><br><span class="line">    const &#123; data, type &#125; = e.data || &#123;&#125;;</span><br><span class="line">    if ((type === &#x27;beforeHistoryChange&#x27; || type === &#x27;afterHistoryChange&#x27;) &amp;&amp; data?.url) &#123;</span><br><span class="line">        // 这里先采用一个兜底的URL承接任意地址</span><br><span class="line">        const entry = `/fin/base.html?entry=$&#123;encodeURIComponent(data.url)&#125;`;</span><br><span class="line">        // 地址不一样才需要更新</span><br><span class="line">        if (location.pathname + location.search !== entry) &#123;</span><br><span class="line">            window.history.replaceState(null, &#x27;&#x27;, entry);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>加上上述代码之后，点击iframe中的跳转链接，URL会实时更新，浏览器的前进后退功能也正常。</p><p>为什么需要同时保留跳转前和跳转后呢？因为如果只保留跳转前，只能满足前面的case1和case2，case3无法满足，也就是点击后退按钮只有iframe会后退，URL地址不会更新。</p><h2 id="3-美化URL地址"><a href="#3-美化URL地址" class="headerlink" title="3.      美化URL地址"></a>3.      美化URL地址</h2><p>简单的使用<code>/fin/base.html?entry=xxx</code>这样的通用地址虽然能用，但是不太美观，而且很容易被人看出来是iframe实现的，比较没有诚意，所以如果被接入系统的页面数量在可枚举范围内，建议给每个地址维护一个新的短地址。</p><p>首先，新增一个SPA页面<code>/fin/*.html</code>，和前面的<code>/fin/base.html</code>指向同一个页面，然后维护一个URL地址的映射，类似这样：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// A系统地址到B系统地址映射</span><br><span class="line">const entryMap = &#123;</span><br><span class="line">    &#x27;/fin/home.html&#x27;: &#x27;https://fs.alibaba.com/xxx/home.htm?hideLayout=1&#x27;,</span><br><span class="line">    &#x27;/fin/apply.html&#x27;: &#x27;https://fs.alibaba.com/xxx/apply?hideLayout=1&#x27;,</span><br><span class="line">    &#x27;/fin/failed.html&#x27;: &#x27;https://fs.aibaba.com/xxx/failed?hideLayout=1&#x27;,</span><br><span class="line">    // 省略</span><br><span class="line">&#125;;</span><br><span class="line">const iframeMap = &#123;&#125;; // 同时再维护一个子页面 -&gt; 父页面URL映射</span><br><span class="line">for (const entry in entryMap) &#123;</span><br><span class="line">    iframeMap[entryMap[entry].split(&#x27;?&#x27;)[0]] = entry;</span><br><span class="line">&#125;</span><br><span class="line">class App extends React.Component &#123;</span><br><span class="line">    state = &#123;</span><br><span class="line">        currentEntry: decodeURIComponent(iutil.getParam(&#x27;entry&#x27;) || &#x27;&#x27;) || entryMap[location.pathname] || &#x27;&#x27;,</span><br><span class="line">    &#125;;</span><br><span class="line">    render() &#123;</span><br><span class="line">        return &lt;div&gt;</span><br><span class="line">            &lt;iframe id=&quot;microFrontIframe&quot; src=&#123;this.state.currentEntry&#125;/&gt;</span><br><span class="line">        &lt;/div&gt;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同时完善一下更新URL地址部分：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// base.html继续用作兜底</span><br><span class="line">let entry = `/fin/base.html?entry=$&#123;encodeURIComponent(data.url)&#125;`;</span><br><span class="line">const [path, search] = data.url.split(&#x27;?&#x27;);</span><br><span class="line">if (iframeMap[path]) &#123;</span><br><span class="line">    entry = `$&#123;iframeMap[path]&#125;?$&#123;search || &#x27;&#x27;&#125;`;</span><br><span class="line">&#125;</span><br><span class="line">// 地址不一样才需要更新</span><br><span class="line">if (location.pathname + location.search !== entry) &#123;</span><br><span class="line">    window.history.replaceState(null, &#x27;&#x27;, entry);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>省略参数透传部分代码。</p><br /><h2 id="全局跳转拦截"><a href="#全局跳转拦截" class="headerlink" title="全局跳转拦截"></a>全局跳转拦截</h2><p>为什么一定要做全局跳转拦截呢？一个因为我们需要把<code>hideLayout</code>参数一直透传下去，否则就会点着点着突然出现下面这种双菜单的情况：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252226881.png"></p><p>另一个是有些页面在被嵌入前是当前页面打开的，但是被嵌入后不能继续在当前iframe打开，比如支付宝付款这种第三方页面，想象一下下面这种情况会不会觉得很怪？所以这类页面一定要做特殊处理让它跳出去而不是当前页面打开。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252227385.png"></p><p>URL跳转可以分为服务端跳转和浏览器跳转，浏览器跳转又包括<code>a标签</code>跳转、<code>location.href</code>跳转、<code>window.open</code>跳转、<code>historyAPI</code>跳转等；</p><p>而根据是否新标签打开又可以分为以下4种场景：</p><p>a. 继续当前iframe打开，需要隐藏原系统的所有layout；</p><p>b. 当前父页面打开第三方页面，不需要任何layout；</p><p>c. 新开标签打开第三方页面（如支付宝页面），不需要做特殊处理；</p><p>d. 新开标签打开宿主页面，需要把原系统layout替换成新layout；</p><p>为此，先定义好一个<code>beforeRedirect</code>方法，由于新标签打开有<code>target=&quot;_blank&quot;</code>和<code>window.open</code>等方式，父页面打开有<code>target=&quot;_parent&quot;</code>和<code>window.parent.location.href</code>等方式，为了更好的统一封装，我们把特殊情况的跳转统一在<code>beforeRedirect</code>处理好，并约定只有有返回值的情况才需要后续继续处理跳转：</p><figure class="highlight plaintext"><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><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">// 维护一个需要做特殊处理的第三方页面列表</span><br><span class="line">const thirdPageList = [</span><br><span class="line">    &#x27;https://service.alibaba.com/&#x27;,</span><br><span class="line">    &#x27;https://sale.alibaba.com/xxx/&#x27;,</span><br><span class="line">    &#x27;https://alipay.com/xxx/&#x27;,</span><br><span class="line">    // ...</span><br><span class="line">];</span><br><span class="line">/**</span><br><span class="line"> * 封装统一的跳转拦截钩子，处理参数透传和一些特殊情况</span><br><span class="line"> * @param &#123;*&#125; href 要跳转的地址，允许传入相对路径</span><br><span class="line"> * @param &#123;*&#125; isNewTab 是否要新标签打开</span><br><span class="line"> * @param &#123;*&#125; isParentOpen 是否要在父页面打开</span><br><span class="line"> * @returns 返回处理好的跳转地址，如果没有返回值则表示不需要继续处理跳转</span><br><span class="line"> */</span><br><span class="line">function beforeRedirect(href, isNewTab) &#123;</span><br><span class="line">    if (!href) &#123;</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    // 传过来的href可能是相对路径，为了做统一判断需要转成绝对路径</span><br><span class="line">    if (href.indexOf(&#x27;http&#x27;) !== 0) &#123;</span><br><span class="line">        var a = document.createElement(&#x27;a&#x27;);</span><br><span class="line">        a.href = href;</span><br><span class="line">        href = a.href;</span><br><span class="line">    &#125;</span><br><span class="line">    // 如果命中白名单</span><br><span class="line">    if (thirdPageList.some(item =&gt; href.indexOf(item) === 0)) &#123;</span><br><span class="line">        if (isNewTab) &#123;</span><br><span class="line">            // _rawOpen参见后面 window.open 拦截</span><br><span class="line">            window._rawOpen(href);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            // 第三方页面如果不是新标签打开就一定是父页面打开</span><br><span class="line">            window.parent.location.href = href;</span><br><span class="line">        &#125;</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    // 需要从当前URL继续往下透传的参数</span><br><span class="line">    var params = [&#x27;hideLayout&#x27;, &#x27;tracelog&#x27;];</span><br><span class="line">    for (var i = 0; i &lt; params.length; i++) &#123;</span><br><span class="line">        var value = getParam(params[i], location.href);</span><br><span class="line">        if (value) &#123;</span><br><span class="line">            href = setParam(params[i], value, href);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    if (isNewTab) &#123;</span><br><span class="line">        let entry = `/fin/base.html?entry=$&#123;encodeURIComponent(href)&#125;`;</span><br><span class="line">        const [path, search] = href.split(&#x27;?&#x27;);</span><br><span class="line">        if (iframeMap[path]) &#123;</span><br><span class="line">            entry = `$&#123;iframeMap[path]&#125;?$&#123;search || &#x27;&#x27;&#125;`;</span><br><span class="line">        &#125;</span><br><span class="line">        href = `https://payment.alibaba.com$&#123;entry&#125;`;</span><br><span class="line">        window._rawOpen(href);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    // 如果是以iframe方式嵌入，向父页面发送通知</span><br><span class="line">    postMessage(&#x27;beforeHistoryChange&#x27;, &#123; url: href &#125;);</span><br><span class="line">    return href;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="1-服务端跳转拦截"><a href="#1-服务端跳转拦截" class="headerlink" title="1.      服务端跳转拦截"></a>1.      服务端跳转拦截</h2><p>服务端主要是对301或302重定向跳转进行拦截，以Egg为例，只要重写 <code>ctx.redirect</code> 方法即可。</p><h2 id="2-a标签跳转拦截"><a href="#2-a标签跳转拦截" class="headerlink" title="2.      a标签跳转拦截"></a>2.      a标签跳转拦截</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">document.addEventListener(&#x27;click&#x27;, function (e) &#123;</span><br><span class="line">    var target = e.target || &#123;&#125;;</span><br><span class="line">    // A标签可能包含子元素，点击目标可能不是A标签本身，这里只简单判断2层</span><br><span class="line">    if (target.tagName === &#x27;A&#x27; || (target.parentNode &amp;&amp; target.parentNode.tagName === &#x27;A&#x27;)) &#123;</span><br><span class="line">        target = target.tagName === &#x27;A&#x27; ? target : target.parentNode;</span><br><span class="line">        var href = target.href;</span><br><span class="line">        // 不处理没有配置href或者指向JS代码的A标签</span><br><span class="line">        if (!href || href.indexOf(&#x27;javascript&#x27;) === 0) &#123;</span><br><span class="line">            return;</span><br><span class="line">        &#125;</span><br><span class="line">        var newHref = beforeRedirect(href, target.target === &#x27;_blank&#x27;);</span><br><span class="line">        // 没有返回值一般是已经处理了跳转，需要禁用当前A标签的跳转</span><br><span class="line">        if (!newHref) &#123;</span><br><span class="line">            target.target = &#x27;_self&#x27;;</span><br><span class="line">            target.href = &#x27;javascript:;&#x27;;</span><br><span class="line">        &#125; else if (newHref !== href) &#123;</span><br><span class="line">            target.href = newHref;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;, true);</span><br></pre></td></tr></table></figure><h2 id="3-location-href拦截"><a href="#3-location-href拦截" class="headerlink" title="3.      location.href拦截"></a>3.      location.href拦截</h2><p><code>location.href</code>拦截至今是一个困扰前端界的难题，这里只能采用一个折中的方法：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 由于 location.href 无法重写，只能实现一个 location2.href = &#x27;&#x27;</span><br><span class="line">if (Object.defineProperty) &#123;</span><br><span class="line">    window.location2 = &#123;&#125;;</span><br><span class="line">    Object.defineProperty(window.location2, &#x27;href&#x27;, &#123;</span><br><span class="line">        get: function() &#123;</span><br><span class="line">            return location.href;</span><br><span class="line">        &#125;,</span><br><span class="line">        set: function(href) &#123;</span><br><span class="line">            var newHref = beforeRedirect(href);</span><br><span class="line">            if (newHref) &#123;</span><br><span class="line">                location.href = newHref;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因为我们不仅实现了<code>location.href</code>的写，<code>location.href</code>的读也一起实现了，所以可以放心大胆的进行全局替换。找到对应前端工程，首先全局搜索<code>window.location.href</code>，批量替换成<code>(window.location2 || window.location).href</code>，然后再全局搜索<code>location.href</code>，批量替换成<code>(window.location2 || window.location).href</code>（思考一下为什么一定是这个顺序呢）。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252228911.png"></p><p>另外需要注意，有些跳转可能是写在npm包里面的，这种情况只能npm也跟着替换一下了，并没有其它更好办法。</p><h2 id="4-window-open拦截"><a href="#4-window-open拦截" class="headerlink" title="4.      window.open拦截"></a>4.      window.open拦截</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">var tempOpenName = &#x27;_rawOpen&#x27;;</span><br><span class="line">if (!window[tempOpenName]) &#123;</span><br><span class="line">    window[tempOpenName] = window.open;</span><br><span class="line">    window.open = function(url, name, features) &#123;</span><br><span class="line">        url = beforeRedirect(url, true);</span><br><span class="line">        if (url) &#123;</span><br><span class="line">            window[tempOpenName](url, name, features);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="5-history-pushState拦截"><a href="#5-history-pushState拦截" class="headerlink" title="5.      history.pushState拦截"></a>5.      history.pushState拦截</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">var tempName = &#x27;_rawPushState&#x27;;</span><br><span class="line">if (!window.history[tempName]) &#123;</span><br><span class="line">    window.history[tempName] = window.history.pushState;</span><br><span class="line">    window.history.pushState = function(state, title, url) &#123;</span><br><span class="line">        url = beforeRedirect(url);</span><br><span class="line">        if (url) &#123;</span><br><span class="line">            window.history[tempName](state, title, url);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="6-history-replaceState拦截"><a href="#6-history-replaceState拦截" class="headerlink" title="6.      history.replaceState拦截"></a>6.      history.replaceState拦截</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">var tempName = &#x27;_rawReplaceState&#x27;;</span><br><span class="line">if (!window.history[tempName]) &#123;</span><br><span class="line">    window.history[tempName] = window.history.replaceState;</span><br><span class="line">    window.history.replaceState = function(state, title, url) &#123;</span><br><span class="line">        url = beforeRedirect(url);</span><br><span class="line">        if (url) &#123;</span><br><span class="line">            window.history[tempName](state, title, url);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br /><h2 id="全局loading处理"><a href="#全局loading处理" class="headerlink" title="全局loading处理"></a>全局loading处理</h2><p>完成上述步骤后，基本上已经看不出来是iframe了，但是跳转的时候中间有短暂的白屏会有一点顿挫感，体验不算很流畅，这时候可以给iframe加一个全局的loading，开始跳转前显示，页面加载完再隐藏：</p><p>B系统：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">document.addEventListener(&#x27;DOMContentLoaded&#x27;, function (e) &#123;</span><br><span class="line">    postMessage(&#x27;iframeDOMContentLoaded&#x27;, &#123; url: location.href &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>A系统：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">window.addEventListener(&#x27;message&#x27;, (e) =&gt; &#123;</span><br><span class="line">    const &#123; data, type &#125; = e.data || &#123;&#125;;</span><br><span class="line">    // iframe 加载完毕</span><br><span class="line">    if (type === &#x27;iframeDOMContentLoaded&#x27;) &#123;</span><br><span class="line">        this.setState(&#123;loading: false&#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    if (type === &#x27;beforeHistoryChange&#x27;) &#123;</span><br><span class="line">        // 此时页面并没有立即跳转，需要再稍微等待一下再显示loading</span><br><span class="line">        setTimeout(() =&gt; this.setState(&#123;loading: true&#125;), 100);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>除此之外还需要利用iframe自带的onload加一个兜底，防止iframe页面没有上报 <code>iframeDOMContentLoaded</code> 事件导致loading不消失：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// iframe自带的onload做兜底</span><br><span class="line">iframeOnLoad = () =&gt; &#123;</span><br><span class="line">    this.setState(&#123;loading: false&#125;);</span><br><span class="line">&#125;</span><br><span class="line">render() &#123;</span><br><span class="line">    return &lt;div&gt;</span><br><span class="line">        &lt;Loading visible=&#123;this.state.loading&#125; tip=&quot;正在加载...&quot; inline=&#123;false&#125;&gt;</span><br><span class="line">            &lt;iframe id=&quot;microFrontIframe&quot; src=&#123;this.state.currentEntry&#125; onLoad=&#123;this.iframeOnLoad&#125;/&gt;</span><br><span class="line">        &lt;/Loading&gt;</span><br><span class="line">    &lt;/div&gt;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还需要注意，当新标签页打开页面时并不需要显示loading，需要注意区分。</p><br /><h2 id="弹窗居中问题"><a href="#弹窗居中问题" class="headerlink" title="弹窗居中问题"></a>弹窗居中问题</h2><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252229409.png"></p><p>当前场景下弹窗个人觉得并不需要处理，因为菜单的宽度有限，不仔细看的话甚至都没注意到弹窗没有居中：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252230745.png"></p><p>如果非要处理的话也不麻烦，覆盖一下原来页面弹窗的样式，当包含<code>hideLayout</code>参数时，让弹窗的位置分别向左移动<code>menuWidth/2</code>、向上移动<code>navbarHeight/2</code>即可（遮罩位置不能动、也动不了）。<br>添加了<code>marginLeft=-120px</code>、<code>marginTop=-30px</code> 后的弹窗效果：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252230012.png"></p><br /><h2 id="最终效果"><a href="#最终效果" class="headerlink" title="最终效果"></a>最终效果</h2><p>其实不难看出，最终效果和SPA几乎无异，而且菜单和导航本来就是无刷新的，页面跳转没有割裂感：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252231935.gif"></p><br /><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>上述方案有几个没有提到的点：</p><ul><li>方案成立的前提是建立在2个系统共用一套用户体系，否则需要对2个系统的登录体系进行打通，一般包括账号绑定、A系统默认免登B系统，等等，这需要一定额外的工作量；</li><li>参数的透传与删除，例如我希望除了hideLayout参数之外其它URL参数全部在父子页面之间透传；</li><li>埋点，数据上报的时候需要增加一个额外参数来标识流量来自另外一个系统；</li></ul><p>在第一次摸索方案时可能需要花费一些时间，但是在熟悉之后，如果后续还有类似把B系统接入A系统的需求，在没有特殊情况且顺利的前提下可能花费1-2天时间即可完成，最重要的是大部分工作都是全局生效的，不会随着页面的增多而导致工作量增加，测试回归的成本也非常低，只需要验证所有页面跳转、展示等是否正常，功能本身一般不会有太大问题，而如果是微前端方案的话需要从头到尾全部仔仔细细测试一遍，开发和测试的成本都不可估量。</p><p>作者：阿里巴巴终端技术<br>链接：<a href="https://juejin.cn/post/7185070739064619068">https://juejin.cn/post/7185070739064619068</a><br>来源：稀土掘金<br>著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/c99665c4/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>微前端父子应用css命名冲突的解决方案</title>
      <link>https://blog.helloallen.cn/57769d31/</link>
      <guid>https://blog.helloallen.cn/57769d31/</guid>
      <pubDate>Mon, 25 Dec 2023 22:56:59 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h2><p>微前端项目集成子应用过程中，往往会遇到css命名冲突，样式污染问题。</p><p>例如<code>qiankun</code>框架支持沙箱css，可以开启<code>strictStyleIsolation</code>等解决方案。</p><p>也可以在项目开发时约定各自的前缀，<code>vue style scoped</code> 样式作用域等避免样式污染。</p><p>但很多项目的UI库用的是<code>element-plus</code>或<code>element-ui</code>，大版本都不一致，就必须做样式隔离。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312252240008.png"></p><p>这里采用<code>PostCSS</code>的 <code>postcss-namespace</code> 插件，简单实现添加前缀的方式，支持<code>webpack</code>和<code>vite</code>构建，方法都一样。</p><br /><h2 id="效果示例"><a href="#效果示例" class="headerlink" title="效果示例"></a>效果示例</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 转换前</span><br><span class="line">h1, .h1 &#123;</span><br><span class="line">  font-weight: bold;</span><br><span class="line">&#125;</span><br><span class="line">@media screen and (max-width: 500px) &#123;</span><br><span class="line">    h1 &#123;</span><br><span class="line">      font-size: 24px;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 转换后</span><br><span class="line">.global-css h1, .global-css .h1 &#123;</span><br><span class="line">  font-weight: bold;</span><br><span class="line">&#125;</span><br><span class="line">@media screen and (max-width: 500px) &#123;</span><br><span class="line">    .global-css h1 &#123;</span><br><span class="line">      font-size: 24px;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br /><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h2 id="1-npm安装依赖包"><a href="#1-npm安装依赖包" class="headerlink" title="1.      npm安装依赖包"></a>1.      npm安装依赖包</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i -D postcss-loader postcss-selector-namespace</span><br></pre></td></tr></table></figure><h2 id="2-在项目根目录放置一个文件：postcss-config-js"><a href="#2-在项目根目录放置一个文件：postcss-config-js" class="headerlink" title="2.      在项目根目录放置一个文件：postcss.config.js "></a>2.      在项目根目录放置一个文件：<code>postcss.config.js </code></h2><p>文件内容如下：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">module.exports = &#123;</span><br><span class="line">  plugins: &#123;</span><br><span class="line">    &#x27;postcss-selector-namespace&#x27;: &#123;</span><br><span class="line">      namespace(css) &#123;</span><br><span class="line">        // 不需要添加命名空间的文件</span><br><span class="line">        if (css.includes(&#x27;unNamespace&#x27;)) return &#x27;&#x27;;</span><br><span class="line">        return &#x27;.global-css&#x27;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="3-在index-html文件，html下增加一个class"><a href="#3-在index-html文件，html下增加一个class" class="headerlink" title="3.      在index.html文件，html下增加一个class"></a>3.      在index.html文件，html下增加一个class</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;html lang=&quot;zh-CN&quot; class=&quot;global-css&quot;&gt;</span><br><span class="line">    ...</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure><br /><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h2 id="1-html-样式丢失"><a href="#1-html-样式丢失" class="headerlink" title="1.      html 样式丢失"></a>1.      html 样式丢失</h2><p>因为<code>html</code>的样式被转成 <code>.global-css html</code> 了。添加一个不需要添加前缀的文件 <code>unNamespace.less</code>，全局引入。</p><p>然后在 <code>postcss.config.js</code> 文件添加一个判断，如果css名包含 <code>unNamespace</code> 字眼，就跳过。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">if (css.includes(&#x27;unNamespace&#x27;)) return &#x27;&#x27;;</span><br></pre></td></tr></table></figure><h2 id="2-postcss-loader-安装失败，提示版本冲突"><a href="#2-postcss-loader-安装失败，提示版本冲突" class="headerlink" title="2.      postcss-loader 安装失败，提示版本冲突"></a>2.      postcss-loader 安装失败，提示版本冲突</h2><p>使用命令：<code>npm i postcss-loader --legacy-peer-deps</code> ，目的是绕过<code>peerDependency</code>， 忽略项目中引入的各个modules之间的相同modules但不同版本的问题并继续安装。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF/">微前端</category>
      
      
      <comments>https://blog.helloallen.cn/57769d31/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>使用Github Action实现全自动部署</title>
      <link>https://blog.helloallen.cn/41767f46/</link>
      <guid>https://blog.helloallen.cn/41767f46/</guid>
      <pubDate>Sun, 24 Dec 2023 23:08:58 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Github-Action简介"><a href="#Github-Action简介" class="headerlink" title="Github Action简介"></a>Github Action简介</h2><p>Github Action是 GitHub于2018年10月推出的一个CI\CD服务。</p><blockquote><p> CI\CD 其实说的是三件事情：「持续集成（Continuous Integration）」、「持续交付（Continuous Delivery）」、「持续部署（Continuous Deployment）」。因为「持续交付」和「持续部署」的英文缩写是一样的，所以这三件事情缩写成了 CI\CD 。</p></blockquote><h2 id="教程常量声明"><a href="#教程常量声明" class="headerlink" title="教程常量声明"></a>教程常量声明</h2><table><thead><tr><th>常量名</th><th>常量释义</th></tr></thead><tbody><tr><td><strong>[Blogroot]</strong></td><td>本地存放博客源码的文件夹路径</td></tr><tr><td><strong>[SourceRepo]</strong></td><td>存放博客源码的私有仓库名</td></tr><tr><td><strong>[SiteBlogRepo]</strong></td><td>存放编译好的博客页面的公有仓库名 Site指站点，教程中会替换成 Github</td></tr><tr><td><strong>[SiteUsername]</strong></td><td>用户名 Site指站点，教程中会替换成 Github</td></tr><tr><td><strong>[SiteToken]</strong></td><td>申请到的令牌码 Site指站点，教程中会替换成 Github、Gitee、Coding</td></tr><tr><td><strong>[GithubEmail]</strong></td><td>与github绑定的主邮箱，建议使用Gmail</td></tr></tbody></table><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># 在记事本中逐个记录，方便替换，以下为我的示例</span><br><span class="line">[Blogroot]：E:\Blogroot</span><br><span class="line"></span><br><span class="line">[SourceRepo]：HelloAllenW/HexoBlog</span><br><span class="line"></span><br><span class="line">[SiteBlogRepo]</span><br><span class="line">  [GithubBlogRepo]：HelloAllenW.github.io</span><br><span class="line"></span><br><span class="line">[SiteUsername]</span><br><span class="line">  [GithubUsername]：HelloAllenW</span><br><span class="line"></span><br><span class="line">[SiteToken]</span><br><span class="line">  [GithubToken]：15076c8eb9c874sad676bc9bfb13sadw86babf2</span><br><span class="line"></span><br><span class="line">[GithubEmail]：hailun081@163.com</span><br></pre></td></tr></table></figure><h2 id="Github-Action使用教程"><a href="#Github-Action使用教程" class="headerlink" title="Github Action使用教程"></a>Github Action使用教程</h2><h2 id="1-获取Token"><a href="#1-获取Token" class="headerlink" title="1. 获取Token"></a>1. 获取Token</h2><p>为了确保交由<code>Github Action</code>来持续部署时，<code>Github Action</code>具备足够的权限来进行<code>hexo deploy</code>操作，需要先获取<code>Token</code>，博主目前仅在<code>Github</code>处部署了静态页面，所以也就只需要获取<code>Github</code>的<code>Token</code>。</p><p>在主页依次选择【Settings】-【Developer settings】-【Personal access tokens】-【Tokens(classic)】-【Generate new token】- 【Generate new token(classic)】，填写好描述，勾选【repo】和【workflows】，然后点击【Generate token】生成一个Token。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312242328947.png"></p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312242329656.png"></p><blockquote><p><code>token</code>只会显示这一次，之后将无法查看，所以务必保证你已经记录下了<code>Token</code>。之后如果忘记了就只能重新生成重新配置了。</p></blockquote><h2 id="2-创建存放源码的私有仓库"><a href="#2-创建存放源码的私有仓库" class="headerlink" title="2. 创建存放源码的私有仓库"></a>2. 创建存放源码的私有仓库</h2><p>我们需要创建一个用来存放<code>Hexo</code>博客源码的私有仓库<code>[SourceRepo]</code>。创建完成后，需要把博客的源码<code>push</code>到这里。首先获取远程仓库地址，此处虽然<code>SSH</code>和<code>HTTPS</code>均可。<code>SSH</code>在绑定过<code>ssh key</code>的设备上无需再输入密码，<code>HTTPS</code>则需要输入密码，但是<code>SSH</code>偶尔会遇到端口占用的情况。请自主选择。</p><blockquote><p>这里之所以是私有仓库，是因为在接下来的配置中会用到<code>Token</code>，如果<code>Token</code>被盗用，别人可以肆意操作你的github仓库内容，为了避免这一风险，才选择的博客源码闭源。</p></blockquote><h2 id="3-配置Github-Action"><a href="#3-配置Github-Action" class="headerlink" title="3. 配置Github Action"></a>3. 配置Github Action</h2><p>（1）在<code>[Blogroot]</code>新建<code>.github</code>文件夹,注意开头是有个<code>.</code>的。然后在<code>.github</code>内新建<code>workflows</code>文件夹，再在<code>workflows</code>文件夹内新建<code>autodeploy.yml</code>,在<code>[Blogroot]/.github/workflows/autodeploy.yml</code>里面输入</p><figure class="highlight plaintext"><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><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"># 当有改动推送到master分支时，启动Action</span><br><span class="line">name: 自动部署</span><br><span class="line"></span><br><span class="line">on:</span><br><span class="line">  push:</span><br><span class="line">    branches:</span><br><span class="line">      - master #2020年10月后github新建仓库默认分支改为main，注意更改</span><br><span class="line"></span><br><span class="line">  release:</span><br><span class="line">    types:</span><br><span class="line">      - published</span><br><span class="line"></span><br><span class="line">jobs:</span><br><span class="line">  deploy:</span><br><span class="line">    runs-on: ubuntu-latest</span><br><span class="line">    steps:</span><br><span class="line">    - name: 检查分支</span><br><span class="line">      uses: actions/checkout@v2</span><br><span class="line">      with:</span><br><span class="line">        ref: master #2020年10月后github新建仓库默认分支改为main，注意更改</span><br><span class="line"></span><br><span class="line">    - name: 安装 Node</span><br><span class="line">      uses: actions/setup-node@v1</span><br><span class="line">      with:</span><br><span class="line">        node-version: &quot;12.x&quot; #action使用的node版本，建议大版本和本地保持一致。可以在本地用node -v查询版本号。</span><br><span class="line"></span><br><span class="line">    - name: 安装 Hexo</span><br><span class="line">      run: |</span><br><span class="line">        export TZ=&#x27;Asia/Shanghai&#x27;</span><br><span class="line">        npm install hexo-cli -g</span><br><span class="line"></span><br><span class="line">    - name: 缓存 Hexo</span><br><span class="line">      uses: actions/cache@v1</span><br><span class="line">      id: cache</span><br><span class="line">      with:</span><br><span class="line">        path: node_modules</span><br><span class="line">        key: $&#123;&#123;runner.OS&#125;&#125;-$&#123;&#123;hashFiles(&#x27;**/package-lock.json&#x27;)&#125;&#125;</span><br><span class="line"></span><br><span class="line">    - name: 安装依赖</span><br><span class="line">      if: steps.cache.outputs.cache-hit != &#x27;true&#x27;</span><br><span class="line">      run: |</span><br><span class="line">        npm install --save</span><br><span class="line"></span><br><span class="line">    - name: 生成静态文件</span><br><span class="line">      run: |</span><br><span class="line">        hexo clean</span><br><span class="line">        hexo generate</span><br><span class="line"></span><br><span class="line">    - name: 部署 #此处master:master 指从本地的master分支提交到远程仓库的master分支，若远程仓库没有对应分支则新建一个。如有其他需要，可以根据自己的需求更改。</span><br><span class="line">      run: |</span><br><span class="line">        cd ./public</span><br><span class="line">        git init</span><br><span class="line">        git config --global user.name &#x27;$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;&#x27;</span><br><span class="line">        git config --global user.email &#x27;$&#123;&#123; secrets.GITHUBEMAIL &#125;&#125;&#x27;</span><br><span class="line">        git add .</span><br><span class="line">        git commit -m &quot;$&#123;&#123; github.event.head_commit.message &#125;&#125; $(date +&quot;%Z %Y-%m-%d %A %H:%M:%S&quot;) Updated By Github Actions&quot;</span><br><span class="line">        git push --force --quiet &quot;https://$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;:$&#123;&#123; secrets.GITHUBTOKEN &#125;&#125;@github.com/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;.github.io.git&quot; master:master</span><br></pre></td></tr></table></figure><blockquote><p>注意最后一行的<code>master:master</code>指从本地的master分支提交到远程仓库的master分支,需要根据你自己的实际情况进行调整。本地分支可以在git bash中看到。线上分支可以在提交仓库中查看。因为“政治正确”的原因，github在2020年10月将默认分支改为main。而git软件在本地默认创建的分支依然是master，所以若你线上仓库默认分支是main，这里应该写成master:main，表示从本地的master推送到远程的main。</p></blockquote><p>（2）之后需要自己到仓库的Settings-&gt;Secrets-&gt;actions 下添加环境变量，变量名参考脚本中出现的，依次添加。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312242335113.png"></p><p>需要部署在githubpage上，那么脚本中必要的变量为<br><code>GITHUBUSERNAME</code>、<code>GITHUBEMAIL</code>、<code>GITHUBTOKEN</code>，因此添加这三条变量。变量具体内容释义可以查看本文开头。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312242337935.png"></p><h2 id="4-重新设置远程仓库和分支"><a href="#4-重新设置远程仓库和分支" class="headerlink" title="4. 重新设置远程仓库和分支"></a>4. 重新设置远程仓库和分支</h2><p>（1）添加屏蔽项<br>因为能够使用指令进行安装的内容不包括在需要提交的源码内，所有我们需要将这些内容添加到屏蔽项，表示不上传到github上。这样可以显著减少需要提交的文件量和加快提交速度。<br>打开<code>[Blogroot]/.gitignore</code>,输入以下内容：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">.DS_Store</span><br><span class="line">Thumbs.db</span><br><span class="line">db.json</span><br><span class="line">*.log</span><br><span class="line">node_modules/</span><br><span class="line">public/</span><br><span class="line">.deploy*/</span><br><span class="line">.deploy_git*/</span><br><span class="line">.idea</span><br><span class="line">themes/butterfly/.git</span><br></pre></td></tr></table></figure><p>如果不是<code>butterfly</code>主题，记得替换最后一行内容为你自己当前使用的主题。</p><p>（2）提交源码到私有仓库<code>[SourceRepo]</code><br>在博客根目录[Blogroot]下启动终端，使用git指令重设仓库地址。这样在新建仓库，我们仍旧可以保留珍贵的commit history，便于版本回滚。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">git remote rm origin # 删除原有仓库链接</span><br><span class="line">git remote add origin git@github.com:[GithubUsername]/[SourceRepo].git #[SourceRepo]为新的存放源码的github私有仓库</span><br><span class="line">git checkout -b master # 切换到master分支，</span><br><span class="line">#2020年10月后github新建仓库默认分支改为main，注意更改</span><br><span class="line"># 如果不是，后面的所有设置的分支记得保持一致</span><br><span class="line">git add .</span><br><span class="line">git commit -m &quot;github action update&quot;</span><br><span class="line">git push origin master</span><br><span class="line">#2020年10月后github新建仓库默认分支改为main，注意更改</span><br></pre></td></tr></table></figure><p>（3）可能遇到的bug<br>因为<code>butterfly</code>主题文件夹下的<code>.git</code>文件夹的存在，那么主题文件夹会被识别子项目。从而无法被上传到源码仓库。若是遇到添加屏蔽项，但是还是无法正常上传主题文件夹的情况。请先将本地源码中的<code>themes</code>文件夹移动到别的目录下。然后<code>commit</code>一次。接着将<code>themes</code>文件夹移动回来，再<code>commit</code>一次。</p><blockquote><p>要是还不行，那就删了<code>butterfly</code>主题文件夹下的<code>.git</code>文件夹，然后再重复上述的<code>commit</code>操作。</p></blockquote><h2 id="5-查看部署情况"><a href="#5-查看部署情况" class="headerlink" title="5. 查看部署情况"></a>5. 查看部署情况</h2><p>此时，打开GIthub存放源码的私有仓库，找到action。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312242341919.png"></p><p>点击Deploy查看部署情况</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312242341784.png"></p><p>若全部打钩，恭喜你，你现在可以享受自动部署的快感了。</p><h2 id="Hexo自动部署至虚拟主机"><a href="#Hexo自动部署至虚拟主机" class="headerlink" title="Hexo自动部署至虚拟主机"></a>Hexo自动部署至虚拟主机</h2><p>打开 Action 配置文件<code>（本地博客仓库目录/.github/workflows/(Action配置文件).yml）</code>，在后面添加</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">- name: Deploy Files on Ftp Server</span><br><span class="line">  uses: SamKirkland/FTP-Deploy-Action@4.3.3</span><br><span class="line">  with:</span><br><span class="line">    server: (FTP服务器地址)</span><br><span class="line">    username: (FTP用户名)</span><br><span class="line">    password: (FTP密码)</span><br><span class="line">    local-dir: ./public/</span><br><span class="line">    server-dir: (FTP服务器文件目录)</span><br><span class="line">    port: (FTP服务器端口，一般是21)</span><br><span class="line">    protocol: ftp</span><br></pre></td></tr></table></figure><p>最后直接将博客源码提交到github上就行了。</p><h2 id="可能遇到的问题"><a href="#可能遇到的问题" class="headerlink" title="可能遇到的问题"></a>可能遇到的问题</h2><h2 id="1-unknown-block-tag-“tagname”"><a href="#1-unknown-block-tag-“tagname”" class="headerlink" title="1. unknown block tag: “tagname”"></a>1. unknown block tag: “tagname”</h2><p>要是在github action部署时遇到<code>unknown block tag: &quot;tagname&quot;</code>这样的报错，说明你可能没有正确上传主题文件夹，也可能遇到安装依赖或生成页面失败的情况。</p><p>请按照以下思路逐一排查。</p><p>（1）是否将<code>node_modules</code>也上传到源码仓库<code>[SourceRepo]</code>了。源码仓库不需要有<code>node_modules</code>文件夹。</p><p>（2）是否有将<code>[Blogroot]/themes/</code>下的主题文件夹上传，例如检查[SourceRepo]内的<code>[Blogroot]/themes/Butterfly</code>是否为空文件夹。为了能够正常编译页面，源码仓库需要有<code>[Blogroot]/themes/Butterfly</code>文件夹及它所包含的主题文件内容。<br>为了避免这两点，需要添加git屏蔽项。通过给<code>.gitignore</code>添加屏蔽项解决。<br>打开<code>[Blogroot]/.gitignore</code>,输入以下内容：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">.DS_Store</span><br><span class="line">Thumbs.db</span><br><span class="line">db.json</span><br><span class="line">*.log</span><br><span class="line">node_modules/</span><br><span class="line">public/</span><br><span class="line">.deploy*/</span><br><span class="line">.deploy_git*/</span><br><span class="line">.idea</span><br><span class="line">themes/butterfly/.git</span><br></pre></td></tr></table></figure><p>（3）若是遇到添加屏蔽项，但是还是无法正常上传主题文件夹的情况。</p><ul><li>请先将本地源码中的<code>themes/butterfly</code>文件夹下的<code>.git</code>文件夹删除。</li><li>然后将<code>butterfly</code>文件夹移动到别的目录下。然后<code>commit</code>一次。</li><li>接着将<code>butterfly</code>文件夹移动回来，再<code>commit</code>一次。</li></ul><h2 id="2-遇到spawn-failed报错。"><a href="#2-遇到spawn-failed报错。" class="headerlink" title="2. 遇到spawn failed报错。"></a>2. 遇到<code>spawn failed</code>报错。</h2><p>在<code>github action</code>的配置中出现这一报错。一般是因为涉及到部署地址的配置项有误。</p><p>（1）首先排查你在<code>[Blogroot]\_config.yml</code>的<code>deploy</code>配置项是否按照上文<a href="https://akilar.top/posts/f752c86d/#%E9%85%8D%E7%BD%AEdeploy%E9%A1%B9">配置deploy项</a>中的步骤正确组装配置链接。</p><p>（2）其次排查<code>[Blogroot]\.github\workflows\autodeploy.yml</code>中各个关于仓库链接的配置内容，注意按照注释指引检查空格、分支等。</p><p>（3）更多可能的因素和解决方案可以参考<a href="https://blog.zhheo.com/">@洪哥HEO</a>写的方案:<a href="https://blog.zhheo.com/p/128998ac.html">Hexo错误：spawn failed的解决方法</a>。</p><h2 id="3-变量名称问题"><a href="#3-变量名称问题" class="headerlink" title="3. 变量名称问题"></a>3. 变量名称问题</h2><p>部分不愿意用教程给出的变量名的可能遇到未知bug，此处给出官方的命名规则：</p><p>以下规则适用于密码名称：</p><p>密钥名称只能包含字母数字字符（[a-z]、[A-Z]、[0-9]）或下划线 (_)。 不允许空格。</p><p>密钥名称不得以 <code>GITHUB_</code> 前缀开头。</p><p>密钥名称不能以数字开头。</p><p>密钥名称不区分大小写。</p><p>密钥名称在所创建的级别上必须是唯一的。</p><h2 id="4-分支问题"><a href="#4-分支问题" class="headerlink" title="4. 分支问题"></a>4. 分支问题</h2><p>本地分支和线上分支不一致导致总是提交不上。<br>注意观察autodeploy.yml文件中，</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push --force --quiet &quot;https://$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;:$&#123;&#123; secrets.GITHUBTOKEN &#125;&#125;@github.com/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;.github.io.git&quot; master:master</span><br></pre></td></tr></table></figure><p>末尾的master:master指从本地的master分支提交到远程仓库的master分支。需要根据实际情况进行调整。本地的分支可在git bash中查看。线上的分支可在仓库查看。比如本地默认分支是master，线上默认分支是main，应该改成master:main。<br>会遇到这类问题，一般是有同学直接全局替换master为main导致。</p><h2 id="5-CI-CD时提示：-public目录找不到"><a href="#5-CI-CD时提示：-public目录找不到" class="headerlink" title="5. CI/CD时提示：./public目录找不到"></a>5. CI/CD时提示：./public目录找不到</h2><p>配置文件<code>/.github/workflows/(Action配置文件).yml</code>应该放在博客根目录，并且<code>.github/ </code>和<code> themes/</code>同一级。</p><h2 id="6-CI-CD到部署报错，错误如下："><a href="#6-CI-CD到部署报错，错误如下：" class="headerlink" title="6. CI/CD到部署报错，错误如下："></a>6. CI/CD到部署报错，错误如下：</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">error: src refspec main does not match any</span><br><span class="line">error: failed to push some refs to &#x27;https://github.com/***/***.github.io.git&#x27;</span><br><span class="line">Error: Process completed with exit code 1.</span><br></pre></td></tr></table></figure><p>原因是我本地分支时main，线上分支时main。然后我将配置文件<code>/.github/workflows/(Action配置文件).yml</code>的最后一行改为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push --force --quiet &quot;https://$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;:$&#123;&#123; secrets.GITHUBTOKEN &#125;&#125;@github.com/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;.github.io.git&quot; main:main</span><br></pre></td></tr></table></figure><p>正确应该为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push --force --quiet &quot;https://$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;:$&#123;&#123; secrets.GITHUBTOKEN &#125;&#125;@github.com/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;/$&#123;&#123; secrets.GITHUBUSERNAME &#125;&#125;.github.io.git&quot; master:main</span><br></pre></td></tr></table></figure><p>原因未知。</p><h2 id="7-自动部署虚拟主机报错"><a href="#7-自动部署虚拟主机报错" class="headerlink" title="7. 自动部署虚拟主机报错"></a>7. 自动部署虚拟主机报错</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">----------------------  full error below  ----------------------</span><br><span class="line">----------------------------------------------------------------</span><br><span class="line"></span><br><span class="line">Error: Timeout (control socket)</span><br><span class="line">    at Socket.&lt;anonymous&gt; (/home/runner/work/_actions/SamKirkland/FTP-Deploy-Action/4.3.3/dist/index.js:5288:58)</span><br><span class="line">    at Object.onceWrapper (node:events:627:28)</span><br><span class="line">    at Socket.emit (node:events:513:28)</span><br><span class="line">    at Socket._onTimeout (node:net:550:8)</span><br><span class="line">    at listOnTimeout (node:internal/timers:559:17)</span><br><span class="line">    at processTimers (node:internal/timers:502:7)</span><br><span class="line">Error: Error: Timeout (control socket)</span><br></pre></td></tr></table></figure><p>解决方法是在配置中添加：<code>protocol: ftp</code></p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这里可能有同学要问，github action有啥用？这不就是从<code>hexo cl &amp;&amp; hexo g &amp;&amp; hexo s</code>的三件套变成了<code>git add .</code>,<code>git commit -m &quot;commit content&quot;</code>,<code>git push</code>三件套吗？<br>其实github action的最大作用就是进一步提高速度和便携性，首先，配置要求提交源码这点，萌新小白就没必要再靠本地不断新建压缩包来备份源码了，借助git的版本管理，不管怎么改都可以快速回滚。<br>然后，git提交是增量更新，每次只提交新增或者删改的内容，而hexo deploy是在本地每次重新生成所有静态文件以后再整个提交。github action能帮我们节省大把时间，把最耗时的hexo generate和hexo deploy的工作丢给CI处理。让我们能够专心与编写博客内容，而不是水文3分钟，提交半小时。</p><blockquote><p>需要Gitee和Coding的部署方式，请<a href="https://akilar.top/posts/f752c86d/">点击查看</a></p></blockquote>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Others/">Others</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/">博客搭建</category>
      
      
      <comments>https://blog.helloallen.cn/41767f46/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>2023年度欧洲摄影大奖，30幅作品</title>
      <link>https://blog.helloallen.cn/7d9d60a6/</link>
      <guid>https://blog.helloallen.cn/7d9d60a6/</guid>
      <pubDate>Fri, 15 Dec 2023 00:22:23 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8x71ca8XHEjBjT7bOSJ9Tyib7NujloiaaOWY8q0oyeoBYJiaJ8alvuw1BA/640?wx_fmt=jpeg&from=appmsg&wxfrom=13" alt="图片"></p><p>探索2023年欧洲摄影大奖的令人惊叹的照片。通过这些奖项加入世界范围的探索,这个舞台欢迎来自世界各地的摄影师。探究多样的丰富性,捕捉代代相传的传统的持久诱惑。</p><p><strong>欧洲摄影大奖</strong>是一个具有重要影响力的国际摄影奖项，其评选标准严格、奖项设置丰富。对于摄影师来说，获得该奖项不仅意味着个人成就得到了认可，更是一个激励自己继续创作的动力。同时，欧洲摄影大奖和欧洲摄影基金会也共同推动了欧洲摄影艺术的发展和普及，为摄影师提供了一个展示才华和交流学习的平台。在未来，随着欧洲摄影艺术的不断发展和创新，相信欧洲摄影大奖的影响力和地位也将越来越重要。</p><p><strong>人物摄影,文化奖得主-阿萨罗之魂</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm83Fzadc0ibac8QZfDN7bvGAgvKibbiaAk5vOnViak1pD6ic1ibAVye4ic8Ufuw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>“巴布亚新几内亚野生森林中的古鲁波卡峰是鬼之地。它们慢慢地从树上走出来,它们的动作就像魔鬼的舞蹈,无缝地与森林融合在一起。</p><p>他们可怕的脑袋被瘦削的灰色身体粘在一起。他们突然消失了,又像幽灵一样出现在游客后面。他们是土著战士,居住在巴布亚新几内亚阿萨罗河沿岸的一个山谷里。今天,阿斯罗·穆德曼是巴布亚新几内亚最著名的部落之一。每当他们戴上泥面具,伪装成白色恶魔,他们都体现出将敌人赶出他们珍爱的村庄和祖国的精神。”</p><p><strong>编辑摄影,纪录片奖得主–乔科埃略的”有弹性的母亲”</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8XG42TDF6IInCLm6Uu5pdmsDeKB8aItQ1IwU02ZTnC2u2lux89vIpEw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>法国摄影,美术奖得主-克利斯多夫迪米尼的第一号拳击俱乐部</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8x71ca8XHEjBjT7bOSJ9Tyib7NujloiaaOWY8q0oyeoBYJiaJ8alvuw1BA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>德国摄影,美术奖**</strong>得主-玛莲娜·内维尔的自我之旅**</p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8oqeKgibSTp7QDNxEIR2RYiaa32weiaH7ve5qV9ibhAeLsHKv5A9S6FCNBQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>欧洲摄影大奖是欧洲最具影响力的摄影奖项之一，旨在表彰在摄影领域取得卓越成就的艺术家。该奖项由欧洲摄影基金会（European Photography Foundation）主办，每年评选一次，获奖作品不仅代表了欧洲最高水平的摄影艺术，同时也反映了当代社会和文化的多样性和变迁。</p><p>欧洲摄影大奖的评选标准非常严格，要求参赛作品必须符合以下条件：</p><ol><li>必须是欧洲摄影师的作品；</li><li>必须是在欧洲摄影基金会认可的博物馆、画廊或机构中展出的作品；</li><li>必须是在上一年度内完成的作品；</li><li>必须符合欧洲摄影基金会的主题或命题要求（如有）。</li></ol><p>评选过程由一个独立的评审团进行，评审团由来自不同领域的知名艺术家、评论家和策展人组成。他们根据作品的创新性、技术技巧、审美价值和社会意义等方面进行评估，最终选出优胜者。</p><p>欧洲摄影大奖的奖项设置非常丰富，包括最佳摄影师奖、最佳系列作品奖、最佳实验作品奖、最佳长期项目奖、最佳新人奖等。此外，还有特别奖和荣誉奖，以表彰对欧洲摄影艺术做出杰出贡献的个人或机构。</p><p>自成立以来，欧洲摄影大奖已经成为了欧洲摄影界的一个重要事件。每年的评选结果都会引起广泛的关注和讨论，因为它们不仅代表了欧洲最高水平的摄影艺术，也反映了当代社会和文化的发展趋势。对于摄影师来说，获得欧洲摄影大奖不仅是对他们个人成就的认可，更是对他们未来发展的鼓励和支持。</p><p>除了欧洲摄影大奖本身的影响力之外，其背后的欧洲摄影基金会也是值得一提的。该基金会致力于推动欧洲摄影艺术的发展和普及，通过举办展览、研讨会、工作坊等活动，为摄影师提供了一个交流和学习的平台。同时，该基金会还支持年轻摄影师的创作和成长，为欧洲摄影界培养了一批优秀的新生力量。</p><p><strong>战争/冲突胜利者-战争与和平</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8yiaVeUTr762LgRMtA8vCO2MegxrTgLZDGNRMXWDearEBEaBQAbISY7A/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>优秀的艺术摄影,街道冠军-向光明跑由马尔科威尔姆</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8kHRKBYIqUHxSebR57DD5ibm5ibcVVgcRcW9YEhKAve8ib3nOo2X6AlDaw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>意大利摄影,美术奖得主-2万里的海底罗宾永</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8RBDSDkTMpaM4p5eeOXvDiaXWHZJjpyfDmSs1CIiapZCF7Xd4gSOzHEJQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>自然摄影,时间流逝的胜利者–爱是亚历山大塞莱兹诺夫</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8QUMqB5QgL0icH3dyKwRNmaAxMF2Tt8JhjhLwpXicEoIFLGLtpmNBgRGg/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>黑白摄影,肖像奖得主-火在我心中</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8FPeFrAKcMeicd9H0YdqKrfXia4y8jaZsnC3mY9kr6TibpvS3icUr37QcdA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>自然摄影,无人机冠军–拉雷斯·别里乌的熔岩大象</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8Buh2qZa5blIlRD9CayS3EgfvwiaybRhicyLjULrsJ7MJmJbGltkpXEHQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>德国摄影,动感图像奖得主-停止你的动作由杰奎琳·罗迪格</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm89ic8BMAky6yYGdYDSiar4OQhCeVjRk0l7p7bEXrhgUwX0B81yOoJ9YVA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>特别类,数码增强摄影奖得主–川上和志的最后一个节目</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm80GoyMvVtmWibzR6Cb42iaabIfiaMGb6Y1gTzBwv9fuHNZmmZ17tia1bYXw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>黑色和白色摄影,人类冠军-水和光由利莎海因里希斯</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8Nh6OCtwBK9zLIRYdoOlujx5INRTy99jQZ1870s69eicvmyatDxksgOg/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>优秀的艺术摄影,人们的胜利-精彩的时刻</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm840GTicSPMtZN7rjiaByrZ9ZiaL3PfMR9w5RqkLQB2GJyyQTrnDv6VQjkw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>商业摄影,专辑封面冠军-你和所有的季节由安迪·韦尔斯</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8SxtibGiasajLha5WjsgXqibk0ZFz951FpJHKXCTXxdx7FqpMGIZehBic8A/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>建筑摄影,建筑冠军-塔达乌尔由格里奥利里</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8Z5VHdgmZhGAfxSG4LrjibaoqwichfkQZOufOw9iazC0wJaQ7TKjLSwkRg/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>人们摄影,环境奖得主–约翰T在加丹加生存下来。皮德森</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8OcxrJysxialL6yCVHWjgoTgXTBFxq5UIia9aXDWDX1ib51ap3655kgfCw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>自然摄影,野生动物奖得主-伟大的白色</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8EY7vwWAGmvN2OZCHY73eLeryhzaM8n9gmBUiag0oD0OIiaVjUNLPJCnA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>编辑摄影,摄影新闻奖得主-乌克兰:战争的恐怖</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8pltK9Yehic2LUkpEM1zM58H74u12taQEMfPBicrVU0hKDFCMhCyEfvWA/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>特殊类别,长期曝光摄影冠军-马克托马拉的克兰兹巴赫</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8ZUOeJTWqYSib1EmmN5IuUXyqe7r51ibJicrP0daqIgPzfibOArfl4DzP0Q/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>人物摄影,宗教胜利者–蔡明伦</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8mAT97cokEdRyOqmmhmQ1BfyHqAWQRibDDMk96MBGa7PgTIkVvNEw4cw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>建筑摄影,抽象胜利者–安娜·瓦克的翅膀</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8SsOW1lC2NA351GZnSvLMrXtncYiclUOibLxj02iah7OmCF41EBJuVQibqg/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>意大利摄影,景观冠军–安德烈萨基的火焰山脉</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8HY1BG4ibX0w5YSUJtvcricFPcOygGc7VmrA06pWCbUXqzXYA5oibVNACg/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>编辑摄影,纪录片奖得主–若昂·科埃略的结束</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8xx7h577P5ZxS8hJTa4BKfiblasDZWXb8Aq7Nb6LBNGtAciaECLMymVWQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>欧洲摄影大奖的历史可以追溯到1954年，当时它被设立为“Foto Club尤里卡奖”，旨在鼓励和表彰在摄影领域取得杰出成就的艺术家。随着时间的推移，该奖项逐渐发展成为欧洲最具影响力的摄影奖项之一，并更名为“欧洲摄影大奖”。</p><p>在历史上，欧洲摄影大奖曾经颁发给许多杰出的摄影师，包括法国摄影师简·布拉克（Jean Bracq）、德国摄影师瓦尔特·德·玛利亚（Walter de Maria）、英国摄影师约翰·斯通（John Stone）等。这些获奖者不仅在欧洲摄影界享有崇高的声誉，也在全球范围内产生了广泛的影响。</p><p>如今，欧洲摄影大奖已经发展成为一个国际性的摄影奖项，吸引了来自世界各地的摄影师参加。每年的评选过程都非常严格，评审团由来自不同领域的专家组成，以确保获奖作品的质量和价值。同时，欧洲摄影大奖也得到了欧洲摄影基金会的大力支持，该基金会通过举办展览、研讨会、工作坊等活动，为摄影师提供了一个交流和学习的平台。</p><p><strong>人物摄影,文化冠军-浮动市场威廉伊迪亚特罗德里格斯</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm864vjuyB3NlLxHtsBx7EmXyX3OQljYNO3G5icoGozvXicRppeWnYNPtpQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>大自然摄影,野生动物奖得主-卡里姆·伊利雅工作室的火红乌鸦</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8FUzrdl5WFlVA2Kw8fknx1cB6nkh3QAiakddSrMMOyHJzxywSjC39deQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>法国摄影,景观奖得主–冰岛圣诗–山</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8EHOeGSwqsIE9JKsRN9JfwO6zlficRagzEeHUeic95xy8HVxu6AFHQO7A/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>自然摄影,宏观胜利者–被尼基·科勒蒙无力</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8x8eR2a15gLUXSWFwfZya71a3k6FzH0rF3eibUPru84qOBY0n1YIGoew/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>优秀的艺术摄影,人们的胜利-回家的路奥萨马埃洛勒米</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm8sM5YN3mepY7AMKtLnd2b4Y5LM5u18xwYDFvDjV3nN6Pj2icDcZViaudQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p><strong>美术摄影,旅游冠军-富士山之美</strong></p><p><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/zicx72M5jPSCdEeelESxMgvhVclTtLdm837yEWHQEePQvChaJYibuqicf3U9DibiaiaZz2I52vcgdia24EEGyVDbSy1SQ/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="图片"></p><p>在欧洲摄影大奖的发展过程中，也存在着一些挑战和问题。例如，随着数字技术的发展，摄影作品的真实性和质量也受到了质疑。此外，由于欧洲摄影大奖是一个国际性的奖项，如何平衡不同文化背景和价值观也是一大挑战。</p><p>然而，尽管面临挑战和问题，欧洲摄影大奖仍然保持着其崇高的声誉和影响力。它不仅是一个表彰优秀作品的奖项，更是一个激励摄影师不断追求创新和卓越的平台。在未来，随着摄影技术的不断发展和创新，相信欧洲摄影大奖也会继续发展和壮大。</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/%E8%89%BA%E6%9C%AF%E4%B8%8E%E6%96%87%E5%AD%A6/">艺术与文学</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E6%91%84%E5%BD%B1/">摄影</category>
      
      
      <comments>https://blog.helloallen.cn/7d9d60a6/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Github + jsDelivr + PicGo 打造稳定快速、高效免费的图床!</title>
      <link>https://blog.helloallen.cn/e292dc0e/</link>
      <guid>https://blog.helloallen.cn/e292dc0e/</guid>
      <pubDate>Tue, 12 Dec 2023 00:24:01 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="缘起"><a href="#缘起" class="headerlink" title="缘起"></a>缘起</h2><p>不希望将大量的图片等静态资源放在自己部署了项目的云服务器上，又不希望增加成本去专门购置一台静态资源服务器，<br>放在其他免费服务器上又希望能做到CDN加速。于是找到了<strong>Github + jsDelivr + PicGo</strong>来解决这个需求。以下文章部分转载自<a href="https://www.bilibili.com/read/cv4297993">利用jsDelivr白嫖全球超高速静态资源访问服务！</a>。</p><h2 id="jsDelivr是什么"><a href="#jsDelivr是什么" class="headerlink" title="jsDelivr是什么"></a>jsDelivr是什么</h2><p>jsDelivr由ProspectOne维护的公共库，使用的融合CDN技术，由Cloudflare、Fastly、StackPath、QUANTIL等CDN供应商提供了<strong>全球超过750个CDN节点</strong>。<br>最重要的是，jsDelivr在<strong>中国大陆</strong>也拥有超过数百个节点，因为jsDelivr拥有<strong>正规的ICP备案</strong>，解决了中国大陆的访问速度优化，实现真正的<strong>全球极速低延迟</strong>体验。<br>jsDelivr是<strong>免费</strong>的、<strong>不限制带宽</strong>的，可以加速<strong>NPM</strong>、<strong>Github</strong>内的文件。<br>本文采用的方法就是将静态文件资源放到Github的仓库内，再使用jsDelivr进行加速访问，最后通过PicGo上传管理资源，打造一个高速访问的图床！<br><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL0hlbGxvQWxsZW5XL0Jsb2dBc3NldHNAdjEuMy9pbWFnZXMvMjAyMC8wNC9qc2RlbGl2ci01LndlYnA?x-oss-process=image/format,png" alt="全球节点分布地图"></p><h2 id="创建仓库"><a href="#创建仓库" class="headerlink" title="创建仓库"></a>创建仓库</h2><p>在Github新建一个公开仓库，用于存放我们的静态文件资源。这里不再过多赘述，下面的链接是我的<a href="https://github.com/HelloAllenW/BlogAssets">静态文件资源仓库</a>。</p><h2 id="使用jsDelivr访问资源"><a href="#使用jsDelivr访问资源" class="headerlink" title="使用jsDelivr访问资源"></a>使用jsDelivr访问资源</h2><p>根据<a href="https://www.jsdelivr.com/">jsdelivr官方文档</a>，有很多种访问资源的方式，这里主要介绍三种。</p><h2 id="通过releases访问"><a href="#通过releases访问" class="headerlink" title="通过releases访问"></a>通过releases访问</h2><p>在仓库首页找到releases<br><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL0hlbGxvQWxsZW5XL0Jsb2dBc3NldHNAdjEuMy9pbWFnZXMvMjAyMC8wNC9qc2RlbGl2ci0xLnBuZw?x-oss-process=image/format,png" alt="新建releases"><br>创建new releases，如果之前创建过则选择Draft a new releases<br><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL0hlbGxvQWxsZW5XL0Jsb2dBc3NldHNAdjEuMy9pbWFnZXMvMjAyMC8wNC9qc2RlbGl2ci0yLnBuZw?x-oss-process=image/format,png" alt="新建releases"><br>标题输入版本号，根据你的需求即可，比如我这里是v1.0<br>输入完毕后点击下方绿色按钮。<br><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL0hlbGxvQWxsZW5XL0Jsb2dBc3NldHNAdjEuMy9pbWFnZXMvMjAyMC8wNC9qc2RlbGl2ci0zLnBuZw?x-oss-process=image/format,png" alt="新建releases"><br>跳转到以下页面代表创建成功<br><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL0hlbGxvQWxsZW5XL0Jsb2dBc3NldHNAdjEuMy9pbWFnZXMvMjAyMC8wNC9qc2RlbGl2ci00LnBuZw?x-oss-process=image/format,png" alt="新建releases"><br>根据jsDelivr的要求，文件路径为：<a href="https://cdn.jsdelivr.net/gh/user/repo@version/file">https://cdn.jsdelivr.net/gh/user/repo@version/file</a><br>以我的为例，访问仓库目录下的jsdelivr-1.png文件，为以下链接：<br><a href="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets@v1.3/images/2020/04/jsdelivr-1.png">https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets@v1.3/images/2020/04/jsdelivr-1.png</a><br>可以正常访问，成功~<br>这种方案的优点是，可以区分版本，就算以后删掉了一些文件也可以通过旧的releases访问，而且可以及时更新缓存。<br>美中不足的是，每次仓库里更新资源后，需要发布个releases才能获取更新文件，并不是很方便，所以适合于存放基本不需要更新修改添加的静态文件。需要频繁修改或上传的文件不建议放到这里面来。</p><h2 id="直接访问"><a href="#直接访问" class="headerlink" title="直接访问"></a>直接访问</h2><p>根据jsDelivr的要求，文件路径为：<a href="https://cdn.jsdelivr.net/gh/user/repo/file">https://cdn.jsdelivr.net/gh/user/repo/file</a><br>以我的为例：<br><a href="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/2020/04/jsdelivr-1.png">https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/2020/04/jsdelivr-1.png</a><br>不推荐使用这种方法，暂未摸清如何更新缓存。</p><h2 id="访问最新文件"><a href="#访问最新文件" class="headerlink" title="访问最新文件"></a>访问最新文件</h2><p>根据jsDelivr的要求，文件路径为：<a href="https://cdn.jsdelivr.net/gh/user/repo@latest/file">https://cdn.jsdelivr.net/gh/user/repo@latest/file</a><br>以我的为例：<a href="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets@latest/images/2020/04/jsdelivr-1.png">https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets@latest/images/2020/04/jsdelivr-1.png</a><br>这种方案不需要发布releases，可以直接从repo读取文件，而且实时更新缓存。<br>但是官方并不推荐使用这种方法，因为修改repo的文件后，如果没有修改网站的旧链接，可能会出问题。根据你自己的情况决定吧。</p><h2 id="访问统计"><a href="#访问统计" class="headerlink" title="访问统计"></a>访问统计</h2><p>jsDelivr还提供了文件列表和文件访问统计页面：<br>文件列表：<a href="https://cdn.jsdelivr.net/gh/user/repo/">https://cdn.jsdelivr.net/gh/user/repo/</a><br>比如我的：<a href="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/">https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/</a></p><p>访问统计：<a href="https://www.jsdelivr.com/package/gh/user/repo">https://www.jsdelivr.com/package/gh/user/repo</a><br>比如我的：<a href="https://www.jsdelivr.com/package/gh/HelloAllenW/BlogAssets">https://www.jsdelivr.com/package/gh/HelloAllenW/BlogAssets</a></p><h2 id="代码压缩"><a href="#代码压缩" class="headerlink" title="代码压缩"></a>代码压缩</h2><p>jsDelivr还提供了代码压缩服务，比如将JS/CSS的代码压缩，优化访问速度。<br>只是前几次访问会执行压缩操作，速度比较慢。后面就会将文件缓存，速度不会再慢了。<br>直接将访问链接的文件后缀改成.min.js即可，比如：<br><a href="https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js">https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js</a></p><h2 id="在GitHub中生成一个Token"><a href="#在GitHub中生成一个Token" class="headerlink" title="在GitHub中生成一个Token"></a>在GitHub中生成一个Token</h2><p>在主页依次选择【Settings】-【Developer settings】-【Personal access tokens】-【Tokens(classic)】-【Generate new token】- 【Generate new token(classic)】，填写好描述，勾选【repo】，然后点击【Generate token】生成一个Token，注意这个Token只会显示一次，自己先保存下来，或者等后面配置好PicGo后再关闭此网页。<br><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312112349137.png"><br><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312112352386.png"><br><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312112352936.png"><br><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312242323101.png"></p><h2 id="配置PicGo"><a href="#配置PicGo" class="headerlink" title="配置PicGo"></a>配置PicGo</h2><p>前往<a href="https://molunerfinn.com/PicGo/">下载PicGo</a>，如果官方下载速度过慢，请使用<a href="https://mirrors.sdu.edu.cn/github-release/1702304660/github-release/Molunerfinn_PicGo/">山东大学镜像</a>进行下载。安装好后开始配置图床。<br><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312112352311.png"></p><ul><li>设定仓库名：按照【用户名 / 图床仓库名】的格式填写</li><li>设定分支名：【master】 【main】(github 更新后默认为 main)</li><li>设定Token：粘贴之前生成的【Token】</li><li>指定存储路径：填写想要储存的路径，如【images/】，这样就会在仓库下创建一个名为 images 的文件夹，图片将会储存在此文件夹中</li><li>设定自定义域名：它的作用是，在图片上传后，PicGo会按照【自定义域名+储存路径+上传的图片名】的方式生成访问链接，放到粘贴板上，因为我们要使用 jsDelivr 加速访问，所以可以设置为【<a href="https://cdn.jsdelivr.net/gh/%E7%94%A8%E6%88%B7%E5%90%8D/%E5%9B%BE%E5%BA%8A%E4%BB%93%E5%BA%93%E5%90%8D">https://cdn.jsdelivr.net/gh/用户名/图床仓库名</a> 】，上传完毕后，我们就可以通过【<a href="https://cdn.jsdelivr.net/gh/%E7%94%A8%E6%88%B7%E5%90%8D/%E5%9B%BE%E5%BA%8A%E4%BB%93%E5%BA%93%E5%90%8D/%E5%9B%BE%E7%89%87%E8%B7%AF%E5%BE%84">https://cdn.jsdelivr.net/gh/用户名/图床仓库名/图片路径</a> 】加速访问我们的图片了，比如：<a href="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312112352311.png">https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202312112352311.png</a></li></ul><p><img src="https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL0hlbGxvQWxsZW5XL0Jsb2dBc3NldHNAbGF0ZXN0L2ltYWdlcy8yMDIwLzA0L2pzZGVsaXZyLWRpdmlzaW9uLnBuZw?x-oss-process=image/format,png" alt="分割线"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>经速度测试，访问速度非常快，有效提升整体速度，还能省下一大笔费用，实属优质白嫖~<br>并且配置好PicGo后，我们可以直接将图片拖拽到上传区（选择URL格式），将会自动上传并复制访问链接，将链接粘贴到博文中就行了，此外PicGo还有相册功能，可以对已上传的图片进行删除，修改链接等快捷操作，PicGo还可以生成不同格式的链接、支持批量上传、快捷键上传、自定义链接格式、上传前重命名等，更多功能自己去探索吧！</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Others/">Others</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/">博客搭建</category>
      
      
      <comments>https://blog.helloallen.cn/e292dc0e/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>哥大校长2023毕业演讲：认识到自己巨大的无知，时刻保持开放的心态！</title>
      <link>https://blog.helloallen.cn/cdac8766/</link>
      <guid>https://blog.helloallen.cn/cdac8766/</guid>
      <pubDate>Fri, 08 Dec 2023 23:08:25 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/0iawiadjXSytexd4jo9LgJDhQC70k7BdvF2btu9rs8ysyYbtkfaTkvupd6yUbA5A5S8MBcOODReCDaDmuTPicoEUQ/640?wx_fmt=jpeg&wxfrom=13&wx_lazy=1&wx_co=1&tp=wxpic" alt="图片"></p><p>美国哥伦比亚大学举行2023年毕业典礼，哥伦比亚大学校长李·卡罗尔·布林格（Lee Carroll Bollinger）发表毕业演说。</p><p>现年73岁的布林格于2002年开始担任哥伦比亚大学校长，迄今已经20余年，即将离任。这是他最后一次以哥伦比亚大学校长的身份发表毕业演讲。</p><p>在此次演讲中，布林格没有涉及“宏大叙事”的话题，而是围绕如何成为一个立足于当今世界的人，以及培养和发展什么样的个人品质展开。</p><p>他重点讲到，人类的本性并不是与生俱来的开放。即使专家，对自己和我们的世界也是所知甚少。要认识到自己巨大的无知，看到很多问题的复杂性，并保持个人的开放性！</p><p>以下是演讲内容——</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/0iawiadjXSytexd4jo9LgJDhQC70k7BdvFib2mOflxYN8H28XBjGmx6Br4eLU1DuCqGoYsqxJ204EvZ6Fuod9Spxg/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" alt="图片"></p><p>在这个特别的早晨，我很荣幸欢迎各位来到这个特别的场合。</p><p>今天我特别伤感，因为这将是我担任哥伦比亚大学校长20多年的最后一次毕业典礼演讲。我想我们是一起毕业，我相信你和我都将在余生中把这一刻铭记在心。</p><p>但是就我个人而言，我很高兴地说我找到了一份工作，我将回到哥伦比亚大学法学院继续教书——这是我1973年开始的职业生涯，我从哥伦比亚大学法学院毕业两年后，就开始从事法学教育的职业，那时我和你们差不多大。</p><p>我很喜欢担任这所伟大的大学的校长。无论从哪方面来看，这都是我度过一生的一种值得的方式，最重要的是，这本身就是一场改变我个人的教育。</p><p>离任校长重新当老师对我来说有点复杂。当我离开同事们，去适应一个我个人不再那么重要的世界时，我感到有些悲伤。</p><p>但是，我也很高兴在生活中有更多的空间和时间来做其他事情——这也许就像你去上学时你的家人的感受一样。然而，结束也是生活的一部分，我非常高兴米努什·沙菲克将成为我们的下一任校长！</p><p>因此，请允许我以个人名义，并代表全体教职员工和管理人员，对你们每一位丰富了我们生活的人表示感谢，并向所有在你们的学术生涯中支持过你们的人表示感谢！</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/0iawiadjXSytexd4jo9LgJDhQC70k7BdvFj6lghY9ROzXqYM0TRtd1b4Sb6GAeicY7EOnEgCD2n6qB3iajcJrtI9hA/640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" alt="图片"></p><p>我想了很多关于今天演讲的话题，很多人会期待我能够提供以一些深刻的想法。你很可能期望我谈论重大问题。但令我惊讶的是，你们已经精通你们这一代人肩负的解决文明问题的任务。</p><p>我能做的，也是我希望做的，就是总结我多年来所学到的对美好生活有帮助的一小部分体会。我感兴趣的是如何成为一个立足于当今世界的人，以及培养和发展什么样的个人品质。</p><p>这个话题这似乎很简单，我没有一个确切的主题来形容我将要谈论的东西，但是，总的来说，它是关于发展某种开放性的倾向——这是经常被评论的，但很少有人意识到，实现和维持这种开放性是多么困难。</p><p>无论是作为社会还是作为个人，开放有很多模式。我们通常从美国宪法关于言论自由的《第一修正案》思考这个问题，碰巧我对这个有点研究。（注：哥大校长布林格是研究《第一修正案》领域的法学专家）</p><p>我引用《第一修正案》的原因，你可能会认为它是我们所有人都应该努力遵循的一种信仰，事实上，在很多方面恰恰相反。</p><p>在今天这个时代，你们中的一些人可能会觉得《第一修正案》保护了太多不好的东西，给分裂我们的有毒力量提供了氧气。</p><p>相反，我则想把《第一修正案》作为一个参照点，开启我们着手创造我们个人的“言论自由”这一更为复杂的任务。</p><p>这是我们自己决定如何思考、学习、容忍或不容忍、与他人交往或不交往——包括与我们最亲密的人的基本点。</p><p>我们认识到，人类的本性并不自然地对其他信仰和思想开放。我们生来就不宽容，而不是宽容。</p><p>因此，我今天要讲的重点是，我们如何在自己的内心建立一种开放的心态，这种心态是真实的、持久的，最终是一种积极改变的力量。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/0iawiadjXSytexd4jo9LgJDhQC70k7BdvF8zBLLKngPViaq4IfzqQIyR6zHcAVdT3LCesf6ibK9eVsPSoXVPUxuNDw/640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" alt="图片"></p><p>在学术界，一个特殊的框架适用于寻求真理。在这个框架下，这种追求受到客观、理性、文明、同行评议、完全归因和对自己的想法始终持怀疑态度的严格规范的限制。</p><p>我喜欢称之为“学者气质”（Scholarly Temperament）的东西占主导地位。对于那些不准守规范的人来说，惩罚是严厉的——他们无法得到晋升，甚至被排斥。就像《第一修正案》对言论自由的承诺一样，学者气质来之不易，它只能通过“教育”和精神纪律来实现。</p><p>但是，我们每个人日复一日构建自己的生活。没有人会选择按照宪法第一修正案或学者气质的规定来生活。</p><p>因此，以下是我寻求帮助的一些想法。我发现它们对我建立自己的理解和知识，感觉更自由、更快乐，以及培养与他人的关系都很有用。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/0iawiadjXSytexd4jo9LgJDhQC70k7BdvFZUUPCeuEn6Qw9ppqglfAaTjLhUbdOFKKJymFn08BsM68nxGAibmpuPg/640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1&wx_co=1&tp=wxpic" alt="图片"></p><p>第一个建议，就是要时刻警惕那些把我们引入歧途的自然冲动。我们会有自己的信仰，我们越是坚定地持有信仰，我们就越想保护它们免受矛盾和拒绝。但我们的冲动是危险，我们不仅想要“反对”持反对意见者，我们还想和其他人一起感到这样做的正确性。“我们只会同意我们所同意的。”</p><p>换句话说，我们需要看到，我们的自然倾向是思想封闭，而不是开放。我们并非生来就相信言论自由或公开。我们必须学会改变这种状态。</p><p>第二，我认识到我们——即使是专家——实际上对自己和我们的世界所知甚少。正如这所大学作为人类知识宝库所证明的那样，人类的知识是浩瀚而惊人的，但我们的无知要大得多。</p><p>我喜欢并非常尊重专业知识，但你必须小心，不要让它吓到你。做到这一点的最好方法是探索我们共同的未知事物，因为这是我们发现共同人性的地方，也是新旧事物等待我们发现的地方。</p><p>第三，对于那些我们所做和能够知道的事情，我们必须始终尽可能深入地了解它们的复杂性。</p><p>大脑会自然而然地简化事物，寻找并假设有答案。我总是告诉我的学生，要把我们学习的问题尽可能地复杂化。我建议你遵循学术界行之有效的方法，让他们的头脑做好准备，在每次回应开始时说:“嗯，这很复杂，……”然后从那里开始。</p><p>第四，如果你看到了反对开放的离心力，看到了前方的道路，你就会意识到这是只有通过持续的练习才会发生的事情——这是一种习惯。你必须让这种习惯成为你的一部分，一遍又一遍地做。说“保持开放”，就像对别人说“去弹钢琴吧”一样常见。你必须努力学习，培养你的能力，获得敏捷和力量——这就是钢琴家学习音阶的原因，这些音阶代表着思想的开放。</p><p>第五，当你与别人交谈时，这其实是一个很好的学习方式，你应该总是问更多的问题而不是回答。</p><p>每个人都能教给我们一些东西，一些独特的东西，你的任务就是找到它。问题与答案的比例至少保持在80%。考虑到人的本性，我预测你们在这方面不会有任何问题（除非你们遇到参加过这次毕业典礼的人，他真正听了我说的话，并且被说服了——我知道，这是很少的一部分人)。</p><p>第六，试着这样做：当你遇到一个问题——一个理智的人不同意的问题时，想象你会提出的所有论点，直到没有其他更好选择的地步。然后从头再来，想象你是另一个人，在你的脑海里把他们的论点都列出来。然后试着在你的头脑中同时记住这两个论点。这是很难做到的。</p><p>第七，永远记住，生活中的问题可能结局不同，但其复杂性或多或少是相同的。你的父母无疑会同意，决定送孩子去哪所学校可能和美国外交政策的任何问题一样令人烦恼。在任何情况下，都不要忽视做出“正确”决定的困难。</p><p>第八，请记住，敞开心扉不仅是通往真相和理解的途径，还有助于建立关系。我很久以前就知道，在婚姻、家庭生活和友谊中，没有所谓的契约。当感情发生变化时，”但我们说好了”是没用的。同理心是开放的一个分支，同理心对任何层次的关系都是至关重要的。</p><p>第九，记录。问问你自己，我学到了什么，为什么我不明白，我在多大程度上遵循了自己的原则。从研究人员到葡萄酒专家，每个人都知道，通过写下你的感受，你可以更好地理解你的体验，并为未来提供一个参考点。</p><p>最后，要知道年龄的增长会让这一切变得更容易。年龄越大，你就越不确定，你就越感激人类出于好奇心所做的一切。年龄会帮助你走出困境，让你对自己和他人更有耐心，更愿意接受这个世界上令人困惑但又令人兴奋的奥秘。</p><p>所以，这里总结这十个建议：</p><p>1、了解自己不好的冲动；</p><p>2、感受我们巨大的无知；</p><p>3、关注事物的复杂性，而不是问题的答案；</p><p>4、让开放成为一种习惯；</p><p>5、问更多的问题而不是提供答案；</p><p>6、想象你是你不同意的那个人；</p><p>7、看到平凡生活中的复杂性；</p><p>8、在人际关系中保持开放和同理心；</p><p>9、记录；</p><p>10、让年龄来帮助你。</p><p>我非常幸运，我的职业生涯与我的个人生活相呼应：言论自由、伟大的美国大学、作为一名法学教授和哥伦比亚大学校长，这一切都交织在一起。</p><p>这给了我一座宝贵的材料库，从国家到日常生活，我都可以从中挖掘。今天，我仍然不能理解我需要理解的所有问题，但随着它们的交融，我对每一个问题都有了更好的理解。我希望并期待你们会发现在你们的生活中也是如此。</p><p>我向你们所有人致以最深切的祝贺，尤其是我的2023届毕业生们。</p><p>谢谢！</p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/%E8%89%BA%E6%9C%AF%E4%B8%8E%E6%96%87%E5%AD%A6/">艺术与文学</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E6%96%87%E5%AD%A6/">文学</category>
      
      
      <comments>https://blog.helloallen.cn/cdac8766/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>包管理器 npm、cnpm</title>
      <link>https://blog.helloallen.cn/1db99446/</link>
      <guid>https://blog.helloallen.cn/1db99446/</guid>
      <pubDate>Fri, 08 Dec 2023 10:53:43 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<h3 id="1-npm-基本概念"><a href="#1-npm-基本概念" class="headerlink" title="1. npm 基本概念"></a>1. npm 基本概念</h3><p>npm 全称为 <code>Node Package Manager</code>，是一个基于 Node.js 的包管理器，也是 Node.js 社区最流行、支持的第三方模块最多的包管理器。它的初衷就是让开发人员更容易分享和重用代码。npm 提供了命令行工具，其主要功能是管理Node.js包，包括安装、更新、删除、查看、搜索、发布等。</p><p>npm 最初只是Node.js 的包管理器，但随着前端技术的不断发展，它的定位变成了广义的包管理器，可以实现JavaScript、React、Vue、Gulp、移动开发等包管理，是目前最大、生态最为健全的包管理器。</p><p>npm 能解决 Node.js 在模块管理上的很多问题，其常见的应用场景如下：</p><ul><li>从npm镜像服务器下载第三方模块；</li><li>从npm镜像服务器下载并安装命令行程序到本地；</li><li>自己发布模块到npm镜像服务器供他人使用。</li></ul><p>npm 不需要单独安装，在安装 Node.js 时，就会连带着一起安装 npm 了。但是安装的 npm 不一定是最新的版本，可以使用以下命令来查看本地 npm 的版本：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm -v</span><br></pre></td></tr></table></figure><p>这里的 -v 是 –version 的缩写，表示版本。如果想升级 npm 版本，可以使用以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install npm@latest -g</span><br></pre></td></tr></table></figure><p>这里@latest表示最新的版本，-g 是 –global 的缩写，表示全局安装。</p><p>除此之外，还可以使用help命令来查看npm帮助：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm 命令 --help</span><br></pre></td></tr></table></figure><p>比如查看 install 的参数形式：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install --help</span><br></pre></td></tr></table></figure><p>其中–help可以简写为-h。</p><p>常见的npm命令：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># 初始化</span><br><span class="line">npm init # 初始化后会出现一个package.json配置文件，可以在后面加上 -y ，快速跳过问答式界面。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 安装与卸载</span><br><span class="line">npm install</span><br><span class="line">npm install 包名 --save-dev（npm install 包名 -D） # 安装的包只用于开发环境，不用于生成环境。会出现在package.json中的devDependencies中。</span><br><span class="line">npm install 包名 --save（npm install 包名 -S） # 安装的包需要发布到生产环境。会出现在package.json中的dependencies中。</span><br><span class="line">npm update 包名 # 更新指定包</span><br><span class="line">npm unintall 包名 # 卸载指定包</span><br><span class="line">npm uninstall --save xxx # 从dependencies中删除 </span><br><span class="line">npm uninstall --save-dev xxx # 从devDependencies中删除</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 配置相关</span><br><span class="line">npm config list # 查看配置</span><br><span class="line">npm config set registry https://registry.npmmirror.com # 修改包下载源，这里修改为淘宝镜像</span><br><span class="line">npm config get registry # 查看某一项配置</span><br><span class="line">npm config delete registry # 删除某一项配置</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 查看相关</span><br><span class="line">npm -v # 查看npm版本</span><br><span class="line">npm list # 查看当前目录下已安装的node包</span><br><span class="line">npm list -g # 查看全局已安装的node包</span><br><span class="line">npm --help # 查看帮助命令</span><br><span class="line">npm 指定命令 --help # 查看指定命令的帮助</span><br><span class="line">npm info 指定包名 # 查看远程npm上指定包的所有版本信息</span><br><span class="line">npm root # 查看当前包的安装路径</span><br><span class="line">npm root -g # 查看全局包的安装路径</span><br><span class="line">npm ls 包名 # 查看本地安装的指定包和版本信息</span><br><span class="line">npm ls 包名 -g # 查看全局安装的指定包和版本信息</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 其他</span><br><span class="line">npm cache clean -f # 清理缓存</span><br></pre></td></tr></table></figure><p>说完这些概念，下面就来看看 npm 在使用时有哪些实用的技巧。</p><h3 id="2-初始化-package"><a href="#2-初始化-package" class="headerlink" title="2. 初始化 package"></a>2. 初始化 package</h3><p>凡是使用npm管理的项目，都需要初始化一个package.json文件。</p><p>可以使用以下命令来初始化一个包：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm init</span><br></pre></td></tr></table></figure><p>当执行这个命令时，它会通过问答的形式来一步步进行设置。如果不需要修改默认的配置，直接一路回车即可。如果想跳过向导，快速生成一个package.json 文件，可以执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm init --yes</span><br></pre></td></tr></table></figure><p>其中，–yes可以简写为-y。这时生成的package.json文件的配置项就是 npm 的默认配置。当然这个默认配置也是可以更改的，可以通过类似下面这样的形式来修改 npm 的默认配置：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm config set init.author.name YOUR_NAME</span><br><span class="line">npm config set init.author.email YOUR_EMAIL</span><br></pre></td></tr></table></figure><p>当执行以上命令之后，之后再执行 npm init 命令时，package.json 的作者姓名和邮箱都会初始化为我们设定的值。</p><h3 id="3-快速了解-package"><a href="#3-快速了解-package" class="headerlink" title="3. 快速了解 package"></a>3. 快速了解 package</h3><p>当要使用一个包时，如果想要了解它是如何使用的，可以使用以下命令来打开这个包的主页，它会自动启动浏览器并打开这个页面，这里以React为例：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm home react</span><br></pre></td></tr></table></figure><p>如果想要查看这个包现存的issue，或者公开的roadmap，可以执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm bugs react</span><br></pre></td></tr></table></figure><p>如果想要查看这个包的代码地址，可以执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm repo react</span><br></pre></td></tr></table></figure><p>如果想要查看这个包的详细信息，可以执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm info react</span><br></pre></td></tr></table></figure><p>执行结果如下：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081057551.webp"></p><p>这里返回的是一个JavaScript对象，里面包含react模块的详细信息，可以通过info命令来获取这个对象的成员信息：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm info react description</span><br></pre></td></tr></table></figure><p>执行结果如下：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081057503.png"></p><h3 id="4-安装依赖"><a href="#4-安装依赖" class="headerlink" title="4. 安装依赖"></a>4. 安装依赖</h3><p>可以使用npm install命令来安装需要的包，如果想把这个包自动添加到package.json中，可以执行以下命令，这里以安装React为例：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install react --save</span><br></pre></td></tr></table></figure><p>如果想要安装不同版本的包，可以这样：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 安装最新版本</span><br><span class="line">npm install react@latest// 安装指定版本</span><br><span class="line">npm install react@16.8.0// 安装指定区间版本</span><br><span class="line">npm install react@&quot;&gt;=16.8.0 &lt;17.0.1&quot;</span><br></pre></td></tr></table></figure><p>当使用npm安装依赖时，分为本地安装（local）和全局安装（global），它俩的区别就是是否包含-g参数：</p><p>（1）-g 将模块安装到本地node_modules目录下，但不保存在package.json中。 </p><p>（2） –save 或者 -S 将模块安装到本地node_modules目录下，同时保存到package.json中的dependencies配置项中，在生产环境下这个包的依赖依然存在。 </p><p>（3）–sava-dev 或者 -D 将模块安装到本地node_modules目录下，同时保存到package.json中的devDependencies配置项中，仅供开发时使用。 </p><p>（4）–global 或者 -g 安装的模块为全局模块，如果命令行模块，会直接链接到环境变量中。 </p><p>可以使用require关键字来引入本地安装的包。为了避免引用模块消失，保证依赖模块都会出现在package.json中，最好在npm install 时加上–save。</p><p>需要注意，在执行npm install命令时，npm 5 之前只会下载，不会保存依赖信息。如果需要保存，就需要加上 –save 选项， npm 5 以后就可以省略 –save 选项了，它会自动保存。</p><h3 id="5-锁定依赖"><a href="#5-锁定依赖" class="headerlink" title="5. 锁定依赖"></a>5. 锁定依赖</h3><p>当使用–save来安装依赖时，npm 会把这个依赖保存起来，并添加^前缀，他表示，当再次执行 npm install 命令时，会自动安装这个包在此大版本下的最新版本。如果想要修改这个功能，可以执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config set save-prefix=&#x27;~&#x27;</span><br></pre></td></tr></table></figure><p>执行完该命令之后，就会把^符号改为~符号。当再次安装新模块时，就从只允许小版本的升级变成了只允许补丁包的升级。</p><p>如果想要锁定当前的版本，可以执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config set save-exact true</span><br></pre></td></tr></table></figure><p>这样每次 npm install xxx –save 时就会锁定依赖的版本号，相当于加了 –save-exact 参数。建议线上的应用都采用这种锁定版本号的方式。</p><p>为了彻底的锁定依赖的版本，让应用在任何机器上都安装同样的版本，可以执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm shrinkwrap</span><br></pre></td></tr></table></figure><p>执行这个命令之后，就会在项目的根目录产生一个npm-shrinkwrap.json配置文件，这里面包含了通过node_modules 计算出的模块的依赖树及版本。只要目录下有 npm-shrinkwrap.json 则运行 npm install 时就会优先使用 npm-shrinkwrap.json 中的配置进行安装，没有则使用 package.json 进行安装。</p><h3 id="6-搜索依赖"><a href="#6-搜索依赖" class="headerlink" title="6. 搜索依赖"></a>6. 搜索依赖</h3><p>npm 为我们提供了search 命令，用于搜索npm仓库，它搜索的参数可以是一个字符串，也可以是一个正则表达式：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm search react</span><br></pre></td></tr></table></figure><p>搜索结果如下：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081059409.webp"></p><p>当然，我们也可以去node.js官网去找：<a href="https://link.zhihu.com/?target=https://www.npmjs.com/">https://www.</a><a href="https://link.zhihu.com/?target=https://www.npmjs.com/">npmjs.com/</a> </p><p>想要找到一个合适的依赖包可能并不是一件容易的事。这时，可以使用网站<a href="https://link.zhihu.com/?target=https://npms.io/">https://</a><a href="https://link.zhihu.com/?target=https://npms.io/">npms.io/</a>，这里将各个包的质量、受欢迎度、可维护性等指标做了量化。这些指标包括：是否使用了过时的依赖包、是否有代码检查配置、是否经过测试以及最近的版本是何时发布的等。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081059167.webp"></p><p>不过，更直接方法可能就是去搜索引擎看别人的推荐了~</p><h3 id="7-更新、卸载依赖"><a href="#7-更新、卸载依赖" class="headerlink" title="7. 更新、卸载依赖"></a>7. 更新、卸载依赖</h3><p>npm 为我们提供了更新依赖版本的命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm update [package name]</span><br></pre></td></tr></table></figure><p>如果想要更新全局安装的模块，需要添加参数 -global：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm update -global [package name]</span><br></pre></td></tr></table></figure><p>当执行这两个命令时，它会先到远程仓库查询最新版本，然后查询本地版本。如果本地版本不存在，或者远程版本较新，就会安装。</p><p>如果想要更新该依赖包在package.json中的版本，就需要使用-S或者–save参数。需要注意的是，从npm v2.6.1 开始，npm update只会更新顶层的模块，而不更新依赖的依赖模块，而之前的版本是递归更新的。如果想要这种效果，可以使用以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm --depth 9999 update</span><br></pre></td></tr></table></figure><p>除了可以更新包之外，还可以删除指定的包：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall [package name]</span><br></pre></td></tr></table></figure><p>如果想要删除全局的包，需要添加参数 -global：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall [package name] -global</span><br></pre></td></tr></table></figure><h3 id="8-查找过时的包"><a href="#8-查找过时的包" class="headerlink" title="8. 查找过时的包"></a>8. 查找过时的包</h3><p>npm 提供了一个命令来查看过时的依赖：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm outdated</span><br></pre></td></tr></table></figure><p>在我的项目中执行该命令，输出结果如下：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081101825.webp"></p><p>可以看到，这里列出了过时依赖的包名称、当前的版本、希望的版本、最新的版本、依赖在本地路径、依赖这个包的项目名称。</p><p>可以通过以下命令来检查npm包的最新版本：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">// 展示包的信息</span><br><span class="line">npm view &lt;package-name&gt;</span><br><span class="line">npm v &lt;package-name&gt;// 展示最新版本</span><br><span class="line">npm v &lt;package-name&gt; version// 展示所有版本</span><br><span class="line">npm v &lt;package-name&gt; versions</span><br></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081101641.webp"></p><h3 id="9-执行脚本"><a href="#9-执行脚本" class="headerlink" title="9. 执行脚本"></a>9. 执行脚本</h3><p>npm 不仅可以用于管理模块，还可以用于执行脚本。在package.json文件中有一个scripts字段，可以用于定义脚本命令，功npm 使用。我们除了可以在package.json文件中查看有哪些命令，也可以使用以下命令来查看所有脚本命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run</span><br></pre></td></tr></table></figure><p>我的项目中执行该命令之后的结果如下：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081102047.webp"></p><p>可以看到，这里定义了dev、build、build:test等命令，如果需要执行这些命令，只要这样执行即可：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm run dev</span><br><span class="line">npm run build</span><br></pre></td></tr></table></figure><p>这里不在多说，这或许是我们平时用的最多的命令了，可以根据实际开发情况，来定制自己的npm命令。</p><h3 id="10-安装可靠的依赖"><a href="#10-安装可靠的依赖" class="headerlink" title="10. 安装可靠的依赖"></a>10. 安装可靠的依赖</h3><p>可以使用 npm ci 命令来清理、安装依赖项。它通常用于CI/CD等自动化环境，使用它可以获得可靠的依赖。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm ci</span><br></pre></td></tr></table></figure><p>当执行该命令时，它会先删除本地的node_modules文件，因此它不需要去校验已下载文件版本与控制版本的关系，也不用校验是否存在最新版本的库，所以下载的速度相比npm install会更快。之后它会按照 package-lock.json 文件来安装确切版本的依赖项。并且不会将这个版本写入package.json或者package-lock.json文件。</p><p>使用该命令时，需要注意：</p><ul><li>项目必需有 package-lock.json 或 npm-shrinkwrap.json 文件，如果没有，该命令将不起作用；</li><li>npm ci 是 npm v6 中引入了的新命令，所以使用该命令时需要确保npm版本要&gt;=5.7；</li><li>npm ci 不能用来安装单个依赖，只能用来安装整个项目的依赖；</li><li>npm ci 会安装 dependencies 和 devDependencies；</li><li>整个安装过程不会更新 package.json 或 package-lock.json 文件，整个安装过程是锁死的；</li><li>当package-lock.json中的依赖和package.json中不一致时，npm ci 会退出但不会修改package-lock.json文件。</li></ul><h3 id="11-删除重复的包"><a href="#11-删除重复的包" class="headerlink" title="11. 删除重复的包"></a>11. 删除重复的包</h3><p>我们可以通过运行npm dedupe命令来删除重复的依赖项。该命令通过删除重复包并在多个依赖包之间共享公共依赖项来简化整体的结构。它会产生一个扁平的、去重的树。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm dedupenpm ddp</span><br></pre></td></tr></table></figure><h3 id="12-扫描漏洞"><a href="#12-扫描漏洞" class="headerlink" title="12. 扫描漏洞"></a>12. 扫描漏洞</h3><p>可以运行 npm audit 命令来扫描项目，来查找所有依赖项中存在的漏洞：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm audit</span><br></pre></td></tr></table></figure><p>来看我的项目扫描结果：</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081103085.webp"></p><p>可以运行以下命令来自动安装所有易受攻击包的补丁版本：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm audit fix</span><br></pre></td></tr></table></figure><h3 id="13-列举已安装的包"><a href="#13-列举已安装的包" class="headerlink" title="13. 列举已安装的包"></a>13. 列举已安装的包</h3><p>可以通过以下命令来获取整个项目的包信息：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm list</span><br></pre></td></tr></table></figure><p>npm list命令以树型结构列出当前项目安装的所有模块，以及它们依赖的模块。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081104811.webp"></p><p>如果加上global参数，就会列出全局安装的模块：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm list -global</span><br></pre></td></tr></table></figure><p>也可以查看指定包的依赖，比如在我现在做的项目下，执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm list react</span><br></pre></td></tr></table></figure><p>还可以使用npm ls 命令来查看指定包的依赖信息：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm ls react</span><br></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402081105717.webp"></p><p>可以使用–depth参数来限制搜索的深度：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm ls --depth=1</span><br></pre></td></tr></table></figure><h3 id="14-测试本地包"><a href="#14-测试本地包" class="headerlink" title="14. 测试本地包"></a>14. 测试本地包</h3><p>当我们在本地开发npm模块时，可以使用npm link命令来将本地的npm模块连接到对用的项目中去，便于对模块进行调试和测试。使用方式也很简单，在项目中执行以下命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm link</span><br></pre></td></tr></table></figure><p>执行完该命令之后，就会为这个npm包创建到全局，路径是{prefix}/lib/node_modules/<package>，它是一个快捷方式。之后我们就可以使用以下命令来在需要这个模块的项目中链接这个包：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm link 模块名</span><br></pre></td></tr></table></figure><p>这里的模块名就是依赖包的名称，也就是模块包的package.json文件中的name字段值。</p><p>如果不想继续使用了，执行以下命令来解除link即可：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm unlink 模块名</span><br></pre></td></tr></table></figure><h3 id="15-npm安装包位置修改"><a href="#15-npm安装包位置修改" class="headerlink" title="15. npm安装包位置修改"></a>15. npm安装包位置修改</h3><p>（1）修改npm全局安装位置</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config set prefix &quot;D:\Users\Allen&#x27;s hp\npm&quot;</span><br></pre></td></tr></table></figure><p>（2） 修改npm缓存位置</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config set cache &quot;D:\Users\Allen&#x27;s hp\npm-cache&quot;</span><br></pre></td></tr></table></figure><p>（3）修改系统环境变量</p><p>将以上两个路径添加至系统变量Path即可</p><p>（4）检测</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm config list # 查看npm相关配置</span><br><span class="line">npm root -g # 查看全局包的安装路径</span><br></pre></td></tr></table></figure><h3 id="16-cnpm-和-nrm"><a href="#16-cnpm-和-nrm" class="headerlink" title="16. cnpm 和 nrm"></a>16. cnpm 和 nrm</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># 安装</span><br><span class="line">npm install -g cnpm --registry=https://registry.npmmirror.com</span><br><span class="line"></span><br><span class="line"># 检测是否安装正常</span><br><span class="line">cnpm -v</span><br></pre></td></tr></table></figure><p>它的实质是：</p><ul><li>全局安装 cnpm</li><li>并且将安装 ‘ 包 ‘（各种包） 的地址切换到 国内的淘宝镜像</li></ul><p>这里面省略了一个很重要的东西，就是 nrm 的使用，这个包的功能可以让我们随意的切换我们下载包的地址。</p><ul><li><p>如果装好了 cnpm 可以， <code>cnpm i nrm -g</code></p></li><li><p><code>nrm ls</code> 查看所有 包下载路径， 也就是存放包的不同位置，自然就有取包的速度区分</p></li><li><p><code>nrm use</code> 使用包路径， 当然也可以直接用 <code>nrm help</code> 查看 nrm 功能帮助</p></li></ul><h3 id="17-三种方式设置npm的registry"><a href="#17-三种方式设置npm的registry" class="headerlink" title="17. 三种方式设置npm的registry"></a>17. 三种方式设置npm的registry</h3><p>（1）原npm地址</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config set registry http://registry.npmjs.org</span><br></pre></td></tr></table></figure><p>（2）设置国内镜像</p><ul><li>a. 通过config命令</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm config set registry https://registry.npmmirror.com</span><br><span class="line">npm info underscore （如果上面配置正确这个命令会有字符串response）</span><br></pre></td></tr></table></figure><ul><li>b. 命令行指定</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm --registry https://registry.npmmirror.com info underscore</span><br></pre></td></tr></table></figure><ul><li>c. 编辑 ~/.npmrc 加入下面内容</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">registry = https://registry.npmmirror.com</span><br></pre></td></tr></table></figure><p>（3）使用nrm管理registry地址</p><ul><li>a. 下载nrm</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g nrm</span><br></pre></td></tr></table></figure><ul><li>b. 添加registry地址</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nrm add npm http://registry.npmjs.org</span><br><span class="line">nrm add taobao https://registry.npmmirror.com</span><br></pre></td></tr></table></figure><ul><li>c. 切换npm registry地址</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nrm use taobao</span><br><span class="line">nrm use npm</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA/">项目构建</category>
      
      
      <comments>https://blog.helloallen.cn/1db99446/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>使用 OPFS 实现高性能本地文件访问</title>
      <link>https://blog.helloallen.cn/e9d5263c/</link>
      <guid>https://blog.helloallen.cn/e9d5263c/</guid>
      <pubDate>Fri, 08 Dec 2023 10:15:37 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>相比于本地应用而言，目前在Web应用中对于文件系统的操作一直是比较困难的。</p><p>然而，在js刚出世时，是可以直接读写所有文件的，这导致当时产生了很多js病毒，带来了很严重的安全问题。后来才禁止了js读写任何文件，这又导致很多功能（比如选择文件并修改保存）基本是无法实现的，只能通过上传、修改、下载等不够流畅的交互来实现。  </p><p>但是现在，随着web应用的不断发展，上述痛点已经被File System Access API基本解决了。</p><h2 id="一、File-System-Access-API"><a href="#一、File-System-Access-API" class="headerlink" title="一、File System Access API"></a>一、File System Access API</h2><p>File System Access API 是一个允许 Web 应用访问和操作用户设备文件系统的 API。通过这个 API，我们可以在用户的许可下，读取和修改文件，以及访问目录结构。</p><h2 id="1、window-showOpenFilePicker"><a href="#1、window-showOpenFilePicker" class="headerlink" title="1、window.showOpenFilePicker()"></a>1、window.showOpenFilePicker()</h2><p>显示一个允许用户选择一个或多个文件的文件选择器。异步返回一个FileSystemFileHandle对象的数组。</p><h2 id="2、window-showSaveFilePicker"><a href="#2、window-showSaveFilePicker" class="headerlink" title="2、window.showSaveFilePicker()"></a>2、window.showSaveFilePicker()</h2><p>显示一个允许用户保存文件的文件选择器，可以选择现有文件或输入新文件的名称。 异步返回一个FileSystemFileHandle对象。</p><h2 id="3、window-showDirectoryPicker"><a href="#3、window-showDirectoryPicker" class="headerlink" title="3、window.showDirectoryPicker()"></a>3、window.showDirectoryPicker()</h2><p>显示一个目录选择器，允许用户选择一个目录。异步返回一个FileSystemDirectoryHandle对象</p><h2 id="4、DataTransferItem-getAsFileSystemHandle"><a href="#4、DataTransferItem-getAsFileSystemHandle" class="headerlink" title="4、DataTransferItem.getAsFileSystemHandle()"></a>4、DataTransferItem.getAsFileSystemHandle()</h2><p>在拖动事件中使用，如果拖动元素是一个文件则异步返回一个FileSystemFileHandle对象的数组。 如果拖动元素是一个目录则异步返回一个FileSystemFileHandle对象。</p><h2 id="5、StorageManager-getDirectory"><a href="#5、StorageManager-getDirectory" class="headerlink" title="5、StorageManager.getDirectory()"></a>5、StorageManager.getDirectory()</h2><p>从当前网站或者应用程序中的私有存储空间（origin private file system）中读取目录及内容。</p><p>注意：</p><p>访问 OPFS 中的文件不需要权限提示。</p><p>清除网站的数据会删除 OPFS。</p><p>OPFS 受浏览器的存储空间配额限制。</p><h2 id="二、使用示例"><a href="#二、使用示例" class="headerlink" title="二、使用示例"></a>二、使用示例</h2><h2 id="1、读取文件"><a href="#1、读取文件" class="headerlink" title="1、读取文件"></a>1、读取文件</h2><p>要读取一个文件，我们首先需要让用户选择一个文件。使用 File System Access API，我们可以通过 window.showOpenFilePicker() 函数实现这一目的：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">async function readFile() &#123;</span><br><span class="line">  try &#123;</span><br><span class="line">    const [fileHandle] = await window.showOpenFilePicker();</span><br><span class="line">    const file = await fileHandle.getFile();</span><br><span class="line">    const contents = await file.text();</span><br><span class="line">    console.log(contents);</span><br><span class="line">  &#125; catch (err) &#123;</span><br><span class="line">    console.error(&#x27;Error reading file:&#x27;, err);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">readFile();</span><br></pre></td></tr></table></figure><p>这个函数会触发一个文件选择对话框，用户可以在其中选择一个文件。成功获取到文件后，我们可以通过 fileHandle.getFile() 获得一个 File 对象，并使用 file.text() 读取文件内容。</p><h2 id="2、保存文件"><a href="#2、保存文件" class="headerlink" title="2、保存文件"></a>2、保存文件</h2><p>与读取文件类似，我们需要通过 window.showSaveFilePicker() 函数让用户选择一个文件位置来保存文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">async function saveFile(contents) &#123;</span><br><span class="line">  try &#123;</span><br><span class="line">    const fileHandle = await window.showSaveFilePicker();</span><br><span class="line">    const writable = await fileHandle.createWritable();</span><br><span class="line">    await writable.write(contents);</span><br><span class="line">    await writable.close();</span><br><span class="line">  &#125; catch (err) &#123;</span><br><span class="line">    console.error(&#x27;Error saving file:&#x27;, err);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">const contentsToSave = &#x27;This is a test file.&#x27;;</span><br><span class="line">saveFile(contentsToSave);</span><br></pre></td></tr></table></figure><p>window.showSaveFilePicker() 返回一个文件句柄，我们可以通过 fileHandle.createWritable() 创建一个可写流，并使用 writable.write() 将内容写入文件。最后，使用 writable.close() 关闭流。</p><h2 id="三、兼容性与权限"><a href="#三、兼容性与权限" class="headerlink" title="三、兼容性与权限"></a>三、兼容性与权限</h2><p>截至 2021 年 9 月，File System Access API 主要在 Chromium 内核的浏览器上得到支持，包括 Chrome、Edge 和 Opera。不过，随着技术的发展，更多的浏览器可能会支持这一 API。为了确保你的应用在不同的浏览器上运行良好，请务必检查浏览器的兼容性。</p><p>版权声明：本文为CSDN博主「一贱你就笑～」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。</p><p>原文链接：<a href="https://blog.csdn.net/qq_38629292/article/details/129659106">https://blog.csdn.net/qq_38629292/article/details/129659106</a></p>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</category>
      
      
      <comments>https://blog.helloallen.cn/e9d5263c/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>更现代化方式实现明暗模式，两行CSS搞定！</title>
      <link>https://blog.helloallen.cn/cf6de2f6/</link>
      <guid>https://blog.helloallen.cn/cf6de2f6/</guid>
      <pubDate>Sun, 03 Dec 2023 22:27:29 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>在Web开发中，有时希望能够根据用户的偏好模式（明暗模式）来更改网页的颜色。以前们需要使用媒体查询（prefers-color-scheme）来实现这个功能。但现在，CSS提供了一个更简单的方法：light-dark()函数。这个函数可以接受两种不同的颜色作为参数，根据当前所使用的颜色方案，自动输出其中的一种颜色，从而实现自适应的颜色显示。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032228583.png"></p><h2 id="一、以前的明暗模式实现"><a href="#一、以前的明暗模式实现" class="headerlink" title="一、以前的明暗模式实现"></a>一、以前的明暗模式实现</h2><p>要根据所使用的浅色模式或深色模式更改颜色值，通常会使用 prefers-color-scheme 媒体查询来更改自定义属性的值：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">:root &#123;</span><br><span class="line">  --text-color: #333; /* 浅色模式的值 */</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">@media (prefers-color-scheme: dark) &#123;</span><br><span class="line">  --text-color: #ccc; /* 深色模式的值 */</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在实现深色模式时，通常会出现一堆重复的CSS变量，用于设置每种模式的值。然后，CSS 将使用这些自定义属性进行实际声明。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">body &#123;</span><br><span class="line">  color: var(--text-color);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="二、未来的明暗模式实现"><a href="#二、未来的明暗模式实现" class="headerlink" title="二、未来的明暗模式实现"></a>二、未来的明暗模式实现</h2><p>CSS 颜色模块第 5 级规范[1]的新增了 light-dark() 函数。该函数接受两个颜色值作为其参数。根据正在使用的颜色方案，它将输出第一个或第二个颜色参数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">light-dark(&lt;color&gt;, &lt;color&gt;);</span><br></pre></td></tr></table></figure><p>根据规范，如果使用的颜色方案是light或未知，则该函数计算为第一种颜色的计算值；如果使用的颜色方案是dark，则计算为第二种颜色的计算值。</p><p>使用的颜色方案不仅是用户选择的亮暗模式，还需要根据color-scheme属性的值确定使用的颜色方案。color-scheme属性可以指示元素使用哪种颜色方案进行渲染，这个方案会与用户的偏好进行协商，最终确定使用的颜色方案。因此，在使用light-dark()函数时，还需要在CSS中包含对应的color-scheme声明，以确保函数能够正确工作。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">:root &#123;</span><br><span class="line">  color-scheme: light dark;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">:root &#123;</span><br><span class="line">  --text-color: light-dark(#333, #ccc);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>对于上面的代码，在浅色模式下返回第一个值，在深色模式下返回第二个值。</p><p>由于设置了color-scheme，这意味着可以针对某个元素覆盖其值，以强制其进入特定模式。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">.dark &#123;</span><br><span class="line">  color-scheme: dark;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>对于上面的代码，该元素及其子元素上的 light-dark() 将始终返回 dark对应的值。</p><h2 id="三、Demo"><a href="#三、Demo" class="headerlink" title="三、Demo"></a>三、Demo</h2><p>如果你的浏览器支持light-dark()函数，下面的演示将显示几个标有.auto的元素，这些元素会响应切换到浅色或深色模式。而具有.light或.dark类的元素则强制进入它们的正确模式。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">#demo &#123;</span><br><span class="line">    color-scheme: light dark;</span><br><span class="line">    </span><br><span class="line">    .dark &#123;</span><br><span class="line">        color-scheme: dark;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    .light &#123;</span><br><span class="line">        color-scheme: light;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    &amp; div &#123;</span><br><span class="line">        background: light-dark(#d4d4d4, #000);</span><br><span class="line">        color: light-dark(#333, #ccc);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="浏览器支持"><a href="#浏览器支持" class="headerlink" title="浏览器支持"></a>浏览器支持</h2><p>light-dark() 函数的浏览器支持如下：</p><ul><li>Chromium (Blink)：  ❌ 不支持。</li><li>Firefox (Gecko)：  ✅ Firefox 120 开始支持。</li><li>Safari (WebKit)：  ❌ 不支持。</li></ul><p>可以通过以下代码来判断当前使用的浏览器是否支持 CSS light-dark()函数：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">@supports(color: light-dark(#fff, #000)) &#123;</span><br><span class="line">    #output::after &#123;</span><br><span class="line">        content: &quot;✅ 浏览器支持 light-dark()&quot;;</span><br><span class="line">        background-color: #00ff002b;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/CSS/">CSS</category>
      
      
      <comments>https://blog.helloallen.cn/cf6de2f6/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>60 个 CSS 选择器，一网打尽！</title>
      <link>https://blog.helloallen.cn/cd68f417/</link>
      <guid>https://blog.helloallen.cn/cd68f417/</guid>
      <pubDate>Sun, 03 Dec 2023 22:06:23 GMT</pubDate>
      
        
        
      <description></description>
        
      
      
      
      <content:encoded><![CDATA[<p>CSS 选择器用于选择 HTML 元素并将样式应用于它们。使用这些选择器，可以定义特定条件下应用哪些样式。除了普通的选择器外，还有伪类和伪元素，用于选择具有特定状态或特定部分的元素，并将样式应用于它们。本文将通过图文并茂的方式展示这些选择器的使用方法！</p><h2 id="选择器优先级"><a href="#选择器优先级" class="headerlink" title="选择器优先级"></a>选择器优先级</h2><p>当一个元素同时被多个选择器选中时，会根据它们的优先级进行选择。</p><p>选择器优先级从高到低依次为：</p><ul><li><code>!important</code></li><li>内联选择器(style)</li><li>ID选择器</li><li>类选择器 == 属性选择器 == 伪类选择器(:hover、:active、:visited、:focus、:first-child、:last-child、:nth-child(n)等)</li><li>元素选择器(div、p、span等) == 伪元素选择器(::before、::after、::first-letter、::first-line)</li><li>通配符选择器(*) == 子选择器(#parent &gt; .child) == 相邻选择器(#first + p) == 后代选择器(#menu li)。</li></ul><p>如果有多个选择器的优先级相同，则后面的选择器会覆盖前面的选择器。</p><h2 id="选择器"><a href="#选择器" class="headerlink" title="选择器"></a>选择器</h2><h3 id="1、通用选择器"><a href="#1、通用选择器" class="headerlink" title="1、通用选择器"></a>1、通用选择器</h3><p>通用选择器使用 * 来选择全部元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032207946.png"></p><h3 id="2、元素选择器"><a href="#2、元素选择器" class="headerlink" title="2、元素选择器"></a>2、元素选择器</h3><p>同于选择指定 HTML 元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032207237.png"></p><h3 id="3、类选择器"><a href="#3、类选择器" class="headerlink" title="3、类选择器"></a>3、类选择器</h3><p>选择具有指定类名的所有元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032207134.png"></p><h3 id="4、ID选择器"><a href="#4、ID选择器" class="headerlink" title="4、ID选择器"></a>4、ID选择器</h3><p>选择具有指定ID的元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032208238.png"></p><h3 id="5、组合选择器"><a href="#5、组合选择器" class="headerlink" title="5、组合选择器"></a>5、组合选择器</h3><p>连接两个或多个类名或 ID，以选择具有所有指定类名/ID的元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032208352.png"></p><h3 id="6、多重选择器"><a href="#6、多重选择器" class="headerlink" title="6、多重选择器"></a>6、多重选择器</h3><p>使用逗号将多个选择器声明分开，这样可以很容易地将相同的样式应用于多个选择器声明。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032209779.png"></p><h3 id="7、后代选择器"><a href="#7、后代选择器" class="headerlink" title="7、后代选择器"></a>7、后代选择器</h3><p>后代选择器表示选择某个元素的所有后代元素，即位于该元素内部的所有子孙元素。在使用后代选择器时，在两个选择器之间加上一个空格，表示前一个选择器所选中的元素中包含的后代元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032209216.png"></p><h3 id="8、相邻选择器"><a href="#8、相邻选择器" class="headerlink" title="8、相邻选择器"></a>8、相邻选择器</h3><p>相邻选择器用于选择紧接在另一个元素后面的直接相邻兄弟元素的选择器，使用加号（+）作为组合符号，将两个选择器连接起来。它选择的是位于第一个选择器后紧邻的同级元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032210986.png"></p><h3 id="9、子选择器"><a href="#9、子选择器" class="headerlink" title="9、子选择器"></a>9、子选择器</h3><p>子选择器用于选择某个元素的直接子元素，使用大于号（&gt;）作为组合符号，将两个选择器连接起来。它选择的是父级元素下的直接子元素，即元素树结构中的一级关系。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032210570.png"></p><h3 id="10、通用兄弟选择器"><a href="#10、通用兄弟选择器" class="headerlink" title="10、通用兄弟选择器"></a>10、通用兄弟选择器</h3><p>通用兄弟选择器使用波浪号（即通用兄弟组合符）来选择在第一个选择器之前的所有元素，而不要求它们是第一个选择器的直接兄弟元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032211760.png"></p><h3 id="11、猫头鹰选择器"><a href="#11、猫头鹰选择器" class="headerlink" title="11、猫头鹰选择器"></a>11、猫头鹰选择器</h3><p>猫头鹰选择器用于选择所有具有前置兄弟元素的元素，用来在一个容器内的元素之间添加间距，但不包括第一个元素，因为第一个元素没有前置兄弟元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032211591.png"></p><h3 id="12、属性选择器"><a href="#12、属性选择器" class="headerlink" title="12、属性选择器"></a>12、属性选择器</h3><p>属性选择器用于选择具有特定属性的元素。</p><ul><li>使用[attribute]来选择所有具有 attribute 属性的元素：</li></ul><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032212767.png"></p><ul><li>使用 [attribute=value] 来选择具有指定属性及属性值的元素：</li></ul><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032212971.png"></p><ul><li>使用 [attribute~=value] 来选择具有指定属性，并且该属性的多个值中包含给定值的元素：</li></ul><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032213152.png"></p><ul><li>使用 [attribute*=value] 来选择具有指定属性，并且该属性的值中包含特定部分值的元素。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032213112.png"></p><ul><li>使用 [attribute^=value] 来选择具有指定属性，并且该属性的值以给定值开头的元素。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032214069.png"></p><ul><li>使用 [attribute$=value] 来选择具有指定属性，并且该属性的值以给定值结尾的元素。</li></ul><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032214991.png"></p><h2 id="伪类"><a href="#伪类" class="headerlink" title="伪类"></a>伪类</h2><h3 id="1、链接伪类选择器"><a href="#1、链接伪类选择器" class="headerlink" title="1、链接伪类选择器"></a>1、链接伪类选择器</h3><p>这 4 个伪类用于选择链接处于不同状态的元素。它们最常与链接一起使用，但是 :active 也适用于按钮，而 :hover 可以用于各种元素：</p><ul><li>:link：选取未被访问过的链接，用于为用户尚未点击的超链接设置样式。</li><li>:visited：选取已经被用户访问过的链接，用于为用户之前点击过的超链接设置样式。</li><li>:hover：当用户指针（例如鼠标光标）悬停在某些元素（通常是链接）上时，选取这些元素。</li><li>:active：在元素（通常是链接或按钮）被激活时，例如用户点击它们的瞬间，选取这些元素。</li></ul><p>这 4 个伪类可用于提高用户交互性，例如增加链接的可见度，使其更加显著突出，从而改善用户体验。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032215487.png"></p><h3 id="2、-focus-伪类"><a href="#2、-focus-伪类" class="headerlink" title="2、:focus 伪类"></a>2、:focus 伪类</h3><p>:focus 伪类用于选择当前获得焦点的元素。当用户与网页上的表单元素进行交互时，可以通过点击或键盘导航，使某个特定的输入框处于焦点状态。这意味着用户的输入将直接应用到该输入框上。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032215627.png"></p><h3 id="3、-checked-伪类"><a href="#3、-checked-伪类" class="headerlink" title="3、:checked 伪类"></a>3、:checked 伪类</h3><p>:checked 伪类用于选择当前被选中或选择的单选按钮、复选框或 select 元素的选项。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032215044.png"></p><h3 id="4、-disabled-伪类"><a href="#4、-disabled-伪类" class="headerlink" title="4、:disabled 伪类"></a>4、:disabled 伪类</h3><p>:disabled 伪类用于匹配被禁用的表单元素，例如按钮或文本输入框。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032216244.png"></p><h3 id="5、-enabled-伪类"><a href="#5、-enabled-伪类" class="headerlink" title="5、:enabled 伪类"></a>5、:enabled 伪类</h3><p>:enabled 伪类用于匹配可以交互和接收输入的表单元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032216789.png"></p><h3 id="6、-valid-伪类"><a href="#6、-valid-伪类" class="headerlink" title="6、:valid 伪类"></a>6、:valid 伪类</h3><p>:valid 伪类用于选择具有与其属性（如 pattern、type 等）所指定要求相匹配的内容的输入元素。</p><p>当 input 元素的内容符合其属性所指定的要求时，可以使用 :valid 伪类选择它们。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032217292.png"></p><h3 id="7、-invalid-伪类"><a href="#7、-invalid-伪类" class="headerlink" title="7、:invalid 伪类"></a>7、:invalid 伪类</h3><p>:invalid 伪类用于选择具有内容不符合要求的输入元素。</p><p>当input元素的内容不符合其要求时，可以使用 :invalid 伪类来选择它们。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032217165.png"></p><h3 id="8、-required-伪类"><a href="#8、-required-伪类" class="headerlink" title="8、:required 伪类"></a>8、:required 伪类</h3><p>:required 伪类用于选择具有 required 属性的输入元素，该属性表示在提交表单之前必须填写它们。</p><p>当 input 元素具有 required 属性时，可以使用 :required 伪类选择它们。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032217809.png"></p><h3 id="9、-optional-伪类"><a href="#9、-optional-伪类" class="headerlink" title="9、:optional 伪类"></a>9、:optional 伪类</h3><p>:optional 伪类用于选择没有 required 属性的输入元素，这意味着它们不是必填项。</p><p>当input 元素没有 required 属性时，可以使用 :optional 伪类选择它们。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032218921.png"></p><h3 id="10、-first-child-伪类"><a href="#10、-first-child-伪类" class="headerlink" title="10、:first-child 伪类"></a>10、:first-child 伪类</h3><p>:first-child 伪类用于选择父元素中的第一个子元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032218948.png"></p><h3 id="11、-last-child-伪类"><a href="#11、-last-child-伪类" class="headerlink" title="11、:last-child 伪类"></a>11、:last-child 伪类</h3><p>:last-child 伪类用于选择父元素中的最后一个子元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032219309.png"></p><h3 id="12、-nth-child-伪类"><a href="#12、-nth-child-伪类" class="headerlink" title="12、:nth-child 伪类"></a>12、:nth-child 伪类</h3><p>:nth-child 伪类根据元素在父元素中的位置进行选择，允许进行各种选择。:nth-child 还可以自定义模式选择元素：</p><ul><li>:nth-child(odd) 或 :nth-child(2n+1) 选择每个奇数位置的子元素</li><li>:nth-child(even) 或 :nth-child(2n) 选择每个偶数位置的子元素</li></ul><p>公式中的 n 就像一个计数器，可以按重复周期选择元素。例如，:nth-child(3n) 将选择每三个元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032219284.png"></p><h3 id="13、-nth-last-child-伪类"><a href="#13、-nth-last-child-伪类" class="headerlink" title="13、:nth-last-child 伪类"></a>13、:nth-last-child 伪类</h3><p>:nth-last-child 伪类与 :nth-child 类似，但是从最后一个子元素向后计数。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032219361.png"></p><h3 id="14、-only-child-伪类"><a href="#14、-only-child-伪类" class="headerlink" title="14、:only-child 伪类"></a>14、:only-child 伪类</h3><p>当需要选择在其父级元素中唯一的一个子元素时，可以使用 :only-child 伪类。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032220140.png"></p><h3 id="15、-first-of-type-伪类？？"><a href="#15、-first-of-type-伪类？？" class="headerlink" title="15、:first-of-type 伪类？？"></a>15、:first-of-type 伪类？？</h3><p>:first-of-type 伪类选择在其父元素中的特定类型的元素中的第一个元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032220035.png"></p><h3 id="16、-last-of-type-伪类"><a href="#16、-last-of-type-伪类" class="headerlink" title="16、:last-of-type 伪类"></a>16、:last-of-type 伪类</h3><p>:last-of-type 伪类选择在其父元素中的特定类型的元素中的最后一个元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032221936.png"></p><h3 id="17、-nth-of-type-伪类"><a href="#17、-nth-of-type-伪类" class="headerlink" title="17、:nth-of-type 伪类"></a>17、:nth-of-type 伪类</h3><p>当需要根据元素在兄弟元素中的类型和位置选择元素时，可以使用 :nth-of-type 伪类。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032221677.png"></p><h3 id="18、-nth-last-of-type-伪类"><a href="#18、-nth-last-of-type-伪类" class="headerlink" title="18、:nth-last-of-type 伪类"></a>18、:nth-last-of-type 伪类</h3><p>:当需要根据元素在兄弟元素中的类型和位置选择元素，并且从末尾开始计数时，可以使用 :nth-last-of-type 伪类。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032222196.png"></p><h3 id="19、-only-of-type-伪类"><a href="#19、-only-of-type-伪类" class="headerlink" title="19、:only-of-type 伪类"></a>19、:only-of-type 伪类</h3><p>当需要选择在其兄弟元素中为特定类型的元素仅有一个的元素时，可以使用 :only-of-type 伪类。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032222900.png"></p><h3 id="20、-target-伪类"><a href="#20、-target-伪类" class="headerlink" title="20、:target 伪类"></a>20、:target 伪类</h3><p>:target 用于选择具有与 URL 片段匹配的 ID 属性的元素。URL 片段是指 URL 中的 # 符号后面的部分。当从页面中的链接点击跳转到带有特定片段的 URL 时，:target 伪类将会被应用于与片段匹配的对应元素上。这样可以利用 :target 来为被直接链接到的页面部分设置不同的样式，从而提供视觉上的反馈和突出显示。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032223899.png"></p><h3 id="21、-not-伪类"><a href="#21、-not-伪类" class="headerlink" title="21、:not() 伪类"></a>21、:not() 伪类</h3><p>使用 :not() 伪类可以选择不符合指定选择器或条件的元素。这在需要排除某些特定元素时非常有用。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032223884.png"></p><h3 id="22、has-伪类"><a href="#22、has-伪类" class="headerlink" title="22、has() 伪类"></a>22、has() 伪类</h3><p>使用 :has() 伪类可以选择包含某个特定元素或选择器的父级元素，并为其应用样式。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032223897.png"></p><h3 id="23、其他伪类"><a href="#23、其他伪类" class="headerlink" title="23、其他伪类"></a>23、其他伪类</h3><p>除了上面提到的伪类，CSS中还包含以下伪类：</p><ul><li>:root：选择文档中最高级别的父元素，通常是HTML文档中的 <html> 元素。可用于定义对所有页面元素可用的CSS变量。</li><li>:is()：匹配可以是多个选择器之一的元素，使得长的选择器列表更加简短和易读。例如，:is(h1, h2, h3) 会匹配这三个标题元素之一。</li><li>:where()：与 :is() 类似，但允许根据条件选择元素，而不影响选择器的特异性。</li><li>:default：匹配设置为默认选择状态的用户界面元素（如单选按钮或复选框）。</li><li>:empty：选择没有子元素（包括文本节点）的元素。</li><li>:fullscreen：选择当前以全屏模式显示的元素。</li><li>:in-range：匹配值在指定范围内的表单元素（使用 min 和 max 属性指定范围）。</li><li>:out-of-range：匹配值在指定范围之外的表单元素。</li><li>:indeterminate：选择状态不确定的表单元素，例如既未选中也未取消选中的复选框（在树状结构中经常见到）。</li><li>:read-only：匹配由于 readonly 属性而不可编辑的表单元素。</li><li>:read-write：选择可由用户编辑的表单元素，意味着它们不是只读的。</li><li>:lang()：根据元素的语言属性进行匹配。例如，:lang(en) 选择使用英语定义的元素。</li></ul><h2 id="伪元素"><a href="#伪元素" class="headerlink" title="伪元素"></a>伪元素</h2><h3 id="1、-before-伪元素"><a href="#1、-before-伪元素" class="headerlink" title="1、::before 伪元素"></a>1、::before 伪元素</h3><p>::before 伪元素用于在元素内容之前插入内容。它可以用于添加装饰性内容、图标或其他不需要出现在实际 DOM 中的元素。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032224124.png"></p><h3 id="2、-after-伪元素"><a href="#2、-after-伪元素" class="headerlink" title="2、::after 伪元素"></a>2、::after 伪元素</h3><p>::after 伪元素与 ::before 伪元素类似，用于在元素的内容之后插入内容。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032224515.png"></p><h3 id="3、-first-letter-伪元素"><a href="#3、-first-letter-伪元素" class="headerlink" title="3、::first-letter 伪元素"></a>3、::first-letter 伪元素</h3><p>::first-letter 伪元素用于选择并修改块级元素的第一个字母，从而应用特定的样式。这个伪元素只能选择每个块级元素的第一个字母，并且仅在有文本内容的时候生效。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032225018.png"></p><h3 id="4、-first-line-伪元素"><a href="#4、-first-line-伪元素" class="headerlink" title="4、::first-line 伪元素"></a>4、::first-line 伪元素</h3><p>::first-line 伪元素用于选择并修改块级元素的第一行，从而应用特定的样式。这个伪元素只能选择每个块级元素的第一行，并且仅在有文本内容的时候生效。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032225004.png"></p><h3 id="5、-placeholder-伪元素"><a href="#5、-placeholder-伪元素" class="headerlink" title="5、::placeholder 伪元素"></a>5、::placeholder 伪元素</h3><p>::placeholder 伪元素用于选择并修改表单字段的占位符文本，从而应用特定的样式。占位符文本是在用户未输入任何内容时显示的默认文本。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032225147.png"></p><h3 id="6、-selection-伪元素"><a href="#6、-selection-伪元素" class="headerlink" title="6、::selection 伪元素"></a>6、::selection 伪元素</h3><p>::selection 伪元素用于选择并修改用户所选文本的样式。可以应用于包含文本内容的任何元素，如段落、标题、按钮等。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032226186.png"></p><h3 id="7、-marker-伪元素"><a href="#7、-marker-伪元素" class="headerlink" title="7、::marker 伪元素"></a>7、::marker 伪元素</h3><p>::marker 伪元素用于为列表项中的标记符设置样式，这些标记符通常包含无序列表的项目符号或有序列表的数字/字母。</p><p><img src="https://cdn.jsdelivr.net/gh/HelloAllenW/BlogAssets/images/202402032226156.png"></p><h3 id="8、其他伪元素"><a href="#8、其他伪元素" class="headerlink" title="8、其他伪元素"></a>8、其他伪元素</h3><p>除了上述伪元素之外，CSS 还提供了以下伪元素：</p><ul><li>::file-selector-button：用于选择文件的按钮元素的伪元素。它可以用来样式化文件上传控件中的选择按钮。</li><li>::cue：用于样式化媒体元素（如音频或视频）中的字幕或注释的伪元素。可以用来设置字幕的样式，比如字体、颜色等。</li><li>::part()：用于自定义 Web 组件的内部部件的伪元素。它可以针对组件的具体部分应用样式，并通过组件的 shadow DOM 提供的 Custom Elements API 进行访问。</li><li>::slotted()：用于样式化插槽内容的伪元素。插槽是一种在 Web 组件中用于插入内容的机制，::slotted() 可以应用样式到被插入的内容，以实现更精确的样式控制。</li></ul>]]></content:encoded>
      
      
      <category domain="https://blog.helloallen.cn/categories/Web%E5%89%8D%E7%AB%AF/">Web前端</category>
      
      
      <category domain="https://blog.helloallen.cn/tags/CSS/">CSS</category>
      
      
      <comments>https://blog.helloallen.cn/cd68f417/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
