1. 程式人生 > >等離子切割套料軟體破解版下載程式碼

等離子切割套料軟體破解版下載程式碼

等離子切割套料軟體破解版下載程式碼【電同徽l7l54833762】H5頁面由於其具有釋出靈活、跨平臺、易於傳播等突出特點,所以H5頁面是引流拉新、宣傳推廣的重要渠道和方式,備受各公司的青睞。 小編的日常工作就是做各種面向使用者的H5促銷活動的開發,在整個開發週期中,接合我司的一些情況,我總結了H5活動頁面的以下特點:

面向使用者,流量大; 各端展示方案不同,需要相容各端(比如活動規則、展示模組,ios和android不一樣); 需求變更頻繁; 合作方較多(需要跟各個業務線合作聯調); 排期緊張;

所以開發測試期間,部署效率就顯得特別重要了。 由於我司的CDN釋出平臺,需要手動建立模板、貼上程式碼,部署效率比較低下;並且活動頁面程式碼分散,無法統一管理和實現工程化,所以決定實現一套自動化部署系統,目前已經投入使用半年時間了,極大地提高了我們的工作效率。我稱這個自動化部署系統為【H5 活動管理平臺】。 二、H5 活動管理平臺自動化部署實現方案 介紹該平臺實現方案之前,先放張效果圖,好有一個直觀的認識。

該平臺實現主要依賴於本地開發工程、gitlab,三者之間通過通訊互動,實現的自動化部署。

最終達到的效果就是:當本地開發分支merge到測試分支devTest或者master分支時,該平臺會自動拉取最新程式碼,構建目標檔案,然後將目標檔案部署到對應的伺服器目錄,另外提供了上下線、版本回滾、定時上下線等常用功能。 整體架構流程圖:

下面對一些關鍵技術點進行詳細介紹

  1. 本地開發工程 我們的本地開發工程,是使用node + webpack + babel等相關技術搭建的多頁面開發工程,不同的活動位於不同的目錄。因為要做自動化構建部署處理,跟【H5活動管理平臺】互動,所以有以下要點需要注意(可根據自己專案情況,自由調整方案)。

本地開發工程作為自動化構建部署的源頭,需要提供構建命令列用於構建測試檔案和線上檔案,便於後面shell命令呼叫。如在package.json中加入如下命令:

