<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[PrendsMoi]]></title><description><![CDATA[爱折腾的切图仔！]]></description><link>https://liuhgxu.com/</link><image><url>https://liuhgxu.com/favicon.png</url><title>PrendsMoi</title><link>https://liuhgxu.com/</link></image><generator>Ghost 3.9</generator><lastBuildDate>Tue, 14 Apr 2026 13:55:19 GMT</lastBuildDate><atom:link href="https://liuhgxu.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[GitLab-CI/CD 搭建]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="docker">docker搭建</h2>
<pre><code class="language-bash"># 更新apt包索引
sudo apt-get update

# 卸载旧版的docker
sudo apt-get remove docker docker-engine docker.io containerd runc

# 一键安装docker
curl -sSL https://get.daocloud.io/docker | sh
</code></pre>
<h2 id="gitlab">gitlab搭建</h2>
<ol>
<li>安装gitlab</li>
</ol>
<pre><code class="language-bash"># docker安装gitlab镜像
docker pull gitlab/gitlab-ce:latest

# 运行gitlab的docker
docker run \
    --publish 8443:443 --publish 8080:80 --publish 2222:22 \
    --name gitlab \
    --volume /home/gitlab/config:</code></pre>]]></description><link>https://liuhgxu.com/gitlab-ci-cd/</link><guid isPermaLink="false">61235da49ff215177d449aba</guid><category><![CDATA[GitLab]]></category><dc:creator><![CDATA[PrendsMoi]]></dc:creator><pubDate>Mon, 23 Aug 2021 08:36:18 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="docker">docker搭建</h2>
<pre><code class="language-bash"># 更新apt包索引
sudo apt-get update

# 卸载旧版的docker
sudo apt-get remove docker docker-engine docker.io containerd runc

# 一键安装docker
curl -sSL https://get.daocloud.io/docker | sh
</code></pre>
<h2 id="gitlab">gitlab搭建</h2>
<ol>
<li>安装gitlab</li>
</ol>
<pre><code class="language-bash"># docker安装gitlab镜像
docker pull gitlab/gitlab-ce:latest

# 运行gitlab的docker
docker run \
    --publish 8443:443 --publish 8080:80 --publish 2222:22 \
    --name gitlab \
    --volume /home/gitlab/config:/etc/gitlab \
    --volume /home/gitlab/logs:/var/log/gitlab \
    --volume /home/gitlab/data:/var/opt/gitlab \
    gitlab/gitlab-ce
  
 # 暂时关闭服务器防火墙
 systemctl stop firewalld
 
 # 浏览器输入 http://ip:port 访问gitlab
</code></pre>
<ol start="2">
<li>优化gitlab的内存占用</li>
</ol>
<pre><code class="language-bash"># 进入到gitlab的bash
docker exec -it ${gitlab的docker id} /bin/bash 

# 编辑gitlab的配置文件 
vi /etc/gitlab/gitlab.rb

###### 修改配置内容start ######

puma['worker_processes'] = 4 # 去掉#注释 设置进程 不能低于2
puma['worker_timeout'] = 60 # 设置超时时间

###### 修改配置内容end ######

# 重启gitlab
gitlab-ctl restart
</code></pre>
<ol start="3">
<li>配置gitlab clone克隆地址</li>
</ol>
<pre><code class="language-bash"># 进入到gitlab的bash
docker exec -it ${gitlab的docker id} /bin/bash 

# 编辑配置文件
vi /etc/gitlab/gitlab.rb

###### 修改配置内容start ######
external_url 'http://ip:port'  # 访问地址 port为docker run时设置的8080

gitlab_rails['gitlab_shell_ssh_port'] = 2222 # ssh端口号 为docker run时设置的2222

gitlab_rails['gitlab_ssh_host'] = ip # ssh的访问ip
###### 修改配置内容end ######

# 修改配置文件
vi /opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml

###### 修改配置内容start ######
host ip地址  # 设置ip地址
port 访问端口 # 设置访问端口 同external_url设置的端口号
###### 修改配置内容end ######

# 重启gitlab
gitlab-ctl restart
</code></pre>
<h2 id="gitrunner">安装配置git-runner</h2>
<pre><code class="language-bash"># 安装git-runner
sudo docker run -d --name gitlab-runner --restart always \
  -v /home/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest
 
# 注册
docker run --rm -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register \
  --non-interactive \
  --executor &quot;docker&quot; \
  --docker-image alpine:latest \
  --url &quot;&quot; \
  --registration-token &quot;&quot; \
  --description &quot;first-register-runner&quot; \
  --tag-list &quot;vue3-app&quot; \
  --run-untagged=&quot;true&quot; \
  --locked=&quot;false&quot; \
  --access-level=&quot;not_protected&quot;
