1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScript: fileのjs化とか

Posted at

fetchで読み込んだfileの文字列をjsとみなして実行。

UTF8形式限定
//非同期
fetch("a.txt").then(a=>a.text().then(a=>eval(a)))
//同期
(async()=>{eval(await(await fetch("a.txt")).text())})()
UTF8以外
//TextDecoderの引数に文字符号指定. 以下はshift-jisの例
//非同期
fetch("a.txt").then(a=>a.arrayBuffer().then(a=>eval(new TextDecoder("sjis").decode(a))))
//同期
(async()=>{eval(new TextDecoder("sjis").decode(await(await fetch("a.txt")).arrayBuffer()))})()

evalなどという邪道を使いたくないならFunction(...)()を利用したり、以下のようにscript要素を作って中に突っ込んだりするといい

王道
fetch("a.txt").then(a=>a.text().then(txt=>{
var e=document.createElement("script");
	e.type="text/javascript";
	e.charset="utf-8";
	e.text=txt;
	document.getElementsByTagName('head')[0].appendChild(e)
}))

ここからが本番。圧縮fileをjsとみなして実行。base64変換等が不要なので手軽な上に圧縮率も落ちない

gzip展開+js実行
//TextDecoderの引数に元の文字符号指定(UTF8なら不要)
fetch("a.js.gz").then(a=>a.arrayBuffer().then(b=>new Response(new Blob([b]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer().then(c=>eval(new TextDecoder().decode(c)))))

XMLHttpRequestを利用した別解

UTF8形式限定
let xhr=new XMLHttpRequest;
xhr.onload=a=>eval(xhr.response);
xhr.responseType="text";
xhr.send(xhr.open("GET","a.txt"))
UTF8以外
let xhr=new XMLHttpRequest;
xhr.onload=a=>eval(new TextDecoder("sjis").decode(xhr.response))
xhr.responseType="arraybuffer";
xhr.send(xhr.open("GET", "a.txt"))
gzip展開+js実行
let xhr=new XMLHttpRequest;
xhr.onload=a=>new Response(new Blob([xhr.response]).stream().pipeThrough(new DecompressionStream("gzip"))).arrayBuffer().then(b=>eval(new TextDecoder().decode(b)));
xhr.responseType="arraybuffer";
xhr.send(xhr.open("GET","a.js.gz"))

ちなみにsendの引数にopenの返り値を突っこむ必要はない。普通は以下のように分けて書くものだが、圧縮中毒患者はそんな事しないのだ

xhr.open("GET","a.txt");
xhr.send()

応用

今時gzipごときの圧縮率では物足りないと言わざるを得ない。巨大fileを圧縮するならLZMAの出番である。どこぞの血迷ったprogrammerが超小型のdecoderとやらを公開していらっしゃるので、ありがたく拝借しちゃいましょう(戻り値はUint8Arrayに変更)

lzma.js
// @u: Array/Uint8Array
// @return: Uint8Array
lzma=u=>{for(var a=0,b,c,d=u[0],e=d/9,f=(b,a,d=b[a]||(b[a]=1024),c=d*(h>>>11))=>(c=c>n>>>0?(h=c,b[a]+=2048-d>>5,0):(h-=c,n-=c,b[a]-=d>>5,1),h>>24||(h<<=8,n=n<<8|u[i++]),c),q=(b,a)=>f(b,0)?f(b,1)?18+r(b,8,1):10+r(b,3,a*16+261):2+r(b,3,a*16+511),r=(b,a,c,d=1,e=a)=>{for(;a--;)d+=d+f(b,d+c);return 1<<e^d},s,t,v,w=d%9,j,l,n,m=1<<e/5,g=1<<e%5,p=d=0,A=0,o=[],h=16|g--<<8,i=11,k=i;h--;)f[h]=[];for(;i<18;n=n<<8|u[i++])A=u[k--]+A*256;for(;p<A;d=p&m-1)if(f(f[1],s=a*16+d)){if(f(f[e=k=0],a))f(f[2],a)?(f(f[3],a)?(f(f[4],a)?(e=j,j=t):e=t,t=v):e=v,v=b,b=e):(k=!f(f[5],s))&&(a=7>a?9:11),k||(k=q(f[9],d),a=7>a?8:11);else{k=q(f[8],d),a=7>a?7:10,j=t,t=v,v=b,b=r(f[7],6,6>k?k-2<<6:192);if(b>3){if(s=b>>1,d=14>b,l=31-b+(b=(2|b&1)<<--s),!d){for(l=0;4<s--;d+=d-c)h>>>=1,c=n-h>>>31,n-=h&--c,h>>24||(h<<=8,n=n<<8|u[i++]);b+=d<<++s}for(d=1;s>e;b+=c<<e++)d+=d+=c=f(f[6],d+l);if(b<0)break}}for(e=p+~b;k--;)l=o[p++]=o[e++]}else{l=f[16+(l>>8-w|(p&g)<<w)],d=1;if(7>a)for(;d<256;)d+=d+f(l,d);else{for(e=o[p+~b];d<256;)if(k=e>>7&1,e+=e,d+=d+=c=f(l,d|k+1<<8),c^k)for(;d<256;)d+=d+f(l,d)}l=o[p++]=d-256;a-=4>a?a:9<a?6:3}return new Uint8Array(o)}

TextDecoder()の引数に元の文字符号を指定するのは前述の通り。以下の例では引数省略(UTF8)

lzma展開+js実行
fetch("a.js.lzma").then(a=>a.arrayBuffer().then(a=>eval(new TextDecoder().decode(lzma(a)))))

巨大なwasm fileを圧縮しておいて、展開したものとWebAssemblyを組み合わせるのに役立ちやがるぞ

補足

LZMAで圧縮するにはここにあるLZMA SDKの書庫に格納されているlzma.exeを利用する

lzma.exe e a.js a.js.lzma

などと実行すれば圧縮fileが生成される。browserで圧縮処理したいならhexを使うといい。ただし圧縮設定は変更できない。githubのexamplesに良い例が丸出しになっている

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?