본문으로 건너뛰기

"javascript" 태그로 연결된 112개 게시물개의 게시물이 있습니다.

모든 태그 보기

· 약 2분

최근 소스들을 까보다가 발견했는데, npm에 등록된 패키지를 CDN으로 바로 활용 가능한 서비스가 있다. 바로 unpkg이다. 리젼은 여기서 확인 가능하다.

사용법은 엄청나게 간단하다. node_modules 폴더 안에 있는 구조를 URL에 그대로 입력만 해주면 된다. 몇 가지 예로 확인해보자.

<!-- React -->
<script src="https://unpkg.com/[email protected]/dist/react.min.js"></script>
<!-- Lodash -->
<script src="https://unpkg.com/[email protected]/lodash.min.js"></script>
<!-- Bootstrap css -->
<script src="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css"></script>

node_modules 안의 경로가 생각나지 않는다 라면 폴더 경로까지만으로 웹에서 접근해보자. 예를 들어 Bootstrap4라면 https://unpkg.com/[email protected]/ 까지만 들어가면 폴더 구조가 보인다.

여담

블로그의 스크립트도 unpkg로 바꿨는데, 로딩속도가 1초 가까이 줄어든 느낌이다.

이슈

unpkg로 스크립트를 가져오는 도중에 503 timeout 에러가 발생해서 블로그가 동작하지 않았었다. 같은 방법으로 동작하지만 좀 더 reliable한 서비스인 jsdelivr를 사용하자.

· 약 3분

Bower의 시대가 끝났다. 홈페이지를 들어가보면 다음과 같은 문구가 보인다.

..psst! While Bower is maintained, we recommend yarn and webpack for new front-end projects!

Yarn을 사용해보자.

2020년에는 npm 사용을 추천드립니다. 더 이상 느리지 않습니다.

NPM으로 설치할 수도 있는데 추천하는 방법은 Installer이니 다운받고 설치해주면 된다! NPM으로 설치시에는 환경변수 등록을 거쳐야한다.

설치 후 Bash에서 확인해보자.

$ yarn --version
0.24.5

사용법

npm 사용법과 아주 유사하다. 기존 NodeJS 패키지에서 yarn 명령어만을 입력하면 완벽히 호환이 되고, 새로운 프로젝트라면 yarn init 명령어를 실행하면 된다. package.json을 사용하기 때문에 그냥 명령어만 바뀌었다고 생각하면 된다. (패키지들도 npm의 것을 공유한다.)

명령어 비교

install이 add로, uninstall이 remove로, update가 upgrade로 바뀐게 사실상 끝이다. 자세한 옵션은 CLI Docs를 참조하자.

npmYarn
npm installyarn install
(N/A)yarn install --flat
(N/A)yarn install --har
(N/A)yarn install --no-lockfile
(N/A)yarn install --pure-lockfile
npm install [package](N/A)
npm install --save [package]yarn add [package]
npm install --save-dev [package]yarn add [package] [--dev/-D]
(N/A)yarn add [package] [--peer/-P]
npm install --save-optional [package]yarn add [package] [--optional/-O]
npm install --save-exact [package]yarn add [package] [--exact/-E]
(N/A)yarn add [package] [--tilde/-T]
npm install --global [package]yarn global add [package]
npm update --globalyarn global upgrade
npm rebuildyarn install --force
npm uninstall [package](N/A)
npm uninstall --save [package]yarn remove [package]
npm uninstall --save-dev [package]yarn remove [package]
npm uninstall --save-optional [package]yarn remove [package]
npm cache cleanyarn cache clean
rm -rf node_modules && npm installyarn upgrade

Global 경로

  • Windows: %LOCALAPPDATA%/Yarn/config/global

환경 변수 설정

설정을 확인한 뒤 prefix 경로를 PATH에 추가해주면 된다.

$ yarn config list
# { prefix: 'C:\\Users\\{NAME}\\npm' }

결론

bower_components 안녕 이젠 node_modules만 있겠구나

· 약 3분

170323에 Angular2의 stable 버전이라고 할 수 있는 Angular4가 나왔다. Angular2하고 있었는데 나도 모르는 사이에 버전이 4가 되었나, 1에서 2가 그렇게 많이 바뀌었는데 Angular4는 얼마나 바뀐걸까?

Angular2부터는 npm으로 관리되기에 소스의 버전을 따라서 명명을 해 비롯된 것으로 큰 변경점이 없으니 안심해도 된다.