</code></pre>
<ul>
<li><font color="red" size="4">注册需要token和url，获取方式如下图</font></li>
</ul>
<p><a href="https://img.liuhgxu.com/img/image-20210819101503795.png"><img src="https://img.liuhgxu.com/img/image-20210819101503795.png" alt="image-20210819101503795"></a></p>
<ul>
<li>
<p>CI/CD配置yaml脚本需要的变量</p>
<p><a href="https://img.liuhgxu.com/img/image-20210823163059650.png"><img src="https://img.liuhgxu.com/img/image-20210823163059650.png" alt="image-20210823163059650"></a></p>
</li>
</ul>
<h2 id="gitlabciyml">编写.gitlab-ci.yml 🏁</h2>
<pre><code class="language-yaml">stages:
  - init # 初始化
  - lint # 校验
  - build # 打包
  - deploy # 部署

# 在流水线中使用package.json缓存node_modules,只要package.json内容没变就一直使用缓存
cache:
  key:
    files:
      - package.json
  paths:
    - node_modules/

# npm i 安装
init:
  stage: init
  only: 
    refs: 
      - merge_requests
    variables:
      - $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == &quot;develop&quot;
  script:
    - npm cache clean --force
    - npm install -g cnpm --registry=https://registry.npm.taobao.org
    - cnpm install
  after_script:
    - chmod a+x ./dingding.sh # 给钉钉的脚本添加权限
    - ./dingding.sh  # 执行钉钉脚本    

# 代码校验
lint:
  stage: lint
  only: 
    refs: 
      - merge_requests
    variables:
      - $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == &quot;develop&quot;  
  script:
    - npm run lint:jsx
    - npm run lint:css
  allow_failure: true

# 开始构建
build:
  stage: build
  artifacts:
    # 文件名
    name: 'dist'
    # 过期时间
    expire_in: 60 mins
    # 需要打包目录
    paths:
      - dist/
  only: 
    refs: 
      - merge_requests
    variables:
      - $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == &quot;develop&quot; # 表示只有往 develop分支提MR才会触发部署
  script:
    - npm run build:test    
  after_script:
    - chmod a+x ./dingding.sh # 给钉钉的脚本添加权限
    - ./dingding.sh  # 执行钉钉脚本

deploy:
  stage: deploy
  only: 
    refs: 
      - merge_requests
    variables:
      - $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == &quot;develop&quot; # 表示只有往 develop分支提MR才会触发部署
  script:
    - 'which ssh-agent || ( apk update &amp;&amp; apk add openssh-client)' # 预先装 ssh-agent
    - eval $(ssh-agent -s) # 启动服务
    - mkdir -p  /etc/ssh/
    - chmod 700  /etc/ssh
    - echo &quot;$SSH_KNOWHOST&quot; &gt; /etc/ssh/known_hosts
    - echo &quot;$SSH_PRIVATE_KEY&quot; &gt; /etc/ssh/id_rsa
    - echo &quot;$SSH_CONFIG&quot; &gt; /etc/ssh/ssh_config.d/config.conf
    # 配置较低权限
    - chmod 600 /etc/ssh/id_rsa
    - chmod 600 //etc/ssh/ssh_config.d/config.conf
    - chmod 644 /etc/ssh/known_hosts
    # 注入密钥 
    - ssh-add /etc/ssh/id_rsa
    - ssh Aliyun &quot;rm -rf /var/www/project/test&quot;
    - scp -i /etc/ssh/id_rsa -r ./dist/ &quot;$SSH_USERNAME&quot;@&quot;$SSH_HOST&quot;:/var/www/project/test/ 
  after_script:
    - chmod a+x ./dingding.sh # 给钉钉的脚本添加权限
    - ./dingding.sh  # 执行钉钉脚本
  when: on_success
</code></pre>
<h2 id>钉钉配置</h2>
<ol>
<li>
<p>群助手设置</p>
<ul>
<li>
<p>创建群</p>
</li>
<li>
<p>添加智能群助手</p>
<p><a href="https://img.liuhgxu.com/img/image-20210823162617640.png"><img src="https://img.liuhgxu.com/img/image-20210823162617640.png" alt="image-20210823162617640"></a></p>
</li>
<li>
<p>添加自定义机器人</p>
<p><a href="https://img.liuhgxu.com/img/image-20210823162728847.png"><img src="https://img.liuhgxu.com/img/image-20210823162728847.png" alt="image-20210823162728847"></a></p>
<p><a href="https://img.liuhgxu.com/img/image-20210823162904447.png"><img src="https://img.liuhgxu.com/img/image-20210823162904447.png" alt="image-20210823162904447"></a></p>
</li>
<li>
<p>配置机器人</p>
<p><a href="https://img.liuhgxu.com/img/image-20210823162933552.png"><img src="https://img.liuhgxu.com/img/image-20210823162933552.png" alt="image-20210823162933552"></a></p>
</li>
</ul>
</li>
<li>
<p>shell脚本</p>
</li>
</ol>
<pre><code class="language-bash">#!/bin/bash
##################
# 钉钉通知
# 自动化部署脚本中使用
##################