"scripts": { "local": "cross-env NODE_ENV=local node build.js", // 本地開發命令 "build": "cross-env NODE_ENV=product node build.js", // 構建上線檔案 "test": "cross-env NODE_ENV=test node build.js" // 構建測試檔案 } 複製程式碼 提供構建配置檔案dev-config.js,用於過濾webpack構建時的入口目錄,只構建編譯當前正在開發的活動頁面,提高構建速度。

//dev-config.js module.exports = { devPages: ['test'] // 當前自己正在開發頁面目錄,不寫時會編譯所有活動頁面 } 複製程式碼 提供活動頁面目錄資訊配置config.json,該配置資訊用於【H5活動管理平臺】的展示,也就是效果圖中的資訊源。

// config.json { "pages": [ { "folder": "lion", "desc": "前端名獅", "author": "訣九", "user": "juejiu" }, { "folder": "test", "desc": "活動測試頁面", "author": "訣九", "user": "juejiu" } ] }

複製程式碼 構建生成的 JS 和 HTML 檔案,存放在 dist 目錄下的對應活動目錄中。構建生成的目錄結構如下:

|--dist |-- lion |-- lion_app.js |-- index.html |--test |-- test_app.js |-- index.html

複製程式碼 提測時,將開發分支merge到devTest分支,上線時,將開發分支merge到master分支。

  1. gitlab伺服器 Gitlab作為企業程式碼版本管理工具,提供了Webhook的功能配置,Webhook顧名思義,其實就是一鉤子。當我們在Gitlab上做出某些特定操作時,可以觸發鉤子,去進行一些我們事先設定好的指令碼,以達到某些特定功能(例如--前端專案自動釋出)。 實際上可以把它理解為回撥,或者委託,或者事件通知,歸根揭底它就是一個訊息通知機制。當gitlab觸發某個事件時,它會向你的所配置的http服務傳送Post請求。 注意:

URL處填寫的是【H5活動管理平臺】部署的伺服器IP; IP後面跟的merge是該平臺提供的一個介面,用於觸發鉤子後,gitlab伺服器向這個介面傳送Post請求; Secret Token處填寫的是一個token,主要用於merge介面請求做安全校驗,可以隨便設定。

具體配置如下圖:

我們專案是設定的merge鉤子,下面只貼一下Merge request events請求傳遞的資料資訊: Request header: X-Gitlab-Event: Merge Request Hook 複製程式碼Request body: { "object_kind": "merge_request", "user": { "name": "Administrator", "username": "root", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" }, "object_attributes": { "id": 99, "target_branch": "master", "source_branch": "ms-viewport", "source_project_id": 14, "author_id": 51, "assignee_id": 6, "title": "MS-Viewport", "created_at": "2013-12-03T17:23:34Z", "updated_at": "2013-12-03T17:23:34Z", "st_commits": null, "st_diffs": null, "milestone_id": null, "state": "opened", "merge_status": "unchecked", "target_project_id": 14, "iid": 1, "description": "", "source":{ "name":"Awesome Project", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/awesome_space/awesome_project", "avatar_url":null, "git_ssh_url":"[email protected]:awesome_space/awesome_project.git", "git_http_url":"http://example.com/awesome_space/awesome_project.git", "namespace":"Awesome Space", "visibility_level":20, "path_with_namespace":"awesome_space/awesome_project", "default_branch":"master", "homepage":"http://example.com/awesome_space/awesome_project", "url":"http://example.com/awesome_space/awesome_project.git", "ssh_url":"[email protected]:awesome_space/awesome_project.git", "http_url":"http://example.com/awesome_space/awesome_project.git" }, "target": { "name":"Awesome Project", "description":"Aut reprehenderit ut est.", "web_url":"http://example.com/awesome_space/awesome_project", "avatar_url":null, "git_ssh_url":"[email protected]:awesome_space/awesome_project.git", "git_http_url":"http://example.com/awesome_space/awesome_project.git", "namespace":"Awesome Space", "visibility_level":20, "path_with_namespace":"awesome_space/awesome_project", "default_branch":"master", "homepage":"http://example.com/awesome_space/awesome_project", "url":"http://example.com/awesome_space/awesome_project.git", "ssh_url":"[email protected]:awesome_space/awesome_project.git", "http_url":"http://example.com/awesome_space/awesome_project.git" }, "last_commit": { "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "message": "fixed readme", "timestamp": "2012-01-03T23:36:29+02:00", "url": "http://example.com/awesome_space/awesome_project/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", "author": { "name": "GitLab dev user", "email": "gitlabdev@dv6700.(none)" } }, "work_in_progress": false, "url": "http://example.com/diaspora/merge_requests/1", "action": "open", "assignee": { "name": "User1", "username": "user1", "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon" } } }

複製程式碼3. H5 活動管理平臺 當開發者merge程式碼到GitLab伺服器,會觸發merge事件,GitLab會發送一個POST請求連帶資料(資料格式)給webhooks指定的URL,該平臺接收到URL請求後,就涉及如下關鍵技術點:

  1. 根據post請求頭資訊和和body資料,我們能得到如下資訊: merge的目標分支: req.body.object_attributes.target_branch; 安全校驗token:req.headers['x-gitlab-token']; gitlab工程倉庫地址:req.body.project.git_ssh_url 觸發的鉤子行為型別:req.body.object_attributes.action // gitlab觸發merge請求 router.post('/merge', function (req, res, next) { let git_ssh_url = req.body.project.git_ssh_url; let name = req.body.project.name; // 上線merge分支master if (req.headers['x-gitlab-token'] == 'mergeRequest' && req.body.object_attributes.target_branch == 'master' && req.body.object_attributes.action == 'merge') { if (config[name] && config[name].git_ssh_url == git_ssh_url) { mergeTaskQueue.addTask(function () { getCode.init(git_ssh_url, name, 'master').then(function (data) { console.log(data); mergeTaskQueue.run(); }).catch(function (error) { console.log(error); mergeTaskQueue.run(); }) }.bind(null, git_ssh_url, name)); } res.end('receive request'); // 測試merge分支dev } else if (req.headers['x-gitlab-token'] == 'mergeRequest' && req.body.object_attributes.target_branch == config[name].testEnv.targetBranch && req.body.object_attributes.action == 'merge') { if (config[name] && config[name].git_ssh_url == git_ssh_url) { mergeTaskQueue.addTask(function () { getCode.init(git_ssh_url, name, req.body.object_attributes.target_branch).then(function (data) { console.log(data); mergeTaskQueue.run(); }).catch(function (error) { console.log(error); mergeTaskQueue.run(); }) }.bind(null, git_ssh_url, name)); } res.end('receive request'); } else { return res.end('receive request'); } }) 複製程式碼2. 執行指令碼 指令碼這塊沒有使用shell指令碼,而是使用了node版本的shell.js庫,這個庫可以讓我們控制執行邏輯,更友好的處理錯誤資訊,幫助平臺有更友好的資訊展示。 拉取最新程式碼進行構建出目標檔案,大致邏輯如下圖:

function init(git_ssh_url, projectName, targetBranch) { deferred = Q.defer(); if (!git_ssh_url || !projectName) { return deferred.reject('專案地址或者專案名稱為空'); } repository = git_ssh_url; repositoryName = projectName; clonePath = path.join(__dirname, '../projects/' + projectName);

shell.exec('exit 0');
if (shell.test('-e', clonePath)) {
    shell.cd(clonePath);
    let currentBranch = shell.exec('git symbolic-ref --short -q HEAD', {async: false, silent: true}).stdout;
    if(currentBranch != targetBranch) {
        let outInfo = shell.exec('git branch', {async: false, silent: true}).stdout;
        let gitcmd = outInfo.indexOf(targetBranch) >= 0 ? ('git checkout ' + targetBranch) : ('git checkout -b ' + targetBranch + ' origin/' + targetBranch);
        shell.exec('git pull && ' + gitcmd, {async: false, silent: true});
    }
    shell.exec('git pull', {async: false, silent: true}, function (code, stdout, stderr) {
        if (code != 0) {
            console.log(stderr);
            return deferred.reject('git pull error');
        }
        console.log(stdout);
        console.log('git pull run success');
        return buildTest(projectName, targetBranch);
    })
} else {
    if (!fs.existsSync(projects_path)) {
        fs.mkdirSync(projects_path);
    }
    shell.cd(projects_path);
    shell.exec('git clone ' + repository, function (code, stdout, stderr) {
        if (code != 0) {
            console.log(stderr);
            return deferred.reject('git clone error');
        }
        console.log('git clone success');
        shell.cd(clonePath);
        let outInfo = shell.exec('git branch', {async: false, silent: true}).stdout;
        let gitcmd = outInfo.indexOf(targetBranch) >= 0 ? ('git checkout ' + targetBranch) : ('git checkout -b ' + targetBranch + ' origin/' + targetBranch);
        shell.exec(gitcmd, {async: false, silent: true});
        return buildTest(projectName, targetBranch);
    })
}
return deferred.promise;

}

// 構建專案 function buildTest(projectName, targetBranch) { shell.cd(clonePath); shell.exec('npm config set registry https://registry.npm.taobao.org && npm install', {async: true, silent: true}, function (code, stdout, stderr) { if (code != 0) { console.log(stderr); return deferred.reject('npm install error'); } console.log('npm install success'); shell.rm('-rf', path.join(clonePath, 'dist')); let testCommand = config[repositoryName].commands.test || 'npm run test'; //構建測試檔案命令列 shell.exec(testCommand, {async: true, silent: true}, function (code, stdout, stderr) { if (code != 0) { console.log(stderr); return deferred.reject('npm run test fail'); } console.log('npm run test success'); copyPage(repositoryName, 'test'); // copy到測試目錄 if(targetBranch != 'master') { shell.exec('exit 0'); deferred.resolve('build success and finish'); return; // 提測時只構建測試檔案 } // 構建最終上線檔案 shell.rm('-rf', path.join(clonePath, 'dist')); let buildCommand = config[repositoryName].commands.build || 'npm run build'; //構建預上線檔案命令列 shell.exec(buildCommand, {async: true, silent: true}, function (code, stdout, stderr) { if (code != 0) { console.log(stderr); return deferred.reject('npm run build fail'); } console.log('npm run build success'); copyPage(repositoryName, 'online'); //copy到上線正式目錄

            // 每次合併master構建後,都切換到測試分支,便於平臺讀取config.json資訊(測試分支是最新的)
            shell.exec('git checkout ' + config[projectName].testEnv.targetBranch, {async: false, silent: false}); 
            shell.exec('exit 0');
            deferred.resolve('build success and finish');
        })
    })
})

} 複製程式碼3. 動態擴充套件專案 通過修改專案配置檔案,接入不同的專案,配置資訊有每個專案要上傳的CDN路徑、構建命令、專案目錄展示資訊檔案路徑(config.json),如下圖: // 接入該平臺的專案列表 module.exports = { 'h5-activity-cms': { git_ssh_url: '[email protected]:awesome_space/awesome_project.git', desc: '前端名獅專案', tabContent: '前端名獅', //頁面中tab展示文字 onlineParam: { //上傳cdn的引數,根據自己專案設定 html: { domain: '', path: '' }, js: { domain: '', path: '' } }, commands: { //構建指令碼命令列 test: 'npm run test', build: 'npm run build' },

    configFile: 'config.json', // 活動頁面列表資訊
}

} 複製程式碼4. 佇列處理 構建目標檔案的過程中,很多生成檔案、壓縮、copy的非同步操作,不同的merge請求,有可能操作的是同一個檔案,所以需要對merge請求做佇列處理。 class TaskQueue { constructor() { this.list = []; this.isRunning = false; } addTask(task) { this.list.push(task); if(this.isRunning) { return; } this.start(); } shift() { return this.list.length > 0 ? this.list.shift() : null; } run() { let task = this.shift(); if(!task) { this.isRunning = false; return; } task(); } start() { this.isRunning = true; this.run(); } } module