버전별로 보면 이렇다.

  • Angular1 : 기존 javascript로 코딩하던 $scope를 사용했던 버전
  • Angular1.x : Component가 도입된 버전
  • Angular2 : 처음으로 ts가 사용되고 새로운 앵귤러가 된 버전
  • Angular3 : 아무도 모르게 사용을 했었다. package.json에서 @angular/router를 보자 3버전대일 것이다.
  • Angular4 : 성능이 개선되었고 모든 Angular 모듈이 4버전

모든 변경점은 앵귤러 블로그에서 확인할 수 있다.

  • 컴파일시 가벼워졌다.
  • 애니메이션 패키지가 angular/core에서 angular/animation으로 분리되었다.
  • ngIf에서 else 구문을 쓸 수 있다.
  • angular universial의 기능이 angular/platform-server로 통합되었다.
  • typescript 2.1, 2.2버전 호환이 되었다.
  • angular-cli가 1버전으로 업그레이드 되어 1버전의 cli로 프로젝트 생성시 angular4 버전으로 생성이 된다.

업그레이드

# angular 및 typescript
$ npm install @angular/common@latest @angular/compiler@latest @angular/compiler-cli@latest @angular/core@latest @angular/forms@latest @angular/http@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/platform-server@latest @angular/router@latest @angular/animations@latest typescript@latest --save

# zone.js
$ npm install [email protected] --save

# angular-cli
$ npm install @angular/[email protected] --save-dev

충돌

  • angular animation 기능을 사용한다면 platform-browser/animation의 BrowserAnimationsModule을 추가적으로 넣어줘야할 수도 있다.
  • typescript가 업그레이드 되면서 사용하지 않는 메소드나, 오류가 발생할 수 있는 스코프에 대해 linting이 더 강력해진 느낌이었다.

· 약 2분

Single line

var i,
sum = 0;
for (i = 0; i < 10; ++i, sum += i);

console.log(`${i} ${sum}`);

일반적인 형태

var j,
sum2 = 0;
for (j = 0; j < 10; ++j) {
sum2 += j;
}

console.log(`${j} ${sum2}`);

두 예제의 결과는 어떻게 나올까. 첫번째는 10 55, 두번째는 10 45가 나온다.

설명

i 와 j 의 전위 후위 연산은 별로 중요하지 않다. (++i 나 i++이나 결과는 같게 나온다)

Single line

var i,
sum = 0;
// 1 2 3 4
for (i = 0; i < 10; ++i, sum += i);

console.log(`${i} ${sum}`);

일반적인 형태

var j,
sum2 = 0;
// 1 2 4
for (j = 0; j < 10; ++j) {
// 3
sum2 += j;
}

console.log(`${j} ${sum2}`);

안티패턴의 끝

var k,
sum3 = 0;
// 1 2 4 5
for (k = 0; k < 10; ++k, sum3 += k)
// 3
console.log(`${k} ${sum3}`);

연산의 실행 순서가 다르다고 이해하면 되겠다.

· 약 2분

연번 체크 알고리즘이라고도 하는 것 같다. 통계 또는 비밀번호의 연속성을 체크하기 위해 필요할 때가 있다. 비밀번호 연속성 체크에는 target[j]의 데이터를 charCodeAt 을 붙여 처리하면 된다.

function checkSequenceNumbers(target, counterLength = 6) {
// under es6
// let sequentialCounter = Array.apply(null, Array(counterLength)).map(Number.prototype.valueOf,0);
let sequentialCounter = new Array(counterLength).fill(0);
let count = 0;

for (let i = 0, len = target.length; i < len; i++) {
let subCount = 0;

for (let j = 1; j < len; j++) {
if (target[j] === target[i] + 1) {
subCount = subCount + 1;
} else {
continue;
}
}

count = count + subCount;
if (subCount === 0) {
sequentialCounter[count] = sequentialCounter[count] + 1;
count = 0;
}
}

return sequentialCounter;
}

let target = [1, 2, 3, 5, 6, 7, 8, 10, 11, 13, 16, 17];
console.log(checkSequnceNumbers(target));
// => [1, 2, 1, 1, 0, 0]

설명

n 과 n+1... n+n-1 을 비교해서 카운트한다. 결과는 sequentialCounter 배열에 각 포지션에 들어간다.

2 연속 숫자 1 개가 있다면 sequentialCounter[2] = 1;

여담

왜 이런걸 공유를 안할까?

· 약 1분

npm으로 npm의 버전을 업데이트 할 때의 명령어는 다음과 같다.

$ npm install -g npm

업데이트 명령 실행 후 오류가 발생한 뒤 npm 명령어가 없다는 경우가 생길 수 있다. 당황하지 말고 아래 명령어를 실행한다.

