LHJ

I'm a FE developer.

compare before & after screenshot-last4

26 Jun 2020 » node

소스정리

  • git bash창을 제외한 다른 터미널에서 process.exit() 이슈 해결 못했다..해결하고픔
  • image_compare.js
  • package.json
  • 설명서
  • download

  •     'use strict'
          
        process.setMaxListeners(0);
          
        const fs = require('fs'),
            path = require('path'),
            exec = require('child_process'),
            inquirer = require('inquirer'),
            captureWebsite = require('capture-website'),
            resemble = require('resemblejs'),
            file = [
                path.join(__dirname, 'pc/before'),
                path.join(__dirname, 'pc/after'),
                path.join(__dirname, 'm/before'),
                path.join(__dirname, 'm/after')
            ],
            before = fs.readFileSync(path.join(__dirname, 'dist/before/index.html'), 'utf8'),
            after = fs.readFileSync(path.join(__dirname, 'dist/after/index.html'), 'utf8');
          
        // make folders
        file.map(f => fs.mkdirSync(f, {recursive: true}))
          
        // before index.html 과 after index.html 파일에서 리스트를 추출하여 beforeList, afterList 변수에 저장
        let beforeList = before.match(/[src]*\/*html\/(.*?)\.html/g),
            afterList = after.match(/[src]*\/*html\/(.*?)\.html/g),
            beforeItems = [],
            afterItems = [];
          
        // beforeItems 배열과 afterItems 배열에 로컬서버 주소를 각각 저장
        for (let i = 0; i < beforeList.length; i++) {
            if (!Array.isArray(beforeItems[i])) beforeItems[i] = [];
            beforeItems[i] = [`http://localhost:8000/dist/before/${beforeList[i]}`, path.basename(beforeList[i])]
        }
        for (let i = 0; i < afterList.length; i++) {
            if (!Array.isArray(beforeItems[i])) afterItems[i] = [];
            afterItems[i] = [`http://localhost:8000/dist/after/${afterList[i]}`, path.basename(afterList[i])]
        }
          
        // screenshot compare function
        const compare = (pc, i, m) => {
            const num = beforeList.length > afterList.length ? afterList.length : beforeList.length,
                res = ['pc', 'm'],
                x = i === 'iPhone X' ? 'iphoneX 화면으로 촬영되었습니다.' : `m화면 ${m}px width 값에서 촬영되었습니다.`;
            let compareRes = [`pc화면 ${pc}px width 값에서 촬영되었습니다.`, x];
            return new Promise(resolve => {
                res.map(a => {
                    for (let i = 0; i < num; i++) {
                        resemble(path.join(__dirname, `${a}/before/${path.basename(beforeList[i])}.png`))
                            .compareTo(path.join(__dirname, `${a}/after/${path.basename(afterList[i])}.png`))
                            .onComplete(function (data) {
                                // let diff = JSON.stringify(data.diffBounds)
                                if (data.misMatchPercentage !== '0.00') {
                                    compareRes.push(`${a} - ${beforeList[i]} : ${afterList[i]} = ${data.misMatchPercentage}`);
                                } else {
                                    compareRes.push('100% 일치');
                                }
                            });
                    }
                })
                resolve(compareRes.join('\n'));
            })
        }
          
        // 포트번호
        let port;
          
        // 결과물
        let res;
          
        // screeshot options
        let mobileOpts = {
            fullPage: true,
            delay: 5,
            // emulateDevice: 'iPhone X',
            // width: mobileWidth,
        };
        let pcOpts = {
            fullPage: true,
            delay: 5,
            // width: pcWidth,
        };
          
        const questions = [
            {
                type: 'number',
                name: 'port',
                message: '포트번호를 입력해주세요.',
                default: 8000,
            },
            {
                type: 'confirm',
                name: 'result',
                message: '결과물을 텍스트 파일로 내보낼까요?',
            },
            {
                type: 'number',
                name: 'PCBrowserWidth',
                message: 'PC 브라우저 width 값을 얼마로 할까요?',
                default: 1280,
            },
            {
                type: 'confirm',
                name: 'iphoneX',
                message: '아이폰X 화면으로 찍으실건가요?',
            },
            {
                type: 'number',
                name: 'mobileBrowserWidth',
                message: '모바일 width 값은 얼마로 할까요?',
                default: 375,
                when: function (answers) {
                    if (answers.iphoneX) return false;
                    return true
                }
            }
        ];
          
        inquirer.prompt(questions).then(answers => {
            const answerData = JSON.stringify(answers);
            const answerDataJson = JSON.parse(answerData);
            port = answerDataJson.port;
            res = answerDataJson.result;
            pcOpts.width = Number(answerDataJson.PCBrowserWidth);
            mobileOpts.emulateDevice = answerDataJson.iphoneX === true ? 'iPhone X' : '';
            mobileOpts.width = Number.isInteger(answerDataJson.mobileBrowserWidth) ? answerDataJson.mobileBrowserWidth : 375;
        }).then(result => {
            // server 실행
            exec.exec(`http-server -a localhost -p ${port}`, {maxBuffer: 1024 * 500}, (err, stdout, stderr) => {
                if (err) {
                    console.error(err);
                }
                console.log(stdout);
            });
            // screenshot and compare
            const res = (async () => {
                await Promise.all(beforeItems.map(([url, filename]) => {
                    return captureWebsite.file(url, path.join(__dirname, `pc/before/${filename}.png`), pcOpts);
                }));
                await Promise.all(afterItems.map(([url, filename]) => {
                    return captureWebsite.file(url, path.join(__dirname, `pc/after/${filename}.png`), pcOpts);
                }));
                await Promise.all(beforeItems.map(([url, filename]) => {
                    return captureWebsite.file(url, path.join(__dirname, `m/before/${filename}.png`), mobileOpts);
                }));
                await Promise.all(afterItems.map(([url, filename]) => {
                    return captureWebsite.file(url, path.join(__dirname, `m/after/${filename}.png`), mobileOpts);
                }));
                const com = await compare(pcOpts.width, mobileOpts.emulateDevice, mobileOpts.width);
                if (res) {
                    fs.writeFileSync('result.txt', com);
                    console.log(com);
                } else {
                    console.log(com);
                }
                process.exit();
            })();
        }).catch(function (err) {
            console.log(err);
        });
    
  •     {
          "name": "99_image_compare",
          "version": "1.0.0",
          "description": "",
          "main": "index.js",
          "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1"
          },
          "author": "",
          "license": "ISC",
          "devDependencies": {
            "capture-website": "^1.0.0",
            "http-server": "^0.12.3",
            "inquirer": "^7.1.0",
            "resemblejs": "^3.2.4"
          }
        }
    
  •   주의 사항 : http-server로 인해 오류가 생길 시
      npm i -g http-server 
      실행해서 전역적으로 설치
        
      http-server 모듈은 전역으로 한번만 설치해도 되는 모듈이기 때문
        
        
      10.16.3 버전에서도 성공
      만약 안될 시 아래 명령어로 node_modules 폴더를 삭제 후
        
      rm -rf node_modules/
        
      다시 설치
        
      npm i
        
      그리고 실행
        
        
      git bash에서 사용하는 것이 제일 좋다.
      웹스톰 터미널에서 사용했는데, process.exit() 메서드가 작동하긴하는데
      http://localhost:8000/ 서버를 종료시키질 못한다.
      이상하다.