webhook=&quot;https://oapi.dingtalk.com/robot/send?access_token=${DINGDING_TOKEN}&quot; # 你自己创建的钉钉机器人的地址

# 推送模板发送（模板拼接）
function sendDingTalkNotifications() {
      local text=&quot;#### git名称：${CI_PROJECT_NAME} \n ##### 构建分支：${CI_COMMIT_REF_NAME} \n ##### 构建状态：${DEPLOY_STATUS}\n #### 提交者：${GITLAB_USER_NAME}-${GITLAB_USER_EMAIL} \n\n\n ##### 更新内容：${CI_COMMIT_MESSAGE} \n ##### [流水线 Pipeline #${CI_PIPELINE_ID}](${CI_PROJECT_URL}/pipelines/${CI_PIPELINE_ID}) \n
      &quot;
      curl POST &quot;$webhook&quot; -H 'Content-Type: application/json' -d &quot;{\&quot;msgtype\&quot;: \&quot;markdown\&quot;,\&quot;markdown\&quot;: {\&quot;title\&quot;:\&quot;${CI_PROJECT_NAME}\&quot;,\&quot;text\&quot;: \&quot;$text\&quot;}}&quot;
}

if [ &quot;$?&quot; -eq &quot;0&quot; ];then  # &quot;$?&quot; -eq &quot;0&quot; 表示上一句脚本执行成功，1的话表示失败
      case ${CI_JOB_STAGE} in
            &quot;init&quot;)
                  DEPLOY_STATUS='初始化安装成功!'
                  sendDingTalkNotifications
            ;;
            &quot;build&quot;) 
                  DEPLOY_STATUS='构建成功!'
                  sendDingTalkNotifications
            ;;
            &quot;deploy&quot;) DEPLOY_STATUS='部署成功!'
                  sendDingTalkNotifications
            ;;
      esac
else
      case ${CI_JOB_STAGE} in
            &quot;init&quot;|&quot;build&quot;) 
                  DEPLOY_STATUS='构建失败!'
                  sendDingTalkNotifications
            ;;
            &quot;deploy&quot;)
                  DEPLOY_STATUS='部署失败!'
                  sendDingTalkNotifications
            ;;
      esac