# 캐시 강제 삭제
$ npm cache clean -f

# npm 다운로드
$ curl http://npmjs.org/install.sh | sh

다시 npm이 설치되어 npm 명령어를 실행할 수 있다.

· 약 1분

document.querySelector를 사용해 id에 .이 포함된 element를 선택시

<div id="id.has.pariod"></div>
<script>
var $div = document.querySelector("#id.has.pariod");
console.log($div);
// => undefined;
</script>

undefined를 반환하며 선택이 되지 않는다. .(pariod)는 class 선택자라 중복이되어 발생하는 오류이다.

해결

.에 역슬래시를 2개 붙혀 escape 시킨다.

var $div = document.querySelector("#id\\.has\\.pariod");
console.log($div);
// => <div id="id.has.pariod"></div>

· 약 4분

버튼을 눌러 이미지를 다운로드 받고 싶다면 어떻게 해야될까? Client Side 에서 할 수 있는 가장 쉬운 방법은 download attribute를 사용하는 것이다. 하지만 예상했듯이 이 속성은 IE 에서 지원하지 않는다.

base64

먼저 이미지를 base64 인코딩해야한다. FileReader 또는 Canvas 를 이용해 변환할 수 있는데 stackoverflow 의 명쾌한 답변을 참조하자. jQuery 환경이라면 Reading binary data using jquery ajax를 참조해도 된다.

base64encode 가 된 이미지 데이터가 뽑아지면 시작할 수 있다.

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2CAAAAADAeSUUAAADN0lEQVR42u3aQY7CMBAEQP7/afaKtEu2exwk4lROKITEZSQGT/vxiI/ny/H7zOv513ffXZl89viad6M6+cDGxsa+CDsZUP5uMqx3d8gntB3nH1ODjY2NvR373S/88TUtMuG1E5qMExsbGxv7eChJUTl+4nP5wMbGxsZu2UlbJy9RyQS1SxpsbGzsu7FXCkPeTkoihGTQeUPqhF4aNjY29tez81T0+19/JN/GxsbG/mL2rHEzi2OTxc968BwpsLGxsTdiz0Lc/I9+voBprzwhhMbGxsbeiN1S2xvNWkuzZtD6aLGxsbGvxW4f0BaqtpU/C4/bhRA2Njb2TuwkTF0ZVn4+/+zKJEb7lbCxsbG3YM9aRe0CJo8NkivzFhU2Njb2ruwW3/71r0vL6FnDXUvY2NjYl2XPAto8mm0LUrIImcUG2NjY2Luy1xv6eTCwMomzAlZPEzY2NvbF2ceDWIld82XJSjjRbsfExsbG3om9EgbkDak2GM5L6bApho2Njb0F+/imeclJWj/t61nwEBU2bGxs7I3Yn2vifKLN1MKKxQk2Njb2ZdlnFYzZ9bMG00rbCxsbG/sO7Lw13261zIvlMXVW5B7tDGFjY2NvwZ4lpDmpLYenXYmNjY29ETv5u5+XkDYYaFtL7ZKm2KmEjY2NfVl2u10mWYS009q2hNoC9scZbGxs7I3YM+SsjJ3V0lqZ3MfKd4uNjY39lexk6Hlkm4fHs40+7dacomhhY2Njb8TOi1MeCZw7oflER1t2sLGxsS/Onq1d2hC3XYq0japZCIGNjY29K7u9Xds8WmlU5SWwiH6xsbGxt2DnP/dthNBS12FFScPGxsbelN02aNrFRh4tzJ5SbO7BxsbGvgE7Aa8EACvlc6X9hI2Njb0T+1keySBmm3jy0Le92z9JCDY2NvbF2W0BOLfwHJ9vW0v1UgQbGxt7I3ZStFbKTLKMab+TZFH0T+SAjY2NvR07b7vP4ti2TK5MSvRcbGxs7Nuz2wfnT1nZalncBxsbG/vG7PWtlmdt5VlpimFjY2Pvx06aRHlBarfs5O3+9ut5u/rAxsbG3og9W1TkxWYWP7T3zBtV2NjY2BuxfwBOAYaS/PUQNQAAAABJRU5ErkJggg==

blob

이제 이미지 데이터를 Blob Object 로 변환해야한다.

// imageSrc는 위의 이미지 데이터이다.
// 실제 데이터는 iVBO...부터이므로 split한다.
var imgData = atob(imageSrc.split(",")[1]);
var len = imgData.length;
var buf = new ArrayBuffer(len); // 비트를 담을 버퍼를 만든다.
var view = new Uint8Array(buf); // 버퍼를 8bit Unsigned Int로 담는다.
var blob, i;

