<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          從Element-ui源碼聊搭建UI庫 系列二

          共 35406字,需瀏覽 71分鐘

           ·

          2021-06-05 22:05

          這一篇是承接上一篇《從Element-ui源碼聊搭建UI庫 系列一》,

          上一篇主要分析了做組件庫和閱讀 Element 源碼的目的。大致介紹源碼中的目錄結(jié)構(gòu),細(xì)講了 packages 目錄和 package.json,最后解析 script 腳本命令中的前兩者bootstrapbuild:file 命令。這一篇 從 scripts 腳本命令解析繼續(xù)分析其余命令。

          五、 scripts腳本命令解析

          build:theme

          "build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk"

          主要是處理樣式相關(guān)的腳本。拆開來分析下:

          node build/bin/gen-cssfile

          執(zhí)行該文件通過組件列表生成對應(yīng)的 css 文件和 theme-chalk/index.scss 文件,并將所有組件的樣式都導(dǎo)入。以后每次新增一個組件不用手動導(dǎo)入,執(zhí)行命令自動導(dǎo)入。

          比如創(chuàng)建了新組件 aaa,執(zhí)行命令后生成 aaa.scss,并且 index.scss 多了 aaa

          來看下具體實(shí)現(xiàn):

          var fs = require('fs');
          var path = require('path');
          var Components = require('../../components.json');
          var themes = [
            'theme-chalk'
          ];
          Components = Object.keys(Components);
          var basepath = path.resolve(__dirname, '../../packages/');

          function fileExists(filePath{
            try {
              return fs.statSync(filePath).isFile();
            } catch (err) {
              return false;
            }
          }

          themes.forEach((theme) => {
            var isSCSS = theme !== 'theme-default';
            var indexContent = isSCSS ? '@import "./base.scss";\n' : '@import "./base.css";\n';
            Components.forEach(function(key{
              // 導(dǎo)入的組件不在packages文件夾下,需要過濾
              // 以下是option-group的代碼
          //     import ElOptionGroup from '../select/src/option-group';

          // /* istanbul ignore next */
          // ElOptionGroup.install = function(Vue) {
            //   Vue.component(ElOptionGroup.name, ElOptionGroup);
            // };
            
            // export default ElOptionGroup;
            if (['icon''option''option-group'].indexOf(key) > -1return;
            var fileName = key + (isSCSS ? '.scss' : '.css');

            // @import "./popconfirm.scss";
            indexContent += '@import "./' + fileName + '";\n';
            
            // 組裝組件css文件路徑 E:\element-master\element-master\packages\theme-chalk\src\popconfirm.scss
            var filePath = path.resolve(basepath, theme, 'src', fileName);
            
            // 文件不存在就創(chuàng)建遺漏的css文件
            if (!fileExists(filePath)) {
                fs.writeFileSync(filePath, '''utf8');
                console.log(theme, ' 創(chuàng)建遺漏的 ', fileName, ' 文件');
              }
            });
            // 往index.scss中寫入導(dǎo)入 如:@import "./base.scss";
            fs.writeFileSync(path.resolve(basepath, theme, 'src', isSCSS ? 'index.scss' : 'index.css'), indexContent);
          });

          gulp build --gulpfile packages/theme-chalk/gulpfile.js

          把所有的 scss 文件通過 gulp 編譯成 css。

          打包和壓縮的工作平時一般交給 webpack 來做,但是基于工作流用 gulp 更加快捷和方便。

          'use strict';

          const {
            series,
            src,
            dest
          } = require('gulp');
          // 編譯gulp工具
          const sass = require('gulp-sass');
          // 添加廠商前綴
          const autoprefixer = require('gulp-autoprefixer');
          // 壓縮css
          const cssmin = require('gulp-cssmin');

          // src下面的所有文件編譯到lib下
          function compile({
            return src('./src/*.scss')
              .pipe(sass.sync()) //把scss編譯成css
              .pipe(autoprefixer({ //基于目標(biāo)瀏覽器版本,添加廠商前綴
                browsers: ['ie > 9''last 2 versions'],
                cascadefalse
              }))
              .pipe(cssmin()) //壓縮css
              // dest: 流會將 vinyl File保存到指定目錄下
              .pipe(dest('./lib')); //輸出到lib下
          }
          // 讀取src下的fonts文件目錄輸出到lib下
          function copyfont({
            return src('./src/fonts/**')
              .pipe(cssmin())
              .pipe(dest('./lib/fonts'));
          }
          // series: 接受可變數(shù)量的字符串(taskName)和/或函數(shù)(fn),并返回組合任務(wù)或函數(shù)的一個函數(shù)
          exports.build = series(compile, copyfont);

          編譯

          執(zhí)行命令輸出 css 文件,放入 lib 目錄:

          lib目錄

          為什么需要編譯呢?

          因?yàn)?element 在使用時有兩種引入方式:

          • 全局引用:
          import Vue from 'vue';
          import ElementUI from 'element-ui';
          import 'element-ui/lib/theme-chalk/index.css';
          import App from './App.vue';

          Vue.use(ElementUI);

          new Vue({
            el'#app',
            renderh => h(App)
          });

          引入了 lib\theme-chalk\index.css 文件

          • 局部引入:
          import Vue from 'vue';
          import { Button, Select } from 'element-ui';
          import App from './App.vue';

          Vue.component(Button.name, Button);
          Vue.component(Select.name, Select);
          /* 或?qū)憺?br> * Vue.use(Button)
           * Vue.use(Select)
           */


          new Vue({
            el'#app',
            renderh => h(App)
          });

          不需要引入 css 文件,只需引入對應(yīng)的 scss 文件。這就是為什么需要編譯 scss 的原因。

          cp-cli packages/theme-chalk/lib lib/theme-chalk

          cp-cli 是一個跨平臺的 copy 工具 將gulp build --gulpfile .\packages\theme-chalk\gulpfile.js編譯生成的 css 目錄(packages/theme-chalk/lib)復(fù)制到 lib/theme-chalk

          theme-chalk

          方便全局引用,導(dǎo)入 css

          import 'element-ui/lib/theme-chalk/index.css';

          build:utils

          "build:utils": "cross-env BABEL_ENV=utils babel src --out-dir lib --ignore src/index.js"

          將工具函數(shù)通過 babel 轉(zhuǎn)譯后移動到 lib 下,方便項(xiàng)目中使用。

          utils

          src 目錄下的內(nèi)容忽略 index.js 通過 babel 轉(zhuǎn)譯,然后移動到 lib

          lib

          比如 mousewheel 文件

          沒轉(zhuǎn)譯的:

          mousewheel未編譯

          轉(zhuǎn)譯后的:

          mousewheel編譯

          build:umd

          "build:umd": "node build/bin/build-locale.js"

          執(zhí)行后生成 umd 模塊的語言包。

          src/locale/lang 下的語言包都編譯到 lib/umd/locale 下。

          var fs = require('fs');
          // 導(dǎo)出文件
          var save = require('file-save');
          // 解析為絕對路徑
          var resolve = require('path').resolve;
          // 獲取擴(kuò)展名,返回path最后一部分 path.basename('/foo/bar/quux.html', '.html'); // 返回:‘quux’
          var basename = require('path').basename;
          var localePath = resolve(__dirname, '../../src/locale/lang');
          // 讀取src/locale/lang下的列表
          var fileList = fs.readdirSync(localePath);
          // 通過babel轉(zhuǎn)譯
          var transform = function (filename, name, cb{
            // https://babel.docschina.org/docs/en/6.26.3/babel-core/
            require('babel-core').transformFile(resolve(localePath, filename), {
              plugins: [
                'add-module-exports',
                ['transform-es2015-modules-umd', {
                  loosetrue
                }]
              ],
              moduleId: name
            }, cb);
          };
          fileList
            // 過濾js文件
            .filter(function (file{
              return /\.js$/.test(file);
            })
            .forEach(function (file{
              var name = basename(file, '.js');
              // 異步轉(zhuǎn)譯文件中的全部內(nèi)容
              transform(file, name, function (err, result{
                if (err) {
                  console.error(err);
                } else {
                  var code = result.code;

                  code = code
                    .replace('define(\'''define(\'element/locale/')
                    .replace('global.''global.ELEMENT.lang = global.ELEMENT.lang || {}; \n    global.ELEMENT.lang.');
                  save(resolve(__dirname, '../../lib/umd/locale', file)).write(code);

                  console.log(file);
                }
              });
            });

          clean

          "clean": "rimraf lib && rimraf packages/*/lib && rimraf test/**/coverage"

          清除打包好后的文件

          deploy:build

          "deploy:build": "npm run build:file && cross-env NODE_ENV=production webpack --config build/webpack.demo.js && echo element.eleme.io>>examples/element-ui/CNAME"

          npm run build:file 前文分析過了,主要構(gòu)建官網(wǎng)文件。接下來分析新的構(gòu)建腳本。

          生產(chǎn)環(huán)境下構(gòu)建官網(wǎng)。

          cross-env NODE_ENV=production webpack --config build/webpack.demo.js

          生產(chǎn)環(huán)境下構(gòu)建官網(wǎng)。

          官網(wǎng)項(xiàng)目的 webpack 配置:

          // webpack第三方插件
          // https://github.com/webpack-contrib

          const path = require('path');
          const webpack = require('webpack');
          // 這個插件將CSS提取到單獨(dú)的文件中。它為每個包含CSS的JS文件創(chuàng)建一個CSS文件。它支持按需加載CSS和SourceMaps。
          const MiniCssExtractPlugin = require('mini-css-extract-plugin');
          const CopyWebpackPlugin = require('copy-webpack-plugin');
          const HtmlWebpackPlugin = require('html-webpack-plugin');
          const ProgressBarPlugin = require('progress-bar-webpack-plugin');
          const VueLoaderPlugin = require('vue-loader/lib/plugin');
          const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
          const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

          const config = require('./config');

          const isProd = process.env.NODE_ENV === 'production';
          // "dev:play": "npm run build:file && cross-env NODE_ENV=development PLAY_ENV=true webpack-dev-server --config build/webpack.demo.js",
          const isPlay = !!process.env.PLAY_ENV;

          const webpackConfig = {
            mode: process.env.NODE_ENV,
            entry: isProd ? {
              docs'./examples/entry.js'
            } : (isPlay ? './examples/play.js' : './examples/entry.js'),
            output: {
              path: path.resolve(process.cwd(), './examples/element-ui/'),
              publicPath: process.env.CI_ENV || '',
              filename'[name].[hash:7].js',
              chunkFilename: isProd ? '[name].[hash:7].js' : '[name].js'
            },
            resolve: {
              extensions: ['.js''.vue''.json'],
              alias: config.alias,
              modules: ['node_modules']
            },
            // 開發(fā)服務(wù)器
            // webpack-dev-server 可用于快速開發(fā)應(yīng)用程序
            devServer: {
              host'0.0.0.0',
              port8085,
              publicPath'/',
              hottrue
            },
            performance: {
              hintsfalse
            },
            stats: {
              childrenfalse
            },
            module: {
              rules: [{
                  enforce'pre',
                  test/\.(vue|jsx?)$/,
                  exclude/node_modules/,
                  loader'eslint-loader'
                },
                {
                  test/\.(jsx?|babel|es6)$/,
                  include: process.cwd(),
                  exclude: config.jsexclude,
                  loader'babel-loader'
                },
                {
                  test/\.vue$/,
                  loader'vue-loader',
                  options: {
                    compilerOptions: {
                      preserveWhitespacefalse
                    }
                  }
                },
                {
                  test/\.(scss|css)$/,
                  use: [
                    isProd ? MiniCssExtractPlugin.loader : 'style-loader',
                    'css-loader',
                    'sass-loader'
                  ]
                },
                // 使用md-loader加載模塊
                {
                  test/\.md$/,
                  use: [{
                      loader'vue-loader',
                      options: {
                        compilerOptions: {
                          preserveWhitespacefalse
                        }
                      }
                    },
                    {
                      loader: path.resolve(__dirname, './md-loader/index.js')
                    }
                  ]
                },
                {
                  test/\.(svg|otf|ttf|woff2?|eot|gif|png|jpe?g)(\?\S*)?$/,
                  loader'url-loader',
                  // todo: 這種寫法有待調(diào)整
                  query: {
                    limit10000,
                    name: path.posix.join('static''[name].[hash:7].[ext]')
                  }
                }
              ]
            },
            plugins: [
              new webpack.HotModuleReplacementPlugin(),
              new HtmlWebpackPlugin({
                template'./examples/index.tpl',
                filename'./index.html',
                favicon'./examples/favicon.ico'
              }),
              new CopyWebpackPlugin([{
                from'examples/versions.json'
              }]),
              new ProgressBarPlugin(),
              new VueLoaderPlugin(),
              new webpack.DefinePlugin({
                'process.env.FAAS_ENV'JSON.stringify(process.env.FAAS_ENV)
              }),
              new webpack.LoaderOptionsPlugin({
                vue: {
                  compilerOptions: {
                    preserveWhitespacefalse
                  }
                }
              })
            ],
            optimization: {
              minimizer: []
            },
            devtool'#eval-source-map'
          };
          // 生產(chǎn)環(huán)境更換插件\優(yōu)化\擴(kuò)展等
          if (isProd) {
            webpackConfig.externals = {
              vue'Vue',
              'vue-router''VueRouter',
              'highlight.js''hljs'
            };
            webpackConfig.plugins.push(
              new MiniCssExtractPlugin({
                filename'[name].[contenthash:7].css'
              })
            );
            webpackConfig.optimization.minimizer.push(
              new UglifyJsPlugin({
                cachetrue,
                paralleltrue,
                sourceMapfalse
              }),
              new OptimizeCSSAssetsPlugin({})
            );
            // https://webpack.js.org/configuration/optimization/#optimizationsplitchunks
            webpackConfig.optimization.splitChunks = {
              cacheGroups: {
                vendor: {
                  test/\/src\//,
                  name'element-ui',
                  chunks'all'
                }
              }
            };
            webpackConfig.devtool = false;
          }

          module.exports = webpackConfig;

          deploy:extension

          "deploy:extension": "cross-env NODE_ENV=production webpack --config build/webpack.extension.js"

          在生產(chǎn)環(huán)境下構(gòu)建主題插件,主題編輯器的 chorme 插件項(xiàng)目的 webpack 配置,項(xiàng)目在 extension 目錄下。執(zhí)行命令后會在 extension 目錄下生成 dist 目錄,其中包含了 chorme 插件,在瀏覽器加載已解壓的擴(kuò)展程序就可以使用主題生成插件。

          dev:extension

          "dev:extension": "rimraf examples/extension/dist && cross-env NODE_ENV=development webpack --watch --config build/webpack.extension.js"

          啟動主題插件的開發(fā)環(huán)境,可以進(jìn)行開發(fā)調(diào)試。

          dev

          "dev": "npm run bootstrap && npm run build:file && cross-env NODE_ENV=development webpack-dev-server --config build/webpack.demo.js & node build/bin/template.js"

          首先 npm run bootstrap 是用來安裝依賴的。npm run build:file 在前面也有提到,主要用來自動化生成一些文件。主要是 node build/bin/build-entry.js,用于生成 Element 的入口 js:先是讀取根目錄的 components.json,這個 json 文件維護(hù)著 Element 所有的組件路徑映射關(guān)系,鍵為組件名,值為組件源碼的入口文件;然后遍歷鍵值,將所有組件進(jìn)行 import,對外暴露 install 方法,把所有 import 的組件通過 Vue.component(name, component) 方式注冊為全局組件,并且把一些彈窗類的組件掛載到 Vue 的原型鏈上。

          在生成了入口文件的 src/index.js 之后就會運(yùn)行 webpack-dev-server

          啟動組件庫本地開發(fā)環(huán)境。在更改后可以熱更新官網(wǎng)。具體 webpack 配置見 webpack.demo.js。

          dev:play

          "dev:play": "npm run build:file && cross-env NODE_ENV=development PLAY_ENV=true webpack-dev-server --config build/webpack.demo.js"

          組件測試項(xiàng)目,在 examples/play/index.vue 中可以引入組件庫任意組件,也可以直接使用 dev 啟動的項(xiàng)目,在文檔中使用組件。

          用于查看某個組件的效果。適用于組件按需加載的顯示效果。在 webpack.demo.js 通過環(huán)境變量配置輸入。

          element-master\build\webpack.demo.js

          const isPlay = !!process.env.PLAY_ENV;
           
          ……省略webpack具體配置

           entry: isProd ? {
              docs'./examples/entry.js'
            } : (isPlay ? './examples/play.js' : './examples/entry.js'),

          element-master\examples\play.js

          import Vue from 'vue';
          import Element from 'main/index.js';
          import App from './play/index.vue';
          import 'packages/theme-chalk/src/index.scss';

          Vue.use(Element);

          new Vue({ // eslint-disable-line
            renderh => h(App)
          }).$mount('#app');

          element-master\examples\play\index.vue
          <template>
            <div style="margin: 20px;">
              <el-input v-model="input" placeholder="請輸入內(nèi)容"></el-input>
            </div>

          </template>

          <script>
            export default {
              data() {
                return {
                  input: 'Hello Element UI!'
                };
              }
            };
          </
          script>

          dist

          "dist": "npm run clean && npm run build:file && npm run lint && webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js && npm run build:utils && npm run build:umd && npm run build:theme"

          打包組件庫

          npm run clean && npm run build:file && npm run lint 都已經(jīng)解釋過了,分別是清除上一次打包產(chǎn)物、生成入口文件以及 i18n 文件和 eslint 檢測。

          webpack --config build/webpack.conf.js

          生成 umd 格式的 js 文件(index.js

          const path = require('path');
          const ProgressBarPlugin = require('progress-bar-webpack-plugin');
          const VueLoaderPlugin = require('vue-loader/lib/plugin');
          const TerserPlugin = require('terser-webpack-plugin');

          const config = require('./config');
          console.log(config)
          module.exports = {
            // 模式
            mode'production',
            // 入口
            entry: {
              app: ['./src/index.js']
            },
            // 輸出
            output: {
              path: path.resolve(process.cwd(), './lib'),
              publicPath'/dist/',
              // 輸出的文件名
              filename'index.js',
              // 初始的chunk文件名稱
              chunkFilename'[id].js',
              //  library 暴露為 AMD 模塊。 在 AMD 或 CommonJS 的 require 之后可訪問(libraryTarget:'umd')
              libraryTarget'umd',
              // 入口的默認(rèn)導(dǎo)出將分配給 library target:
              // if your entry has a default export of `MyDefaultModule`
              // var MyDefaultModule = _entry_return_.default;
              libraryExport'default',
              // 輸出一個庫,為你的入口做導(dǎo)出。
              library'ELEMENT',
              // 會把 AMD 模塊命名為 UMD 構(gòu)建
              umdNamedDefinetrue,
              // 為了使 UMD 構(gòu)建在瀏覽器和 Node.js 上均可用,應(yīng)將 output.globalObject 選項(xiàng)設(shè)置為 'this'。對于類似 web 的目標(biāo),默認(rèn)為 self。
              globalObject'typeof self !== \'undefined\' ? self : this'
            },
            // 解析
            resolve: {
              // 能夠使用戶在引入模塊時不帶擴(kuò)展.嘗試按順序解析這些后綴名。如果有多個文件有相同的名字,但后綴名不同,webpack 會解析列在數(shù)組首位的后綴的文件 并跳過其余的后綴。
              extensions: ['.js''.vue''.json'],
              // 創(chuàng)建 import 或 require 的別名,來確保模塊引入變得更簡單。
              alias: config.alias
            },
            // 外部擴(kuò)展
            externals: {
              vue: config.vue
            },
            // 優(yōu)化
            optimization: {
              // 允許你通過提供一個或多個定制過的 TerserPlugin 實(shí)例, 覆蓋默認(rèn)壓縮工具(minimizer)
              minimizer: [
                new TerserPlugin({
                  terserOptions: {
                    output: {
                      commentsfalse
                    }
                  }
                })
              ]
            },
            // 性能
            performance: {
              // 不展示警告或錯誤提示。
              // 官網(wǎng)推薦使用error,有助于防止把體積大的bundle部署到生產(chǎn)環(huán)境,從而影響網(wǎng)頁的性能
              // 很奇怪這里要把它關(guān)閉
              hintsfalse
            },
            // stats對象
            stats: {
              // 告知 stats 是否添加關(guān)于子模塊的信息。
              childrenfalse
            },
            // 模塊
            module: {
              // 使用babel-loader和vue-loader
              rules: [
                {
                  test/\.(jsx?|babel|es6)$/,
                  include: process.cwd(),
                  exclude: config.jsexclude,
                  loader'babel-loader'
                },
                {
                  test/\.vue$/,
                  loader'vue-loader',
                  options: {
                    compilerOptions: {
                      preserveWhitespacefalse
                    }
                  }
                }
              ]
            },
            // 插件
            plugins: [
              new ProgressBarPlugin(),
              new VueLoaderPlugin()
            ]
          };

          webpack --config build/webpack.common.js

          生成 commonjs 格式的 js 文件(element-ui.common.js),require 時默認(rèn)加載的是這個文件。

              libraryTarget: 'commonjs2'

          webpack.conf.js 不同在于輸出 outputlibraryExport。

          前者暴露的是 commonjs2,后者暴露的是 umd

          webpack --config build/webpack.component.js

          與前兩者的 index.js 入口不同,以 components.json 為入口,將每一個組件打包生成一個文件,用于按需加載。

          npm run build:utils && npm run build:umd && npm run build:theme 也已經(jīng)講過,分別是轉(zhuǎn)譯工具方法、轉(zhuǎn)譯語言包、生成樣式文件。

          lint

          "lint": "eslint src/**/* test/**/* packages/**/* build/**/* --quiet"

          eslint 校驗(yàn) srcbuild 目錄下的文件。

          pub

          "pub": "npm run bootstrap && sh build/git-release.sh && sh build/release.sh && node build/bin/gen-indices.js && sh build/deploy-faas.sh"

          npm run bootstrap 下載依賴。

          sh build/git-release.sh:主要是檢測 dev 分支是否沖突。

          #!/usr/bin/env sh
          # 切換到dev分支
          git checkout dev
          # 檢測本地是否有未提交文件
          if test -n "$(git status --porcelain)"then
          # 輸出日志
            echo 'Unclean working tree. Commit or stash changes first.' >&2;
            exit 128;
          fi
          # 檢測本地分支是否有誤
          if ! git fetch --quiet 2>/dev/null; then
            # 輸出日志
            echo 'There was a problem fetching your branch. Run `git fetch` to see more...' >&2;
            exit 128;
          fi
          # 檢測是否有最新提交
          if test "0" != "$(git rev-list --count --left-only @'{u}'...HEAD)"then
            # 輸出日志
            echo 'Remote history differ. Please pull changes.' >&2;
            exit 128;
          fi
          # 輸出日志
          echo 'No conflicts.' >&2;

          sh build/release.sh 腳本完成了以下工作:

          1. 合并 dev 分支到 master
          2. 修改樣式包和組件庫的版本號
          3. 發(fā)布樣式包和組件庫
          4. 提交 master 和 dev 分支到遠(yuǎn)程倉庫

          該腳本在發(fā)布組件庫時可以使用,特別是其中自動更改版本號的功能(每次 publish 時都忘改版本號)。這里提交代碼到遠(yuǎn)程倉庫的日志很簡單。

          #!/usr/bin/env sh
          set -e
          # 切換到master
          git checkout master
          # 合并dev分支
          git merge dev
          # npx: 使用本地已安裝的可執(zhí)行工具,而不需要配置 scripts
          VERSION=`npx select-version-cli`
          # 更新版本號
          read -p "Releasing $VERSION - are you sure? (y/n)" -n 1 -r
          echo    # (optional) move to a new line
          if [[ $REPLY =~ ^[Yy]$ ]]
          then
            # 輸出:壓縮版本
            echo "Releasing $VERSION ..."

            # build
            # 編譯打包
            VERSION=$VERSION npm run dist

            # ssr test
            node test/ssr/require.test.js            

            # 發(fā)布到npm
            # publish theme
            # 輸出:壓縮theme-chalk版本
            echo "Releasing theme-chalk $VERSION ..."
            cd packages/theme-chalk
            # 更改主題包的版本信息
            npm version $VERSION --message "[release] $VERSION"
            # 如果是beta版本則打個beta標(biāo)簽
            if [[ $VERSION =~ "beta" ]]
            then
              npm publish --tag beta
            else
              npm publish
            fi
            cd ../..

            # commit
            git add -A
            git commit -m "[build] $VERSION"
            # 更改組件庫的版本信息
            npm version $VERSION --message "[release] $VERSION"
            # publish
            # 發(fā)布到遠(yuǎn)程倉庫
            git push eleme master
            git push eleme refs/tags/v$VERSION
            git checkout dev
            git rebase master
            git push eleme dev
            # 發(fā)布組件庫
            if [[ $VERSION =~ "beta" ]]
            then
              npm publish --tag beta
            else
              npm publish
            fi
          fi

          node build/bin/gen-indices.js 生成目錄,支持搜索:

          'use strict';
          // 生成目錄
          const fs = require('fs');
          const path = require('path');
          // 是一個托管的全文、數(shù)字和分面搜索引擎,能夠從第一次擊鍵交付實(shí)時結(jié)果。
          const algoliasearch = require('algoliasearch');
          // 將Unicode str轉(zhuǎn)換為段字符串,確保在URL或文件名中使用它是安全的。
          // https://www.npmjs.com/package/transliteration?activeTab=readme
          // demo:
          // slugify('你好,世界');
          // // ni-hao-shi-jie
          const slugify = require('transliteration').slugify;
          // 密鑰
          const key = require('./algolia-key');

          const client = algoliasearch('4C63BTGP6S', key);
          const langs = {
            'zh-CN''element-zh',
            'en-US''element-en',
            'es''element-es',
            'fr-FR''element-fr'
          };
          // 四種語言
          ['zh-CN''en-US''es''fr-FR'].forEach(lang => {
            const indexName = langs[lang];
            const index = client.initIndex(indexName);
            index.clearIndex(err => {
              if (err) return;
              // 讀取/examples/docs/中的文件
              fs.readdir(path.resolve(__dirname, `../../examples/docs/${ lang }`), (err, files) => {
                if (err) return;
                let indices = [];
                files.forEach(file => {
                  console.log(file)
                  const component = file.replace('.md''');
                  const content = fs.readFileSync(path.resolve(__dirname, `../../examples/docs/${ lang }/${ file }`), 'utf8');
                  const matches = content
                    .replace(/:::[\s\S]*?:::/g'')
                    .replace(/```[\s\S]*?```/g'')
                    .match(/#{2,4}[^#]*/g)
                    .map(match => match.replace(/\n+/g'\n').split('\n').filter(part => !!part))
                    .map(match => {
                      const length = match.length;
                      if (length > 2) {
                        const desc = match.slice(1, length).join('');
                        return [match[0], desc];
                      }
                      return match;
                    });

                  indices = indices.concat(matches.map(match => {
                    const isComponent = match[0].indexOf('###') < 0;
                    const title = match[0].replace(/#{2,4}/'').trim();
                    const index = { component, title };
                    index.ranking = isComponent ? 2 : 1;
                    index.anchor = slugify(title);
                    index.content = (match[1] || title).replace(/<[^>]+>/g'');
                    return index;
                  }));
                });

                index.addObjects(indices, (err, res) => {
                  console.log(err, res);
                });
              });
            });
          });

          test

          "test": "npm run lint && npm run build:theme && cross-env CI_ENV=/dev/ BABEL_ENV=test karma start test/unit/karma.conf.js --single-run" "test:watch": "npm run build:theme && cross-env BABEL_ENV=test karma start test/unit/karma.conf.js"

          單元測試:UI 組件作為高度抽象的基礎(chǔ)公共組件,編寫單元測試是很有必要的。

          小結(jié)

          系列二結(jié)合系列一中 bootstrapbuild:file 腳本命令。我們一共學(xué)習(xí)了 15 中命令,分別是:

          • bootstrap 安裝依賴包
          • build:file 構(gòu)建官網(wǎng)所需的文件
          • build:theme 構(gòu)建主題樣式
          • build:utilsbabel 編譯工具函數(shù)庫
          • build:umd 編譯生成 umd 模塊的語言包
          • clean 清理打包后的文件
          • deploy:build 生產(chǎn)環(huán)境下構(gòu)建官網(wǎng)
          • deploy:extension 在生產(chǎn)環(huán)境下構(gòu)建主題插件
          • dev:extension 啟動主題插件的開發(fā)環(huán)境,可以進(jìn)行開發(fā)調(diào)試
          • dev 啟動本地開發(fā)環(huán)境,進(jìn)行能夠調(diào)試開發(fā)
          • dev:play 用于查看某個組件的效果
          • dist 打包組件庫
          • lint 校驗(yàn)文件
          • pub 檢測分支是否沖突
          • test 測試項(xiàng)目

          我們不僅知道了每條命令目的,還逐行解析了命令所對應(yīng)的構(gòu)建腳本,這對于我們對項(xiàng)目工程化、模塊化很有幫助。所以我們還要繼續(xù)對源碼進(jìn)行學(xué)習(xí)和推敲。

          最后,希望大家一定要點(diǎn)贊三連。

          可以閱讀我的其他文章,見blog地址

          一個學(xué)習(xí)編程技術(shù)的公眾號。每天推送高質(zhì)量的優(yōu)秀博文、開源項(xiàng)目、實(shí)用工具、面試技巧、編程學(xué)習(xí)資源等等。目標(biāo)是做到個人技術(shù)與公眾號一起成長。歡迎大家關(guān)注,一起進(jìn)步,走向全棧大佬的修煉之路


          瀏覽 121
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  北条麻妃 视频 | 美女在线抠逼 | 学生妹做爱示频 | 韩国一区二区三区 | 日韩免费中文字幕A片 |