fi
</code></pre>
<h2 id>⚠️注意点</h2>
<ul>
<li>git-runner执行时候权限问题
<ul>
<li>进入gitlab-runner的docker，修改/etc/passwd文件中的gitlab-runner的权限与root同等级0</li>
</ul>
</li>
</ul>
<h3 id>参考文章</h3>
<p><a href="https://www.runoob.com/docker/docker-tutorial.html">Docker 教程 | 菜鸟教程 (runoob.com)</a></p>
<p><a href="https://segmentfault.com/a/1190000014305359">使用docker搭建gitlab环境 - SegmentFault 思否</a></p>
<p><a href="https://juejin.cn/post/6967972435064782879">GitLab+Docker快速搭建CI/CD自动化部署 (juejin.cn)</a></p>
<p><a href="https://juejin.cn/post/6995926592887193631">利用 Gitlab CI/CD + Jenkins 实现自动构建，自动部署 (juejin.cn)</a></p>
<p><a href="https://ssoor.github.io/2020/03/25/gitlab-ci-config-file/">Gitlab-CI 配置文件 .gitlab-ci.yml 详细说明，基于官方文档翻译 | 渡渡岛 (ssoor.github.io)</a></p>
<p><a href="https://www.runoob.com/w3cnote/set-ssh-login-key.html">设置 SSH 通过密钥登录 | 菜鸟教程 (runoob.com)</a></p>
<p><a href="https://soulteary.com/2021/07/14/gitlab-14-lightweight-operation-solution.html">GitLab 14 轻量化运行方案 - 苏洋博客 (soulteary.com)</a></p>
<p><a href="https://xuezenghui.com/posts/gitlab-ci-cd/">前端工程化之 CI/CD | Zander Hsueh (xuezenghui.com)</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[webpack多页面配置]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>之前都是使用脚手架直接生成的webpack配置，然后根据需求适当调整便使用了。最近空闲下来，然后就想从零开始写一个webpack配置，在此记录一下配置过程以及遇到的一些问题吧。</p>
<ol>
<li>node环境、npm或者yarn包管理器</li>
<li>创建一个新文件夹，然后使用npm或者yarn初始化</li>
<li>添加webpack依赖，创建一个webpack.config.js文件。顺便创建文件目录等</li>
<li>根据需要安装插件，目前我所用的到插件有</li>
</ol>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;interview&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;面试题记录&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;</code></pre>]]></description><link>https://liuhgxu.com/webpackduo-ye-mian-pei-zhi/</link><guid isPermaLink="false">60b306719d028b0219c07785</guid><category><![CDATA[webpack]]></category><dc:creator><![CDATA[PrendsMoi]]></dc:creator><pubDate>Sun, 30 May 2021 03:35:14 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>之前都是使用脚手架直接生成的webpack配置，然后根据需求适当调整便使用了。最近空闲下来，然后就想从零开始写一个webpack配置，在此记录一下配置过程以及遇到的一些问题吧。</p>
<ol>
<li>node环境、npm或者yarn包管理器</li>
<li>创建一个新文件夹，然后使用npm或者yarn初始化</li>
<li>添加webpack依赖，创建一个webpack.config.js文件。顺便创建文件目录等</li>
<li>根据需要安装插件，目前我所用的到插件有</li>
</ol>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;interview&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;面试题记录&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;webpack serve --mode development&quot;,
    &quot;build&quot;: &quot;webpack --mode production&quot;,
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;
  },
  &quot;author&quot;: &quot;&quot;,
  &quot;license&quot;: &quot;ISC&quot;,
  &quot;dependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.14.3&quot;,
    &quot;@babel/plugin-transform-runtime&quot;: &quot;^7.14.3&quot;,
    &quot;@babel/preset-env&quot;: &quot;^7.14.4&quot;,
    &quot;autoprefixer&quot;: &quot;^10.2.6&quot;,
    &quot;babel-loader&quot;: &quot;^8.2.2&quot;,
    &quot;babel-polyfill&quot;: &quot;^6.26.0&quot;,
    &quot;css-loader&quot;: &quot;^5.2.6&quot;,
    &quot;file-loader&quot;: &quot;^6.2.0&quot;,
    &quot;glob&quot;: &quot;^7.1.7&quot;,
    &quot;html-loader&quot;: &quot;^2.1.2&quot;,
    &quot;node-sass&quot;: &quot;^6.0.0&quot;,
    &quot;postcss&quot;: &quot;^8.3.0&quot;,
    &quot;postcss-loader&quot;: &quot;^5.3.0&quot;,
    &quot;postcss-px2rem&quot;: &quot;^0.3.0&quot;,
    &quot;sass&quot;: &quot;^1.34.0&quot;,
    &quot;sass-loader&quot;: &quot;^11.1.1&quot;,
    &quot;style-loader&quot;: &quot;^2.0.0&quot;,
    &quot;url-loader&quot;: &quot;^4.1.1&quot;,
    &quot;webpack-dev-server&quot;: &quot;^3.11.2&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;clean-webpack-plugin&quot;: &quot;^4.0.0-alpha.0&quot;,
    &quot;copy-webpack-plugin&quot;: &quot;^9.0.0&quot;,
    &quot;extract-text-webpack-plugin&quot;: &quot;^3.0.2&quot;,
    &quot;html-webpack-plugin&quot;: &quot;^5.3.1&quot;,
    &quot;mini-css-extract-plugin&quot;: &quot;^1.6.0&quot;,
    &quot;optimize-css-assets-webpack-plugin&quot;: &quot;^6.0.0&quot;,
    &quot;uglifyjs-webpack-plugin&quot;: &quot;^2.2.0&quot;,
    &quot;webpack&quot;: &quot;^5.38.1&quot;,
    &quot;webpack-cli&quot;: &quot;^4.7.0&quot;
  }
}