for (i = 0; i < len; i++) {
view[i] = imgData.charCodeAt(i) & 0xff; // 비트 마스킹을 통해 msb를 보호한다.
}
// Blob 객체를 image/png 타입으로 생성한다. (application/octet-stream도 가능)
blob = new Blob([view], { type: "image/png" });

msSaveOrOpenBlob

IE10+ 에서 사용가능한 msSaveOrOpenBlob가 필요하다.

msSaveBlob 메서드는 저장 단추만 사용자에게 제공하는 반면 msSaveOrOpenBlob 메소드는 저장 및 열기 단추를 모두 제공한다는 것이 차이점이다.

// blob과 저장될 파일명을 받는다.
window.navigator.msSaveOrOpenBlob(blob, "new_file_name.png");

Not IE

IE 가 세상에 존재하지 않는다면 코드는 아주 예쁘게 짤 수 있다.

<a href="data:image/png;base64,iVBORw0KG..." download="new_file_name.png">
<img src="data:image/png;base64,iVBORw0KG..." />
</a>

a 태그가 보기 싫다면 아래 구문을 포함해 함수로 만든다.

var a = document.createElement("a");
a.style = "display: none";
a.href = img.src;
a.download = "new_file_name.png";

document.body.appendChild(a);
a.click();

setTimeout(function () {
// 다운로드가 안되는 경우 방지
document.body.removeChild(a);
}, 100);

Blob 재사용

IE 때문에 만들었던 Blob 객체를 URL 기능을 이용해 재사용해보자.

var url = URL.createObjectURL(blob);
var a = document.createElement("a");
a.style = "display: none";
a.href = url;
a.download = "new_file_name.png";

document.body.appendChild(a);
a.click();

setTimeout(function () {
document.body.removeChild(a);
URL.revokeObjectURL(url); // 메모리 해제
}, 100);

소스

/**
* [downloadImage]
* @param {[string]} img [base64encoded image data]
* @param {[string]} fileName [new file name]
* @return [image file]
*/
function downloadImage(img, fileName) {
var imgData = atob(img.src.split(",")[1]),
len = imgData.length,
buf = new ArrayBuffer(len),
view = new Uint8Array(buf),
blob,
i;

for (i = 0; i < len; i++) {
view[i] = imgData.charCodeAt(i) & 0xff; // masking
}

blob = new Blob([view], {
type: "application/octet-stream",
});

if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
//var url = URL.createObjectURL(blob);
var a = document.createElement("a");
a.style = "display: none";
//a.href = url;
a.href = img.src;
a.download = fileName;
document.body.appendChild(a);
a.click();

setTimeout(function () {
document.body.removeChild(a);
//URL.revokeObjectURL(url);
}, 100);
}
}

여담

![image from hexo](https://i.imgur.com/36Rf76J.gif title:"실망시키지 않는 IE")

· 약 2분

d3 와 d3-cloud 를 사용해 R 의 Word Cloud 를 javascript 로 구현해보자.

# npm
$ npm install d3
$ npm install d3.layout.cloud
# bower
$ bower install d3
$ bower install d3-cloud

예제

소스

<script src="/bower_components/d3/d3.min.js"></script>
<script src="/bower_components/d3-cloud/build/d3.layout.cloud.js"></script>

<script>
var fill = function (i) {
return d3.schemeCategory20b[i];
};
var layout = d3.layout
.cloud()
.size([500, 500])
.words(
[
"텍스트",
"마이닝",
"샘플",
"좋아요",
"R",
"Word",
"Cloud",
"text",
"mining",
].map(function (d) {
return { text: d, size: 10 + Math.random() * 90, test: "haha" };
})
)
.padding(5)
.rotate(function () {
return ~~(Math.random() * 2) * 90;
})
.font("Impact")
.fontSize(function (d) {
return d.size;
})
.on("end", draw);

layout.start();

function draw(words) {
d3.select("body")
.append("svg")
.attr("width", layout.size()[0])
.attr("height", layout.size()[1])
.append("g")
.attr(
"transform",
"translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")"
)
.selectAll("text")
.data(words)
.enter()
.append("text")
.style("font-size", function (d) {
return d.size + "px";
})
.style("font-family", "Impact")
.style("fill", function (d, i) {
return fill(i);
})
.attr("text-anchor", "middle")
.attr("transform", function (d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function (d) {
return d.text;
});
}
</script>

d3-cloud의 예제소스는 nodejs 환경에서만 돌릴 수 있어 모든 웹에서 예제를 사용할 수 있게 수정했다.

결과

image from hexo