{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro","result":{"data":{"currentBlog":{"id":"3db31f60-9d84-53dc-b9b9-ae47809f7202","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/20191226/1577353101878-vue.js.png","authors":["yugasun"],"categories":["best-practice"],"date":"2019-12-11T00:00:00.000Z","title":"基于 Serverless Component 全栈解决方案 Ⅱ","description":"如何借助 Serverless Component 快速开发全栈 Web 应用 - 续集","authorslink":["https://github.com/yugasun"],"translators":null,"translatorslink":null,"tags":["Serverless","全栈应用"],"keywords":"Serverless Component,全栈 Web 应用,全栈解决方案","outdated":null},"wordCount":{"words":275,"sentences":54,"paragraphs":53},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro.md","fields":{"slug":"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/","keywords":["serverless","spa","vue","vuejs","website","serverless","fullstack","配置","域名","证书","serverlesscloud"]},"html":"<p>虽然之前的文章 <a href=\"https://yugasun.com/post/serverless-fullstack-vue-practice.html\">基于 Serverless Component 的全栈解决方案</a> 介绍了如何借助 Serverless Component 快速搭建 <code class=\"language-text\">Restful API</code> 后端服务 和 <code class=\"language-text\">Vue.js + Parcel</code> 的前端开发架构，但是最终部署后，腾讯云 COS 的访问 URL 并非自定义的，而且实际应用中，我们更偏向于使用自定义域名，同时静态文件一般都会通过 CDN 加速。那么如何为之前部署的静态网站配置 CDN 加速域名呢？</p>\n<blockquote>\n<p><strong>注意</strong>：在开始阅读本篇文章之前，你需要一个国内备案通过的域名，如果没有，那么本篇文章不太适合你。因为实践类文章，我是极力推荐 <strong>边看边实践</strong> 的，不然也只是看个热闹，看完就忘......</p>\n</blockquote>\n<h2 id=\"配置-cdn\"><a href=\"#%E9%85%8D%E7%BD%AE-cdn\" aria-label=\"配置 cdn permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>配置 CDN</h2>\n<p>登录进入 <a href=\"https://console.cloud.tencent.com/cdn\">CDN（内容分发网络）控制台页面</a>，然后左边菜单选择 <code class=\"language-text\">域名管理</code>：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695508886-fullstack-cdn1.jpg\" alt=\"域名管理\"></p>\n<p>点击 <code class=\"language-text\">添加域名</code> 按钮，进入域名添加页面，因为我们的静态文件是部署在 COS 上，所以源站类型选择 <code class=\"language-text\">对象存储(COS)</code>，接着 <code class=\"language-text\">存储桶设置</code> 选择我们的之前部署好的就行，至于下面的 <code class=\"language-text\">加速服务配置</code>, 一般默认就行，如果有特殊需求，可以自己修改，如下图：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695508405-fullstack-cdn1.jpg\" alt=\"选择静态网站\"></p>\n<p>填写好配置，点击提交，这时部署需要等待大概 2 分钟左右：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695508456-fullstack-cdn1.jpg\" alt=\"添加域名\"></p>\n<p>想通过添加的域名访问，还需要添加一条 <code class=\"language-text\">CNAME</code> 类型的，DNS 解析记录（如果不知道如何添加 CNAME，可以参考此教程 <a href=\"https://cloud.tencent.com/document/product/228/3121\">配置 CNAME</a>），配置好后就可以通过 <a href=\"http://blog.yugasun.com\">http://blog.yugasun.com</a> 访问了。</p>\n<p>但是目前非 HTTPS 的网站，很多浏览器都会有不安全提示，这样用户看到第一反应可能就会畏惧，不会继续访问了。那么如何为加速域名配置 HTTPS 呢？</p>\n<h2 id=\"配置-https\"><a href=\"#%E9%85%8D%E7%BD%AE-https\" aria-label=\"配置 https permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>配置 HTTPS</h2>\n<h3 id=\"准备证书\"><a href=\"#%E5%87%86%E5%A4%87%E8%AF%81%E4%B9%A6\" aria-label=\"准备证书 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>准备证书</h3>\n<p>既然需要配置 HTTPS，肯定是少不了证书，可是一般权威机构的证书都是需要购买的，作为一个 <code class=\"language-text\">qiong bi</code> 程序员，我是骨子里抗拒收费服务的。</p>\n<p>于是抱着侥幸的心理点开了腾讯云的 <a href=\"https://console.cloud.tencent.com/ssl\">SSL 证书</a> 页面，眼前一亮：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695507898-fullstack-cdn1.jpg\" alt=\"申请免费证书\"></p>\n<p>没错就是 <code class=\"language-text\">申请免费证书</code> 按钮！！！！！！</p>\n<p>于是疯狂点击她！选择免费证书机构，填写域名（因为这里是免费证书，所以没法设置泛域名，如：*.yugasun.com）配置一起合成：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695508378-fullstack-cdn1.jpg\" alt=\"申请步骤\"></p>\n<blockquote>\n<p>这里因为我已经申请了 <code class=\"language-text\">blog.yugasun.com</code> 的证书，为了演示，所以填写了 <code class=\"language-text\">demo.yugasun.com</code></p>\n</blockquote>\n<p>配置提交后，选择手动验证，根据指引填写相关 DNS 验证记录：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695507743-fullstack-cdn1.jpg\" alt=\"操作指引\"></p>\n<p>验证通过后就可以使用或下载颁发的免费证书了：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695507970-fullstack-cdn1.jpg\" alt=\"免费证书成功啦\"></p>\n<p>终于可以拥有属于自己的免费证书了，跳个舞，庆祝下~</p>\n<h3 id=\"开始配置\"><a href=\"#%E5%BC%80%E5%A7%8B%E9%85%8D%E7%BD%AE\" aria-label=\"开始配置 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>开始配置</h3>\n<p>证书准备好了，接下来才是正题：为配置好的 CDN 域名，配置 HTTPS。进入 <code class=\"language-text\">域名详情页面</code>，选择 <code class=\"language-text\">高级配置</code>：</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695507732-fullstack-cdn1.jpg\" alt=\"域名详情页\"></p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695507707-fullstack-cdn1.jpg\" alt=\"高级配置\"></p>\n<p>因为是在腾讯云平台申请的免费证书，它会帮我们托管一份，这样我们再配置证书时，可以不用选择上传，只需要从托管的列表中选择就行，是不是很贴心 (*￣︶￣)</p>\n<p><img src=\"https://img.serverlesscloud.cn/20191230/1577695507793-fullstack-cdn1.jpg\" alt=\"证书托管\"></p>\n<p>配置好提交就可以了，到这里我们的所有配置流程已经全部搞定，赶紧访问看看我们的成果吧：<a href=\"https://blog.yugasun.com%E3%80%82\">https://blog.yugasun.com。</a></p>\n<h2 id=\"cdn-serverless-component\"><a href=\"#cdn-serverless-component\" aria-label=\"cdn serverless component permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>CDN Serverless Component</h2>\n<p>上面写了这么多，一定花了大家不少时间吧，可是我真不是故意的，因为我第一次配置的时候也是这么一路艰辛走过来的，我只是想吸引更多志同道合的同志 - <a href=\"https://github.com/yugasun\">GayHub</a>。但是经历一次过后，就再也不想再经历第二次了，实在是太痛苦了......如果你跟我也有同样的感受，那么老铁，千万不要走开，因为接下来的内容将让你的人生更加摇摆。</p>\n<p>你可能要骂我了，我辛辛苦苦付出了这么多，你却说 「不爱我了，因为你喜欢上了渣男」。呵呵，不好意思我也要开始做「渣男」(CDN Component) 了。</p>\n<h3 id=\"修改-serverlessyml-配置\"><a href=\"#%E4%BF%AE%E6%94%B9-serverlessyml-%E9%85%8D%E7%BD%AE\" aria-label=\"修改 serverlessyml 配置 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>修改 serverless.yml 配置</h3>\n<p>首先，请进入 <a href=\"https://yugasun.com/post/serverless-fullstack-vue-practice.html\">基于 Serverless Component 的全栈解决方案</a> 文章创建的项目目录 <code class=\"language-text\">fullstack-application-vue</code>，如果你不想看之前的这一篇，这里也有份项目直通车，运行如下命令即可：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"6397397657780335000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`\\$ serverless create --template-url https://github.com/yugasun/tencent-serverless-demo/tree/master/fullstack-application-vue`, `6397397657780335000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"shell\"><pre class=\"language-shell\"><code class=\"language-shell\">$ serverless create --template-url https://github.com/yugasun/tencent-serverless-demo/tree/master/fullstack-application-vue</code></pre></div>\n<p>修改项目根目录下 <code class=\"language-text\">serverless.yml</code> 配置文件，为 <code class=\"language-text\">@serverless/tencent-website</code> 组件的 <code class=\"language-text\">inputs</code> 新增 <code class=\"language-text\">hosts</code> 配置，如下：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"59422957555383390000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`frontend:\n  component: '@serverless/tencent-website'\n  # 参考: https://github.com/serverless-components/tencent-website/blob/master/docs/configure.md\n  inputs:\n    code:\n      src: dist\n      root: frontend\n      hook: npm run build\n    env:\n      apiUrl: \\${api.url}\n    protocol: https\n    # 以下为 CDN 加速域名配置\n    hosts:\n      - host: blog.yugasun.com\n        https:\n          certId: ZV99hYOj # 这个为你在腾讯云申请的免费证书 ID\n          http2: off\n          httpsType: 4\n          forceSwitch: -2`, `59422957555383390000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">frontend</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'@serverless/tencent-website'</span>\n  <span class=\"token comment\"># 参考: https://github.com/serverless-components/tencent-website/blob/master/docs/configure.md</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">code</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">src</span><span class=\"token punctuation\">:</span> dist\n      <span class=\"token key atrule\">root</span><span class=\"token punctuation\">:</span> frontend\n      <span class=\"token key atrule\">hook</span><span class=\"token punctuation\">:</span> npm run build\n    <span class=\"token key atrule\">env</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">apiUrl</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>api.url<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">protocol</span><span class=\"token punctuation\">:</span> https\n    <span class=\"token comment\"># 以下为 CDN 加速域名配置</span>\n    <span class=\"token key atrule\">hosts</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">host</span><span class=\"token punctuation\">:</span> blog.yugasun.com\n        <span class=\"token key atrule\">https</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">certId</span><span class=\"token punctuation\">:</span> ZV99hYOj <span class=\"token comment\"># 这个为你在腾讯云申请的免费证书 ID</span>\n          <span class=\"token key atrule\">http2</span><span class=\"token punctuation\">:</span> off\n          <span class=\"token key atrule\">httpsType</span><span class=\"token punctuation\">:</span> <span class=\"token number\">4</span>\n          <span class=\"token key atrule\">forceSwitch</span><span class=\"token punctuation\">:</span> <span class=\"token number\">-2</span></code></pre></div>\n<p>OK，配置好了，是的没错，你不用再做任何配置。是不是还没开始就结束了，这正是 “渣男” 带来快感......</p>\n<p>接着执行  <code class=\"language-text\">serverless --debug</code> 命令，静坐喝杯咖啡☕️☕️☕️，刷刷朋友圈，等待部署好就行：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"2706354862250393000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`\\$ serverless --debug\n  // balabala, debug 信息输出\n  frontend:\n    url:  https://br1ovx-efmogqe-1251556596.cos-website.ap-guangzhou.myqcloud.com\n    env:\n      apiUrl: https://service-5y16xi22-1251556596.gz.apigw.tencentcs.com/release/\n    host:\n      - https://blog.yugasun.com (CNAME: blog.yugasun.com.cdn.dnsv1.com）\n  api:\n    region:              ap-guangzhou\n    functionName:        fullstack-vue-api-pro\n    apiGatewayServiceId: service-5y16xi22\n    url:                 https://service-5y16xi22-1251556596.gz.apigw.tencentcs.com/release/\n\n  254s › frontend › done`, `2706354862250393000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"shell\"><pre class=\"language-shell\"><code class=\"language-shell\">$ serverless --debug\n  // balabala, debug 信息输出\n  frontend:\n    url:  https://br1ovx-efmogqe-1251556596.cos-website.ap-guangzhou.myqcloud.com\n    env:\n      apiUrl: https://service-5y16xi22-1251556596.gz.apigw.tencentcs.com/release/\n    host:\n      - https://blog.yugasun.com <span class=\"token punctuation\">(</span>CNAME: blog.yugasun.com.cdn.dnsv1.com）\n  api:\n    region:              ap-guangzhou\n    functionName:        fullstack-vue-api-pro\n    apiGatewayServiceId: service-5y16xi22\n    url:                 https://service-5y16xi22-1251556596.gz.apigw.tencentcs.com/release/\n\n  254s › frontend › <span class=\"token keyword\">done</span></code></pre></div>\n<p>此时你可以开始尽情摇摆了~</p>\n<h2 id=\"更新-frontend-技术栈\"><a href=\"#%E6%9B%B4%E6%96%B0-frontend-%E6%8A%80%E6%9C%AF%E6%A0%88\" aria-label=\"更新 frontend 技术栈 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>更新 Frontend 技术栈</h2>\n<p>之前，为了方便 Demo，使用了 <a href=\"https://github.com/parcel-bundler/parcel\">parcel</a>（一款可快速构建零配置的构建工具），但是对于 Vue.js 开发者来说，大多使用的是官方脚手架工具 <a href=\"https://cli.vuejs.org/\">@vue/cli</a> 来初始化项目的，为了顺应潮流，我也重构了 <code class=\"language-text\">frontend</code> 文件夹下的前端项目。但是这里需要稍微新增一个配置，在根目录下新增 <code class=\"language-text\">vue.config.js</code> 文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"62795815555510240000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`const path = require('path');\nconst PrerenderSPAPlugin = require('prerender-spa-plugin');\n\nmodule.exports = {\n  configureWebpack: {\n    resolve: {\n      // 这新增环境变量别名\n      alias: {\n        ENV: require('path').resolve(__dirname, 'env.js'),\n      },\n    },\n  },\n};`, `62795815555510240000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> path <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> PrerenderSPAPlugin <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'prerender-spa-plugin'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nmodule<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  configureWebpack<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n    resolve<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// 这新增环境变量别名</span>\n      alias<span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token constant\">ENV</span><span class=\"token punctuation\">:</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span>__dirname<span class=\"token punctuation\">,</span> <span class=\"token string\">'env.js'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>然后在我们的入口文件 <code class=\"language-text\">frontend/src/main.js</code> 中引入:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"71936275173652130000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import Vue from 'vue';\nimport App from './App.vue';\n// 引入 api 接口配置 url\nimport 'ENV';\nimport './style/app.css';\n\nVue.config.productionTip = false;\n\nnew Vue({\n  render: (h) => h(App),\n}).\\$mount('#app');`, `71936275173652130000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> Vue <span class=\"token keyword\">from</span> <span class=\"token string\">'vue'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> App <span class=\"token keyword\">from</span> <span class=\"token string\">'./App.vue'</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">// 引入 api 接口配置 url</span>\n<span class=\"token keyword\">import</span> <span class=\"token string\">'ENV'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token string\">'./style/app.css'</span><span class=\"token punctuation\">;</span>\n\nVue<span class=\"token punctuation\">.</span>config<span class=\"token punctuation\">.</span>productionTip <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">new</span> <span class=\"token class-name\">Vue</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token function-variable function\">render</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">h</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">h</span><span class=\"token punctuation\">(</span>App<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">$mount</span><span class=\"token punctuation\">(</span><span class=\"token string\">'#app'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>为什么需要这么做呢？因为 <code class=\"language-text\">express</code> 组件在部署时，会自动在 <code class=\"language-text\">website</code> 组件的 <code class=\"language-text\">inputs.code.root</code> 属性配置的目录中自动生成含有部署的 API 服务的接口文件 <code class=\"language-text\">env.js</code>，如下：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"80269966810361510000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`// frontend/env.js\nwindow.env = {};\nwindow.env.apiUrl = &quot;https://service-5y16xi22-1251556596.gz.apigw.tencentcs.com/release/&quot;;`, `80269966810361510000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// frontend/env.js</span>\nwindow<span class=\"token punctuation\">.</span>env <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\nwindow<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span>apiUrl <span class=\"token operator\">=</span> <span class=\"token string\">\"https://service-5y16xi22-1251556596.gz.apigw.tencentcs.com/release/\"</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>这样我们就可以在前端中使用该接口了：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"33792200606954095000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`// 获得用户列表\nasync getUsers() {\n  this.loading = true;\n  const { data } = await axios.get(\\`\\${window.env.apiUrl}user\\`);\n\n  if (data.code !== 0) {\n    this.userList = [];\n  } else {\n    this.userList = data.data || [];\n  }\n  this.loading = false;\n},`, `33792200606954095000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// 获得用户列表</span>\n<span class=\"token keyword\">async</span> <span class=\"token function\">getUsers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>loading <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> axios<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>window<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span>apiUrl<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">user</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">.</span>code <span class=\"token operator\">!==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>userList <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>userList <span class=\"token operator\">=</span> data<span class=\"token punctuation\">.</span>data <span class=\"token operator\">||</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>loading <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<h2 id=\"小结\"><a href=\"#%E5%B0%8F%E7%BB%93\" aria-label=\"小结 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>小结</h2>\n<p>以上基于腾讯云 <a href=\"https://cloud.tencent.com/product/sf\">Serverless Framework</a> 来实现。到这里，有关 <code class=\"language-text\">Serverless Component</code> 全栈解决方案的全部内容就到此结束啦！</p>\n<hr>\n<div id='scf-deploy-iframe-or-md'></div>\n<hr>\n<blockquote>\n<p><strong>传送门：</strong></p>\n<ul>\n<li>GitHub: <a href=\"https://github.com/serverless/serverless/blob/master/README_CN.md\">github.com/serverless</a></li>\n<li>官网：<a href=\"https://serverless.com/\">serverless.com</a></li>\n</ul>\n</blockquote>\n<p>欢迎访问：<a href=\"https://serverlesscloud.cn/\">Serverless 中文网</a>，您可以在 <a href=\"https://serverlesscloud.cn/best-practice\">最佳实践</a> 里体验更多关于 Serverless 应用的开发！</p>","tableOfContents":"<ul>\n<li><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#%E9%85%8D%E7%BD%AE-cdn\">配置 CDN</a></li>\n<li>\n<p><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#%E9%85%8D%E7%BD%AE-https\">配置 HTTPS</a></p>\n<ul>\n<li><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#%E5%87%86%E5%A4%87%E8%AF%81%E4%B9%A6\">准备证书</a></li>\n<li><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#%E5%BC%80%E5%A7%8B%E9%85%8D%E7%BD%AE\">开始配置</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#cdn-serverless-component\">CDN Serverless Component</a></p>\n<ul>\n<li><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#%E4%BF%AE%E6%94%B9-serverlessyml-%E9%85%8D%E7%BD%AE\">修改 serverless.yml 配置</a></li>\n</ul>\n</li>\n<li><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#%E6%9B%B4%E6%96%B0-frontend-%E6%8A%80%E6%9C%AF%E6%A0%88\">更新 Frontend 技术栈</a></li>\n<li><a href=\"/best-practice/2019-12-11-serverless-fullstack-vue-practice-pro/#%E5%B0%8F%E7%BB%93\">小结</a></li>\n</ul>"},"previousBlog":{"id":"d2a60cba-0dfd-5c94-9848-dc29a897e81e","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/20191230/1577673977066-16ef85f25ee1af09.jpg","authors":["yugasun"],"categories":["best-practice"],"date":"2019-12-12T00:00:00.000Z","title":"如何开发自己的第一个 Serverless Component","description":"我们分享了不少基于 Component 的最佳实践案例，本文教你如何自己开发一个 Component！","authorslink":["https://yugasun.com"],"translators":null,"translatorslink":null,"tags":["Wintersmith","Component"],"keywords":"Serverless Component,最佳实践案例,开发Component,实践案例","outdated":null},"wordCount":{"words":399,"sentences":63,"paragraphs":63},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2019-12-12-how-write-first-serverless-components.md","fields":{"slug":"/best-practice/2019-12-12-how-write-first-serverless-components/","keywords":["serverless","website","serverless","tencent","组件","Serverless","Component","cdn","npm"]}},"nextBlog":{"id":"1e54dd30-fe20-593b-952b-869b890aced3","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020114/1579000616928-HEAD.png","authors":["Anycodes"],"categories":["guides-and-tutorials"],"date":"2019-12-10T00:00:00.000Z","title":"Serverless 的资源评估与成本探索","description":"本文介绍了使用 Serverless 架构布局业务时，需要关注的资源和费用","authorslink":["https://www.zhihu.com/people/liuyu-43-97"],"translators":null,"translatorslink":null,"tags":["资源成本","Serverless"],"keywords":"Serverless 架构,Serverless 布局业务,Serverless 资源评估","outdated":null},"wordCount":{"words":341,"sentences":66,"paragraphs":66},"fileAbsolutePath":"/opt/build/repo/content/blog/2019-12-10-resource-cost.md","fields":{"slug":"/blog/2019-12-10-resource-cost/","keywords":["serverless","云函数","内存","serverlesscloud"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"3db31f60-9d84-53dc-b9b9-ae47809f7202","previousBlogId":"d2a60cba-0dfd-5c94-9848-dc29a897e81e","nextBlogId":"1e54dd30-fe20-593b-952b-869b890aced3"}}}