</code></pre>
<ol>
<li>其中一些loader，例如css-loader、style-loader等都是针对于css处理的，因为extract-text-webpack-plugin在webpack4中使用存在一些问题，而且官方建议使用mini-css-extract-plugin插件，所以我这里就使用官方推荐了。</li>
<li>@babel/core、@babel/preset-env等是针对编译js所引入的包处理</li>
<li>webpack-dev-server开发使用的本地服务，可以配置端口号、热更新等服务</li>
</ol>
<hr>
<p>遇到的问题：</p>
<ul>
<li><s>px转rem插件无法处理sass</s>改用webpack-px-to-rem</li>
<li>html无法进行热更新（将热更新关闭，使用页面自动刷新，比较耗费性能）</li>
</ul>
<hr>
<p>webpack.config.js文件内容</p>
<pre><code class="language-javascript">/*
 * @Author: PrendsMoi
 * @GitHub: https://github.com/PrendsMoi
 * @Blog: https://liuhgxu.com
 * @Description: webpack配置
 * @FilePath: /interview/webpack.config.js
 * @Date: 2021-05-30 11:27:51
 * @LastEditors: PrendsMoi
 * @LastEditTime: 2021-06-13 12:03:35
 */
const webpack = require('webpack')
const path = require('path')
const glob = require('glob')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

// 获取多页面
const getPages = (argv) =&gt; {
  const isDev = argv.mode === 'development'
  const views = glob.sync('src/views/**/*.html')
  const viewJs = glob.sync('src/views/**/*.js')
  const config = {
    hash: true,
    inject: true,
    minify: {
      removeComments: !isDev,
      collapseWhitespace: !isDev
    }
  }
  const entries = {}
  const htmls = []
  views.forEach(item =&gt; {
    const fileInfo = path.parse(item)
    console.log(viewJs.includes(`${fileInfo.dir}/${fileInfo.name}.js`))
    if (viewJs.includes(`${fileInfo.dir}/${fileInfo.name}.js`)) {
      entries[fileInfo.dir.split('/').slice(-1)[0]] = `./${item}`.replace('.html', '.js')
    }
    htmls.push(new HtmlWebpackPlugin({
      ...config,
      filename:  `${fileInfo.name}.html`,
      template: `./${fileInfo.dir}/${fileInfo.name}.html`,
      chunks: [ 'vendor', 'commons', fileInfo.name]
    }))
  })
  const entry = Object.assign({'babel-polyfill': ['babel-polyfill'],commons: './src/app.js'}, entries)
  return {
    entries: entry,
    htmls
  }
}
module.exports = (env, argv) =&gt; ({
  entry:  getPages(argv).entries,
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: (argv.mode === 'development') ? './js/[name].js' : './js/[name].[contenthash].js',
    chunkFilename: (argv.mode === 'development') ? './js/[name].js' : './js/[name].[contenthash].js',
    publicPath: (argv.mode === 'development') ? '' : './'
  },
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          (argv.mode === 'development') ? 'style-loader' : MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: { importLoaders: 2 }
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'expanded'
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins: () =&gt; [
                require('autoprefixer')({
                  browsers: ['last 10 versions', 'ie &gt;= 9'],
                  flexbox:true,
                  remove: false
                }),
                // require('postcss-px2rem')({remUnit: 75})
              ]
            }
          }
        ]
      },
      {
        test: /\.(html)$/,
        use: {
          loader: 'html-loader',
          options: {
            sources: false
          }
        }
      },
      {
        test: /\.js$/,
        include: [
          path.resolve(__dirname, 'src')
        ],
        use: 'babel-loader'
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'file-loader'
          }
        ]
      },
      {
        test: /\.(woff2|woff|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'static/fonts/[name].[hash:7].[ext]'
        }
      }
    ]
  },
  resolve: {//解析模块可选项
  },
  plugins: [
    ...getPages(argv).htmls,
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({filename:(argv.mode === 'development') ? &quot;css/[name].css&quot; : 'css/[name].[hash].css', chunkFilename: '[id].css'}),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, './src/assets'),
          to: 'assets',
          noErrorOnMissing: true
        }
      ],
      options: {}
    }),
    new webpack.LoaderOptionsPlugin({
      options: {
        postcss: [
          require('postcss-px2rem')({remUnit: 37.5})
        ]
      }
    })
  ],
  devtool: (argv.mode === 'development') ? &quot;eval&quot; : &quot;nosources-source-map&quot;,
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          chunks: 'async',
          name: 'commons',
          minChunks: 2,
          maxInitialRequests: 5,
          // minSize: 0
        },
        vendor: {
          test:/node_modules/,
          chunks:'all',
          name:'vendor',
          priority:10
        }
      }
    },
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: (argv.mode === 'development') ? true : false
      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,  //是否启用gzip
    host: 'localhost',
    port: 9000,
    hot: true, // 热更新
    open: true,
    overlay: true,
    inline: true,
    watchContentBase: true
  }
})
</code></pre>
<p>.babelrc文件</p>
<pre><code class="language-javascript">{
	&quot;presets&quot;: [&quot;@babel/preset-env&quot;],
	&quot;plugins&quot;: [&quot;@babel/plugin-transform-runtime&quot;]
}
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[秒杀倒计时问题记录及处理方案]]></title><description><![CDATA[<!--kg-card-begin: markdown--><ul>
<li>后台挂起倒计时停止问题 自定义一个setTimeout来记录时间的走动，当时间跨度不正确时，调整倒计时时间</li>
</ul>
<pre><code class="language-js">// 执行次数
let count = 0
// 本地时间
const localStart = new Date().getTime()
// 计时间隔
const interval = 1000
// 上一次时间
let lastTime = 0
// 计时器
let timeScreen = ''
function isLockScreen() {
  count++
  const nowTime = new Date().getTime()
  // 偏差
  const offset = nowTime - (localStart + count * interval)
  // 判断是否锁屏阻塞
  if(lastTime !== 0 ) {
    if((nowTime - lastTime)</code></pre>]]></description><link>https://liuhgxu.com/miao-sha-dao-ji-shi-wen-ti-ji-lu-ji-chu-li-fang-an-2/</link><guid isPermaLink="false">5f968b371b1f831c75591196</guid><category><![CDATA[Vue]]></category><dc:creator><![CDATA[PrendsMoi]]></dc:creator><pubDate>Mon, 26 Oct 2020 08:41:32 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><ul>
<li>后台挂起倒计时停止问题 自定义一个setTimeout来记录时间的走动，当时间跨度不正确时，调整倒计时时间</li>
</ul>
<pre><code class="language-js">// 执行次数
let count = 0
// 本地时间
const localStart = new Date().getTime()
// 计时间隔
const interval = 1000
// 上一次时间
let lastTime = 0
// 计时器
let timeScreen = ''
function isLockScreen() {
  count++
  const nowTime = new Date().getTime()
  // 偏差
  const offset = nowTime - (localStart + count * interval)
  // 判断是否锁屏阻塞
  if(lastTime !== 0 ) {
    if((nowTime - lastTime) &gt; (offset + 1200) || nowTime &lt; lastTime) {
      lastTime = 0
      // 重新调用
      this.init()
      return false
    }
  }
  lastTime = nowTime - offset
  let nextTime = interval - offset
  if(nextTime &lt; 0){
    nextTime = 0
  }
  timeScreen = setTimeout(this.isLockScreen, nextTime)
}
</code></pre>
<ul>
<li>App内切换webView页面刷新问题 其实这个并不算倒计时的问题，但是在这个项目中遇到也就记录一下吧！说到这个问题真的很揪心，因为当时遇到这个问题，发现这是因为调用App的原生事件去打开新的WebView页面，导致当前H5的href并没有变更。想到的第一个处理方案是希望App端能否提供一个事件监听供我回调，但是App之前没有这个开发需求，项目又急着上线，所以只能放弃。之后想到新的WebView是否会阻塞旧的webView的js，尝试过后发现并不会！然后开始去Google搜索，发现一个visibilitychange的监听事件和document.hidden的属性，尝试使用后，方案可行。</li>
</ul>
<pre><code class="language-js">document.addEventListener('visibilitychange', () =&gt; {
  if(!document.hidden){
    this.init()
	}
}, false)
</code></pre>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Page_Visibility_API">事件和属性的Api链接</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Deno 学习（一）]]></title><description><![CDATA[<!--kg-card-begin: markdown--><ol>
<li>
<p>安装deno，官网有详细的安装教程<a href="https://deno.land/">Deno</a>。安装完成后可以在命令窗口输入deno命令，如下图👇</p>
<img src="https://img.liuhgxu.com/img/image-20200701111614681.png" alt="image-20200701111614681" style="zoom:50%;">
</li>
<li>
<p>使用VsCode并安装Deno的相关插件Deno &amp; [Deprecated] Deno，如果不安装，在进行Deno模块引入时会出现红色的波浪号警告，因为在ts中是不需要文件的扩展名，且ts不支持从url中导入模块。</p>
</li>
<li>
<p>使用本地服务自动更新</p>
<pre><code class="language-bash">1. deno upgrade
2. deno install --allow-read --allow-run --allow-write -f --unstable https://deno.land/x/denon/denon.ts
3. denon -h
4. denon run --allow-env --allow-net demo.ts
</code></pre>
</li>
<li>
<p>demo.ts代码</p>
</li>
</ol>
<p><img src="https://img.liuhgxu.com/img/code.png" alt="code"></p>
<p>5.通过deno run --allow-net demo.ts</p>]]></description><link>https://liuhgxu.com/deno-xue-xi-yi/</link><guid isPermaLink="false">5f1a487a1b1f831c75591185</guid><category><![CDATA[deno]]></category><dc:creator><![CDATA[PrendsMoi]]></dc:creator><pubDate>Fri, 24 Jul 2020 02:35:04 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><ol>
<li>
<p>安装deno，官网有详细的安装教程<a href="https://deno.land/">Deno</a>。安装完成后可以在命令窗口输入deno命令，如下图👇</p>
<img src="https://img.liuhgxu.com/img/image-20200701111614681.png" alt="image-20200701111614681" style="zoom:50%;">
</li>
<li>
<p>使用VsCode并安装Deno的相关插件Deno &amp; [Deprecated] Deno，如果不安装，在进行Deno模块引入时会出现红色的波浪号警告，因为在ts中是不需要文件的扩展名，且ts不支持从url中导入模块。</p>
</li>
<li>
<p>使用本地服务自动更新</p>
<pre><code class="language-bash">1. deno upgrade
2. deno install --allow-read --allow-run --allow-write -f --unstable https://deno.land/x/denon/denon.ts
3. denon -h
4. denon run --allow-env --allow-net demo.ts
</code></pre>
</li>
<li>
<p>demo.ts代码</p>
</li>
</ol>
<p><img src="https://img.liuhgxu.com/img/code.png" alt="code"></p>
<p>5.通过deno run --allow-net demo.ts 运行，打开localhost:9000即可看见效果</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Ghost博客搭建小记]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h3 id>前言</h3>
<p>​	之前Wordpress版博客因为升级导致软件系统崩溃，因此博客也停了许久。前几日突然想把个人博客这块再搭建起来，虽然Wordpress的数据备份还在，却不想再使用。于是开始寻找新的博客系统，通过搜寻发现了Ghost。挺中意它的风格，就着手开始搭建。</p>
<h3 id>购买域名&amp;服务器</h3>
<p>​	服务器选择的阿里云的突发性能T5服务器，域名则是之前在Godaddy购买的。但是购买阿里的服务器部署绑定需要备案，只能将域名从Godaddy中转出。转出方法请看👉<a href="https://liuhgxu.com/ghostbo-ke-da-jian-xiao-ji/%5Bhttps://xmgseo.com/godaddy%E5%9F%9F%E5%90%8D%E8%BD%AC%E5%85%A5%E9%98%BF%E9%87%8C%E4%BA%91/%5D(https://xmgseo.com/godaddy%E5%9F%9F%E5%90%8D%E8%BD%AC%E5%85%A5%E9%98%BF%E9%87%8C%E4%BA%91/)">Godaddy域名转阿里云</a>。之后解析对应的DNS就好了。</p>
<h3 id="ghost">服务器系统选择&amp;Ghost搭建</h3>
<h5 id>系统&amp;服务器安全组</h5>
<ol>
<li>系统选择，Ghost官方推荐Ubuntu，也有对应的教程，所以这里我就使用Ubuntu(我不想说我开始使用CentOs折腾了好久，最后还是没成功(￣▽￣&quot;)...)</li>
<li>⚠️安全组配置（这个不能忘！！！），阿里云服务器默认80等端口不对外开放，所以创建完服务器一定要配置！因为遗忘这个，导致我后续搭建完Ghost总是无法访问。下面是80端口配置规则，如需要https对应配置443端口。若需要其他端口同理。见下方截图👇</li>
</ol>
<p><a href="https://img.liuhgxu.com/img/image-20200308113002988.png"><img src="https://img.liuhgxu.com/img/image-20200308113002988.png" alt="开放端口"></a></p>
<h4 id="ghost">Ghost搭建</h4>
<p>​	SSH连接服务器后，根据<a href="https://ghost.org/docs/install/ubuntu/">官方Ubuntu环境下搭建Ghost</a>步骤搭建即可。<font color="red">（注：在ghost</font></p>]]></description><link>https://liuhgxu.com/ghostbo-ke-da-jian-xiao-ji/</link><guid isPermaLink="false">5e64727232c5641f85edabc1</guid><category><![CDATA[小记]]></category><dc:creator><![CDATA[PrendsMoi]]></dc:creator><pubDate>Sun, 08 Mar 2020 04:33:09 GMT</pubDate><media:content url="https://liuhgxu.com/content/images/2020/03/37804D66-E7E0-4A2C-A359-CA8A8E3895C4_4_5005_c.jpeg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h3 id>前言</h3>
<img src="https://liuhgxu.com/content/images/2020/03/37804D66-E7E0-4A2C-A359-CA8A8E3895C4_4_5005_c.jpeg" alt="Ghost博客搭建小记"><p>​	之前Wordpress版博客因为升级导致软件系统崩溃，因此博客也停了许久。前几日突然想把个人博客这块再搭建起来，虽然Wordpress的数据备份还在，却不想再使用。于是开始寻找新的博客系统，通过搜寻发现了Ghost。挺中意它的风格，就着手开始搭建。</p>
<h3 id>购买域名&amp;服务器</h3>
<p>​	服务器选择的阿里云的突发性能T5服务器，域名则是之前在Godaddy购买的。但是购买阿里的服务器部署绑定需要备案，只能将域名从Godaddy中转出。转出方法请看👉<a href="https://liuhgxu.com/ghostbo-ke-da-jian-xiao-ji/%5Bhttps://xmgseo.com/godaddy%E5%9F%9F%E5%90%8D%E8%BD%AC%E5%85%A5%E9%98%BF%E9%87%8C%E4%BA%91/%5D(https://xmgseo.com/godaddy%E5%9F%9F%E5%90%8D%E8%BD%AC%E5%85%A5%E9%98%BF%E9%87%8C%E4%BA%91/)">Godaddy域名转阿里云</a>。之后解析对应的DNS就好了。</p>
<h3 id="ghost">服务器系统选择&amp;Ghost搭建</h3>
<h5 id>系统&amp;服务器安全组</h5>
<ol>
<li>系统选择，Ghost官方推荐Ubuntu，也有对应的教程，所以这里我就使用Ubuntu(我不想说我开始使用CentOs折腾了好久，最后还是没成功(￣▽￣&quot;)...)</li>
<li>⚠️安全组配置（这个不能忘！！！），阿里云服务器默认80等端口不对外开放，所以创建完服务器一定要配置！因为遗忘这个，导致我后续搭建完Ghost总是无法访问。下面是80端口配置规则，如需要https对应配置443端口。若需要其他端口同理。见下方截图👇</li>
</ol>
<p><a href="https://img.liuhgxu.com/img/image-20200308113002988.png"><img src="https://img.liuhgxu.com/img/image-20200308113002988.png" alt="Ghost博客搭建小记"></a></p>
<h4 id="ghost">Ghost搭建</h4>
<p>​	SSH连接服务器后，根据<a href="https://ghost.org/docs/install/ubuntu/">官方Ubuntu环境下搭建Ghost</a>步骤搭建即可。<font color="red">（注：在ghost install时，步骤Downloading Ghost step 5/5，可能会出现卡住的现象，多数是网络环境不好，重新安装多尝试几次。)</font>之后的根据文档输入（选择）对应的信息（需求），官方安装工具有集成 <a href="https://letsencrypt.org/">Let's Encrypt</a>的htpps配置，只需填写邮箱就好了（用于接收SSL证书过期消息）。安装完成就可以通过域名访问啦。</p>
<h5 id="kaldorei"><a href="https://github.com/xiaoluoboding/ghost-theme-kaldorei">Kaldorei主题配置</a></h5>
<p>​	这个主题的一些配置，都有文档教程，对应修改就好。</p>
<h5 id="typorapicgomac">Typora&amp;PicGo图床(Mac环境)</h5>
<p>​	这个按我个人需求添加的，如果没有特殊需求可以直接使用Ghost后台的Markdown。</p>
<p>​	1. Typora配置（偏好设置-&gt;图像-&gt;上传服务设定选择PicGo.app），下载PicGo.app</p>
<p>​	<a href="https://img.liuhgxu.com/img/image-20200308115709549.png"> <img src="https://img.liuhgxu.com/img/image-20200308115709549.png" alt="Ghost博客搭建小记"></a></p>
<p>​	2. PicGo.app配置</p>
<p>​		PicGo.app支持阿里云等多个图床服务设置，相关配置教程看这👉<a href="https://liuhgxu.com/ghostbo-ke-da-jian-xiao-ji/%5Bhttps://picgo.github.io/PicGo-Doc/zh/guide/config.html#%E5%9B%BE%E5%BA%8A%E5%8C%BA%5D(https://picgo.github.io/PicGo-Doc/zh/guide/config.html#%E5%9B%BE%E5%BA%8A%E5%8C%BA)">PicGo图床配置</a>。PicGo配置完后可以在Typora中点验证图片上传选项按钮进行验证。验证成功记得配置插入图片时上传图片，见上方Typora配置图。</p>
<p>至此，这篇小记就结束了，如果有什么需要我帮助的，请在评论区留言。感谢阅读。完结撒花🎉</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>