next-blurhash-previews 0.0.3-beta8 → 0.0.4-beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/.vscode/settings.json +10 -0
  2. package/bin/generateBlurhash.js +38 -7
  3. package/bin/remark-plugin.js +5 -3
  4. package/components/ImageWithPreview.tsx +54 -12
  5. package/components/NextWrapper.js +29 -0
  6. package/components/imagePreviewBootstrap.tsx +13 -6
  7. package/components/workerScript.ts +17 -0
  8. package/imagePreviewBootstrap.js +14 -0
  9. package/index.js +3 -2
  10. package/package.json +5 -4
  11. package/util/setBootstrap.js +19 -20
  12. package/vite.nextwrapper.config.ts +18 -0
  13. package/{vite.config.ts → vite.wc.config.ts} +3 -6
  14. package/vite.worker.config.ts +18 -0
  15. package/.prettierrc +0 -3
  16. package/components/NextWrapper.tsx +0 -27
  17. package/img1.png +0 -0
  18. package/img5.png +0 -0
  19. package/junk.js +0 -1
  20. package/next-runner/.eslintrc.json +0 -3
  21. package/next-runner/README.md +0 -34
  22. package/next-runner/blog-posts/post1.md +0 -303
  23. package/next-runner/blog-posts/post2.md +0 -10
  24. package/next-runner/blog-posts/post3.md +0 -10
  25. package/next-runner/blog-posts/post4.md +0 -10
  26. package/next-runner/next.config.js +0 -6
  27. package/next-runner/package-lock.json +0 -5080
  28. package/next-runner/package.json +0 -23
  29. package/next-runner/pages/_app.js +0 -11
  30. package/next-runner/pages/_document.js +0 -17
  31. package/next-runner/pages/index.js +0 -47
  32. package/next-runner/public/css-modules/loadingError.png +0 -0
  33. package/next-runner/public/css-modules/styledComponent.png +0 -0
  34. package/next-runner/public/css-modules/styledSass.png +0 -0
  35. package/next-runner/public/css-modules/unstyledComp.png +0 -0
  36. package/next-runner/public/dynamo-introduction/img1.png +0 -0
  37. package/next-runner/public/dynamo-introduction/img10.png +0 -0
  38. package/next-runner/public/dynamo-introduction/img11.png +0 -0
  39. package/next-runner/public/dynamo-introduction/img12.png +0 -0
  40. package/next-runner/public/dynamo-introduction/img13.png +0 -0
  41. package/next-runner/public/dynamo-introduction/img14.png +0 -0
  42. package/next-runner/public/dynamo-introduction/img15.png +0 -0
  43. package/next-runner/public/dynamo-introduction/img2.png +0 -0
  44. package/next-runner/public/dynamo-introduction/img3.png +0 -0
  45. package/next-runner/public/dynamo-introduction/img4.png +0 -0
  46. package/next-runner/public/dynamo-introduction/img5.png +0 -0
  47. package/next-runner/public/dynamo-introduction/img5a.png +0 -0
  48. package/next-runner/public/dynamo-introduction/img6.png +0 -0
  49. package/next-runner/public/dynamo-introduction/img7.png +0 -0
  50. package/next-runner/public/dynamo-introduction/img8.png +0 -0
  51. package/next-runner/public/dynamo-introduction/img9.png +0 -0
  52. package/next-runner/public/favicon.ico +0 -0
  53. package/next-runner/public/img1.png +0 -0
  54. package/next-runner/public/img5.png +0 -0
  55. package/next-runner/public/vercel.svg +0 -4
  56. package/next-runner/styles/Home.module.css +0 -3
  57. package/next-runner/styles/globals.css +0 -22
  58. package/next-runner/yalc.lock +0 -9
  59. package/next-runner/yarn.lock +0 -1650
  60. package/tsconfig.json +0 -21
  61. package/tsconfig.node.json +0 -8
  62. package/yalc.lock +0 -9
@@ -0,0 +1,10 @@
1
+ {
2
+ "vsicons.associations.files": [
3
+ {
4
+ "icon": "vite",
5
+ "extensions": ["vite.worker.config.ts"],
6
+ "filename": true
7
+ },
8
+ { "icon": "vite", "extensions": ["vite.wc.config.ts"], "filename": true }
9
+ ]
10
+ }
@@ -1,11 +1,14 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import colors from "colors";
4
+
1
5
  import sharp from "sharp";
2
6
  import fetch from "node-fetch";
3
7
  import { encode, isBlurhashValid } from "blurhash";
4
8
 
5
- import path from "path";
6
9
  const __dirname = process.cwd();
7
10
 
8
- export async function getSharpImage(imgPath) {
11
+ async function getSharpImage(imgPath) {
9
12
  if (/^http/.test(imgPath)) {
10
13
  const buffer = await fetch(imgPath)
11
14
  .then(fetchResponse => fetchResponse.arrayBuffer())
@@ -13,18 +16,40 @@ export async function getSharpImage(imgPath) {
13
16
 
14
17
  return sharp(buffer);
15
18
  } else {
16
- return sharp(imgPath);
19
+ const ext = path.extname(imgPath);
20
+ const dir = path.dirname(imgPath);
21
+ const basename = path.basename(imgPath, ext);
22
+
23
+ const realImage = sharp(imgPath);
24
+
25
+ const previewOption = path.join(dir, basename + "-preview" + ext);
26
+ console.log(colors.blue("Trying preview", previewOption));
27
+
28
+ if (fs.existsSync(previewOption)) {
29
+ console.log(colors.green("Preview found"));
30
+
31
+ return [realImage, sharp(previewOption)];
32
+ }
33
+
34
+ return [realImage];
17
35
  }
18
36
  }
19
37
 
20
38
  export async function getBlurhash(path) {
21
- const blurhashImage = await getSharpImage(path);
39
+ const [blurhashImage, previewImage] = await getSharpImage(path);
22
40
  const dimensions = await blurhashImage.metadata();
23
41
 
24
- const { width, height } = dimensions;
42
+ const { width: displayWidth, height: displayHeight } = dimensions;
43
+ let { width, height } = dimensions;
44
+
45
+ if (previewImage) {
46
+ const dimensions = await previewImage.metadata();
47
+
48
+ ({ width, height } = dimensions);
49
+ }
25
50
 
26
51
  return new Promise((res, rej) => {
27
- blurhashImage
52
+ (previewImage ?? blurhashImage)
28
53
  .raw()
29
54
  .ensureAlpha()
30
55
  .toBuffer((err, buffer) => {
@@ -40,7 +65,13 @@ export async function getBlurhash(path) {
40
65
  4
41
66
  );
42
67
  if (isBlurhashValid(blurhash)) {
43
- return res({ blurhash, w: width, h: height });
68
+ return res({
69
+ blurhash,
70
+ w: width,
71
+ h: height,
72
+ dw: displayWidth,
73
+ dh: displayHeight,
74
+ });
44
75
  } else {
45
76
  console.log("FAIL");
46
77
  return rej("FAIL");
@@ -10,7 +10,7 @@ export const blurhashPlugin = publicPath => () => {
10
10
  let outstanding = 0;
11
11
 
12
12
  visitParents(tree, "image", async (node, ancestors) => {
13
- let { url: imagePath, alt } = node;
13
+ let { url: imagePath, alt = "" } = node;
14
14
 
15
15
  const originalImg = imagePath;
16
16
  if (!/http/.test(imagePath)) {
@@ -28,6 +28,8 @@ export const blurhashPlugin = publicPath => () => {
28
28
 
29
29
  const blurHash = await getBlurhash(imagePath);
30
30
 
31
+ const { w, h, dw, dh } = blurHash;
32
+
31
33
  console.log(
32
34
  colors.green(`Finished processing ${imagePath}\n\t`, blurHash)
33
35
  );
@@ -37,8 +39,8 @@ export const blurhashPlugin = publicPath => () => {
37
39
 
38
40
  const newNode = `
39
41
  <blurhash-image url="${originalImg}" preview='${JSON.stringify(blurHash)}'>
40
- <img alt="${alt || ""}" src="${originalImg}" slot="image" />
41
- <canvas width="${blurHash.w}" height="${blurHash.h}" slot="preview"></canvas>
42
+ <img alt="${alt}" width="${dw}" height="${dh}" src="${originalImg}" slot="image" />
43
+ <canvas width="${w}" height="${h}" style="width: ${dw}px; height: auto;" slot="preview"></canvas>
42
44
  </blurhash-image>`.trim();
43
45
 
44
46
  parent.children[index] = {
@@ -1,13 +1,19 @@
1
- import { decode } from "../node_modules/blurhash/dist/esm/index";
2
-
1
+ import { decode } from "blurhash/dist/esm";
3
2
  type blurhash = { w: number; h: number; blurhash: string };
4
3
 
4
+ declare global {
5
+ interface HTMLCanvasElement {
6
+ transferControlToOffscreen(): this & Transferable;
7
+ }
8
+ }
9
+
5
10
  class ImageWithPreview extends HTMLElement {
6
11
  sd: ShadowRoot;
7
12
  mo?: MutationObserver;
8
13
 
9
14
  static observedAttributes = ["preview"];
10
15
 
16
+ #connected = false;
11
17
  get #imgEl(): any {
12
18
  return this.querySelector("img");
13
19
  }
@@ -26,6 +32,11 @@ class ImageWithPreview extends HTMLElement {
26
32
  if (this.#imgEl && this.#canvasEl) {
27
33
  this.mo?.disconnect();
28
34
 
35
+ console.log("checkready", this.#imgEl.complete);
36
+
37
+ setInterval(() => {
38
+ console.log("checkready interval", this.#imgEl.complete);
39
+ }, 100);
29
40
  if (this.#imgEl.complete) {
30
41
  this.#imgLoad();
31
42
  } else {
@@ -33,11 +44,12 @@ class ImageWithPreview extends HTMLElement {
33
44
  this.#imgEl.addEventListener("load", this.#imgLoad);
34
45
  }
35
46
 
36
- return true;
47
+ return 1;
37
48
  }
38
49
  };
39
50
 
40
51
  connectedCallback() {
52
+ this.#connected = true;
41
53
  if (!this.#checkReady()) {
42
54
  this.mo = new MutationObserver(this.#checkReady);
43
55
  this.mo.observe(this, {
@@ -49,6 +61,7 @@ class ImageWithPreview extends HTMLElement {
49
61
  }
50
62
 
51
63
  #imgLoad = () => {
64
+ console.log("imgLoad - should work", this.#imgEl.complete);
52
65
  this.sd.innerHTML = `<slot name="image"></slot>`;
53
66
  };
54
67
 
@@ -59,8 +72,16 @@ class ImageWithPreview extends HTMLElement {
59
72
  }
60
73
 
61
74
  #updatePreview() {
75
+ if (!this.#connected || !this.getAttribute("preview")) {
76
+ return;
77
+ }
78
+
62
79
  const previewObj = JSON.parse(this.getAttribute("preview")!);
63
- updateBlurHashPreview(this.#canvasEl, previewObj);
80
+ updateBlurHashPreview(
81
+ this.hasAttribute("sync"),
82
+ this.#canvasEl,
83
+ previewObj
84
+ );
64
85
  }
65
86
  }
66
87
 
@@ -68,15 +89,36 @@ if (!customElements.get("blurhash-image")) {
68
89
  customElements.define("blurhash-image", ImageWithPreview);
69
90
  }
70
91
 
71
- function updateBlurHashPreview(canvasEl: HTMLCanvasElement, preview: blurhash) {
72
- const { w: width, h: height } = preview;
73
-
92
+ const workerBlob = new Blob(
93
+ [document.querySelector("#next-blurhash-worker-script")!.textContent!],
94
+ { type: "text/javascript" }
95
+ );
96
+ const worker = new Worker(window.URL.createObjectURL(workerBlob));
97
+
98
+ function updateBlurHashPreview(
99
+ sync: boolean,
100
+ canvasEl: HTMLCanvasElement,
101
+ preview: blurhash
102
+ ) {
103
+ const { w: width, h: height, blurhash } = preview;
74
104
  canvasEl.width = width;
75
105
  canvasEl.height = height;
76
106
 
77
- const pixels = decode(preview.blurhash, width, height);
78
- const ctx = canvasEl.getContext("2d")!;
79
- const imageData = ctx.createImageData(width, height);
80
- imageData.data.set(pixels);
81
- ctx.putImageData(imageData, 0, 0);
107
+ if (sync) {
108
+ const start = +new Date();
109
+
110
+ const pixels = decode(blurhash, width, height);
111
+ const ctx = canvasEl.getContext("2d")!;
112
+ const imageData = ctx.createImageData(width, height);
113
+ imageData.data.set(pixels);
114
+ ctx.putImageData(imageData, 0, 0);
115
+
116
+ const end = +new Date();
117
+ console.log("Done Encoding Sync", blurhash, end - start);
118
+ } else if (canvasEl.transferControlToOffscreen) {
119
+ const offscreen = canvasEl.transferControlToOffscreen();
120
+ worker.postMessage({ canvas: offscreen, width, height, blurhash }, [
121
+ offscreen,
122
+ ]);
123
+ }
82
124
  }
@@ -0,0 +1,29 @@
1
+ import React, {
2
+ useEffect,
3
+ useRef,
4
+ createElement,
5
+ cloneElement,
6
+ Children,
7
+ } from "react";
8
+
9
+ export const NextWrapper = props => {
10
+ const wcRef = useRef(null);
11
+
12
+ const { blurhash, width, height } = props;
13
+
14
+ const json = JSON.stringify({ w: width, h: height, blurhash });
15
+ const wcProps = { preview: json };
16
+ if (props.sync) {
17
+ wcProps.sync = true;
18
+ }
19
+
20
+ return createElement(
21
+ "blurhash-image",
22
+ {
23
+ ref: wcRef,
24
+ ...wcProps,
25
+ },
26
+ cloneElement(Children.only(props.children), { slot: "image" }),
27
+ createElement("canvas", { width, height, slot: "preview" })
28
+ );
29
+ };
@@ -1,7 +1,14 @@
1
- import { createElement } from "react";
2
- import Script from "next/script";
1
+ import { createElement, Fragment } from "react";
3
2
 
4
- export const imagePreviewBootstrap = createElement(Script, {
5
- dangerouslySetInnerHTML: { __html: `(() => { /*HERE*/ })();` },
6
- strategy: "beforeInteractive",
7
- });
3
+ export const imagePreviewBootstrap = createElement(
4
+ Fragment,
5
+ {},
6
+ createElement("script", {
7
+ id: "next-blurhash-worker-script",
8
+ type: "javascript/worker",
9
+ dangerouslySetInnerHTML: { __html: `(() => { /*WORKER*/ })();` },
10
+ }),
11
+ createElement("script", {
12
+ dangerouslySetInnerHTML: { __html: `(() => { /*WC*/ })();` },
13
+ })
14
+ );
@@ -0,0 +1,17 @@
1
+ import { decode } from "blurhash/dist/esm";
2
+
3
+ addEventListener("message", evt => {
4
+ console.log(evt);
5
+
6
+ const { canvas, width, height, blurhash } = evt.data;
7
+
8
+ console.log("Encoding", blurhash);
9
+ const start = +new Date();
10
+ const pixels = decode(blurhash, width, height);
11
+ const ctx = canvas.getContext("2d");
12
+ const imageData = ctx.createImageData(width, height);
13
+ imageData.data.set(pixels);
14
+ ctx.putImageData(imageData, 0, 0);
15
+ const end = +new Date();
16
+ console.log("Done Encoding", blurhash, end - start);
17
+ });
@@ -0,0 +1,14 @@
1
+ import { createElement, Fragment } from "react";
2
+
3
+ export const imagePreviewBootstrap = createElement(
4
+ Fragment,
5
+ {},
6
+ createElement("script", {
7
+ id: "next-blurhash-worker-script",
8
+ type: "javascript/worker",
9
+ dangerouslySetInnerHTML: { __html: `(() => { "use strict";const I=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","#","$","%","*","+",",","-",".",":",";","=","?","@","[","]","^","_","{","|","}","~"],u=t=>{let n=0;for(let o=0;o<t.length;o++){const e=t[o],c=I.indexOf(e);n=n*83+c}return n},D=t=>{let n=t/255;return n<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)},b=t=>{let n=Math.max(0,Math.min(1,t));return n<=.0031308?Math.round(n*12.92*255+.5):Math.round((1.055*Math.pow(n,.4166666666666667)-.055)*255+.5)},P=t=>t<0?-1:1,p=(t,n)=>P(t)*Math.pow(Math.abs(t),n);class q extends Error{constructor(n){super(n),this.name="ValidationError",this.message=n}}const v=t=>{if(!t||t.length<6)throw new q("The blurhash string must be at least 6 characters");const n=u(t[0]),o=Math.floor(n/9)+1,e=n%9+1;if(t.length!==4+2*e*o)throw new q(\`blurhash length mismatch: length is \${t.length} but it should be \${4+2*e*o}\`)},A=t=>{const n=t>>16,o=t>>8&255,e=t&255;return[D(n),D(o),D(e)]},T=(t,n)=>{const o=Math.floor(t/361),e=Math.floor(t/19)%19,c=t%19;return[p((o-9)/9,2)*n,p((e-9)/9,2)*n,p((c-9)/9,2)*n]},V=(t,n,o,e)=>{v(t),e=e|1;const c=u(t[0]),i=Math.floor(c/9)+1,l=c%9+1,h=(u(t[1])+1)/166,r=new Array(l*i);for(let s=0;s<r.length;s++)if(s===0){const a=u(t.substring(2,6));r[s]=A(a)}else{const a=u(t.substring(4+s*2,6+s*2));r[s]=T(a,h*e)}const d=n*4,g=new Uint8ClampedArray(d*o);for(let s=0;s<o;s++)for(let a=0;a<n;a++){let B=0,E=0,R=0;for(let M=0;M<i;M++)for(let f=0;f<l;f++){const w=Math.cos(Math.PI*a*f/n)*Math.cos(Math.PI*s*M/o);let x=r[f+M*l];B+=x[0]*w,E+=x[1]*w,R+=x[2]*w}let C=b(B),G=b(E),y=b(R);g[4*a+0+s*d]=C,g[4*a+1+s*d]=G,g[4*a+2+s*d]=y,g[4*a+3+s*d]=255}return g};var $=V;addEventListener("message",t=>{console.log(t);const{canvas:n,width:o,height:e,blurhash:c}=t.data;console.log("Encoding",c);const i=+new Date,l=$(c,o,e),m=n.getContext("2d"),h=m.createImageData(o,e);h.data.set(l),m.putImageData(h,0,0);const r=+new Date;console.log("Done Encoding",c,r-i)}); })();` },
10
+ }),
11
+ createElement("script", {
12
+ dangerouslySetInnerHTML: { __html: `(() => { "use strict";const T=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","#","$","%","*","+",",","-",".",":",";","=","?","@","[","]","^","_","{","|","}","~"],u=e=>{let t=0;for(let o=0;o<e.length;o++){const s=e[o],r=T.indexOf(s);t=t*83+r}return t},p=e=>{let t=e/255;return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)},M=e=>{let t=Math.max(0,Math.min(1,e));return t<=.0031308?Math.round(t*12.92*255+.5):Math.round((1.055*Math.pow(t,.4166666666666667)-.055)*255+.5)},A=e=>e<0?-1:1,v=(e,t)=>A(e)*Math.pow(Math.abs(e),t);class L extends Error{constructor(t){super(t),this.name="ValidationError",this.message=t}}const D=e=>{if(!e||e.length<6)throw new L("The blurhash string must be at least 6 characters");const t=u(e[0]),o=Math.floor(t/9)+1,s=t%9+1;if(e.length!==4+2*s*o)throw new L(\`blurhash length mismatch: length is \${e.length} but it should be \${4+2*s*o}\`)},O=e=>{const t=e>>16,o=e>>8&255,s=e&255;return[p(t),p(o),p(s)]},P=(e,t)=>{const o=Math.floor(e/361),s=Math.floor(e/19)%19,r=e%19;return[v((o-9)/9,2)*t,v((s-9)/9,2)*t,v((r-9)/9,2)*t]},E=(e,t,o,s)=>{D(e),s=s|1;const r=u(e[0]),a=Math.floor(r/9)+1,c=r%9+1,g=(u(e[1])+1)/166,l=new Array(c*a);for(let n=0;n<l.length;n++)if(n===0){const i=u(e.substring(2,6));l[n]=O(i)}else{const i=u(e.substring(4+n*2,6+n*2));l[n]=P(i,g*s)}const h=t*4,d=new Uint8ClampedArray(h*o);for(let n=0;n<o;n++)for(let i=0;i<t;i++){let y=0,C=0,k=0;for(let m=0;m<a;m++)for(let f=0;f<c;f++){const w=Math.cos(Math.PI*i*f/t)*Math.cos(Math.PI*n*m/o);let b=l[f+m*c];y+=b[0]*w,C+=b[1]*w,k+=b[2]*w}let B=M(y),R=M(C),q=M(k);d[4*i+0+n*h]=B,d[4*i+1+n*h]=R,d[4*i+2+n*h]=q,d[4*i+3+n*h]=255}return d};var I=E;class S extends HTMLElement{sd;mo;static observedAttributes=["preview"];#s=!1;get#t(){return this.querySelector("img")}get#e(){return this.querySelector("canvas")}constructor(){super(),this.sd=this.attachShadow({mode:"open"}),this.sd.innerHTML='<slot name="preview"></slot>'}#o=()=>{if(this.#t&&this.#e)return this.mo?.disconnect(),console.log("checkready",this.#t.complete),setInterval(()=>{console.log("checkready interval",this.#t.complete)},100),this.#t.complete?this.#n():(this.#r(),this.#t.addEventListener("load",this.#n)),1};connectedCallback(){this.#s=!0,this.#o()||(this.mo=new MutationObserver(this.#o),this.mo.observe(this,{subtree:!0,childList:!0,attributes:!1}))}#n=()=>{console.log("imgLoad - should work",this.#t.complete),this.sd.innerHTML='<slot name="image"></slot>'};attributeChangedCallback(t){this.#e&&t==="preview"&&this.#r()}#r(){if(!this.#s||!this.getAttribute("preview"))return;const t=JSON.parse(this.getAttribute("preview"));H(this.hasAttribute("sync"),this.#e,t)}}customElements.get("blurhash-image")||customElements.define("blurhash-image",S);const G=new Blob([document.querySelector("#next-blurhash-worker-script").textContent],{type:"text/javascript"}),j=new Worker(window.URL.createObjectURL(G));function H(e,t,o){const{w:s,h:r,blurhash:a}=o;if(t.width=s,t.height=r,e){const c=+new Date,x=I(a,s,r),g=t.getContext("2d"),l=g.createImageData(s,r);l.data.set(x),g.putImageData(l,0,0);const h=+new Date;console.log("Done Encoding Sync",a,h-c)}else if(t.transferControlToOffscreen){const c=t.transferControlToOffscreen();j.postMessage({canvas:c,width:s,height:r,blurhash:a},[c])}} })();` },
13
+ })
14
+ );
package/index.js CHANGED
@@ -1,3 +1,4 @@
1
- import { imagePreviewBootstrap } from "./imagePreviewBootstrap";
1
+ import { imagePreviewBootstrap } from "./imagePreviewBootstrap.js";
2
+ import { NextWrapper } from "./components/NextWrapper.js";
2
3
 
3
- export { imagePreviewBootstrap };
4
+ export { imagePreviewBootstrap, NextWrapper };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-blurhash-previews",
3
- "version": "0.0.3-beta8",
3
+ "version": "0.0.4-beta2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "scripts": {
11
11
  "test": "echo \"Error: no test specified\" && exit 1",
12
- "build": "vite build",
12
+ "build": "rm -rf build && vite build --config vite.wc.config.ts && vite build --config vite.worker.config.ts && node util/setBootstrap.js",
13
13
  "build-watch": "vite build -w",
14
14
  "prepare": "npm run build"
15
15
  },
@@ -24,7 +24,7 @@
24
24
  "url": "https://github.com/arackaf/next-static-image-previews/issues"
25
25
  },
26
26
  "homepage": "https://github.com/arackaf/next-static-image-previews#readme",
27
- "dependencies": {
27
+ "devDependencies": {
28
28
  "@types/react": "^18.0.15",
29
29
  "@types/react-dom": "^18.0.6",
30
30
  "@vitejs/plugin-react": "^1.3.2",
@@ -32,9 +32,10 @@
32
32
  "colors": "^1.4.0",
33
33
  "glob": "^8.0.3",
34
34
  "install": "^0.13.0",
35
- "next": "^12.2.0",
36
35
  "node-fetch": "^3.2.6",
37
36
  "npm": "^8.15.1",
37
+ "react": "^18.2.0",
38
+ "react-dom": "^18.2.0",
38
39
  "remark": "^14.0.2",
39
40
  "remark-frontmatter": "^4.0.1",
40
41
  "retext": "^8.1.0",
@@ -1,22 +1,21 @@
1
1
  import fs from "fs";
2
2
 
3
- export default function writeBootstrapScript() {
4
- return {
5
- name: "write-bootstrap-script",
6
- closeBundle() {
7
- let BootstrapModule = fs.readFileSync(
8
- "./components/imagePreviewBootstrap.tsx",
9
- "utf8"
10
- );
11
- const bootstrapScript = fs.readFileSync(
12
- "./build/imageWithPreview.js",
13
- "utf8"
14
- );
15
- BootstrapModule = BootstrapModule.replace(
16
- "/*HERE*/",
17
- bootstrapScript.replace(/[\r\n]\s*$/, "").replace(/`/g, "\\`")
18
- ).replace(/\${/g, "\\${");
19
- fs.writeFileSync("./imagePreviewBootstrap.js", BootstrapModule);
20
- },
21
- };
22
- }
3
+ let BootstrapModule = fs.readFileSync(
4
+ "./components/imagePreviewBootstrap.tsx",
5
+ "utf8"
6
+ );
7
+
8
+ const wcScript = fs.readFileSync("./build/imageWithPreview.js", "utf8");
9
+ const workerScript = fs.readFileSync("./build/workerScript.js", "utf8");
10
+
11
+ BootstrapModule = BootstrapModule.replace(
12
+ "/*WC*/",
13
+ wcScript.replace(/[\r\n]\s*$/, "").replace(/`/g, "\\`")
14
+ )
15
+ .replace(
16
+ "/*WORKER*/",
17
+ workerScript.replace(/[\r\n]\s*$/, "").replace(/`/g, "\\`")
18
+ )
19
+ .replace(/\${/g, "\\${");
20
+
21
+ fs.writeFileSync("./imagePreviewBootstrap.js", BootstrapModule);
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ build: {
6
+ target: "es2022",
7
+ outDir: "./build",
8
+ emptyOutDir: false,
9
+ lib: {
10
+ entry: "components/NextWrapper.tsx",
11
+ formats: ["es"],
12
+ fileName: () => "NextWrapper.js",
13
+ name: "NextWrapper",
14
+ },
15
+ //minify: false,
16
+ },
17
+ plugins: [react()],
18
+ });
@@ -1,21 +1,18 @@
1
1
  import { defineConfig } from "vite";
2
2
  import react from "@vitejs/plugin-react";
3
- import writeBootstrapPlugin from "./util/setBootstrap";
4
3
 
5
4
  export default defineConfig({
6
5
  build: {
7
6
  target: "es2022",
8
7
  outDir: "./build",
8
+ emptyOutDir: false,
9
9
  lib: {
10
- entry: "components/imageWithPreview.tsx",
10
+ entry: "components/ImageWithPreview.tsx",
11
11
  formats: ["cjs"],
12
12
  fileName: () => "imageWithPreview.js",
13
13
  name: "imageWithPreview",
14
14
  },
15
15
  //minify: false,
16
- rollupOptions: {
17
- external: ["react", "react-dom", "next", "next/script"],
18
- },
19
16
  },
20
- plugins: [react(), writeBootstrapPlugin()],
17
+ plugins: [react()],
21
18
  });
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ build: {
6
+ target: "es2022",
7
+ outDir: "./build",
8
+ emptyOutDir: false,
9
+ lib: {
10
+ entry: "components/workerScript.ts",
11
+ formats: ["cjs"],
12
+ fileName: () => "workerScript.js",
13
+ name: "workerScript",
14
+ },
15
+ //minify: false,
16
+ },
17
+ plugins: [react()],
18
+ });
package/.prettierrc DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "arrowParens": "avoid"
3
- }
@@ -1,27 +0,0 @@
1
- import React, { useEffect, useRef } from "react";
2
-
3
- declare global {
4
- namespace JSX {
5
- interface IntrinsicElements {
6
- ["blurhash-image"]: any;
7
- }
8
- }
9
- }
10
-
11
- export const ImageWithPreview = (props: any) => {
12
- const wcRef = useRef<any>(null);
13
-
14
- const { preview } = props;
15
- const { w, h } = JSON.parse(preview);
16
-
17
- useEffect(() => {
18
- wcRef.current.activate();
19
- }, []);
20
-
21
- return (
22
- <blurhash-image ref={wcRef} {...props}>
23
- <img style={{ display: "none" }} />
24
- <canvas width={w} height={h}></canvas>
25
- </blurhash-image>
26
- );
27
- };
package/img1.png DELETED
Binary file
package/img5.png DELETED
Binary file
package/junk.js DELETED
@@ -1 +0,0 @@
1
- "use strict";var B=Object.defineProperty;var T=(t,e,s)=>e in t?B(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var a=(t,e,s)=>(T(t,typeof e!="symbol"?e+"":e,s),s);const k=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","#","$","%","*","+",",","-",".",":",";","=","?","@","[","]","^","_","{","|","}","~"],h=t=>{let e=0;for(let s=0;s<t.length;s++){const n=t[s],o=k.indexOf(n);e=e*83+o}return e},p=t=>{let e=t/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)},b=t=>{let e=Math.max(0,Math.min(1,t));return e<=.0031308?Math.round(e*12.92*255+.5):Math.round((1.055*Math.pow(e,.4166666666666667)-.055)*255+.5)},A=t=>t<0?-1:1,v=(t,e)=>A(t)*Math.pow(Math.abs(t),e);class C extends Error{constructor(e){super(e),this.name="ValidationError",this.message=e}}const G=t=>{if(!t||t.length<6)throw new C("The blurhash string must be at least 6 characters");const e=h(t[0]),s=Math.floor(e/9)+1,n=e%9+1;if(t.length!==4+2*n*s)throw new C(\`blurhash length mismatch: length is \${t.length} but it should be \${4+2*n*s}\`)},V=t=>{const e=t>>16,s=t>>8&255,n=t&255;return[p(e),p(s),p(n)]},D=(t,e)=>{const s=Math.floor(t/361),n=Math.floor(t/19)%19,o=t%19;return[v((s-9)/9,2)*e,v((n-9)/9,2)*e,v((o-9)/9,2)*e]},H=(t,e,s,n)=>{G(t),n=n|1;const o=h(t[0]),c=Math.floor(o/9)+1,l=o%9+1,x=(h(t[1])+1)/166,g=new Array(l*c);for(let r=0;r<g.length;r++)if(r===0){const i=h(t.substring(2,6));g[r]=V(i)}else{const i=h(t.substring(4+r*2,6+r*2));g[r]=D(i,x*n)}const d=e*4,u=new Uint8ClampedArray(d*s);for(let r=0;r<s;r++)for(let i=0;i<e;i++){let y=0,E=0,I=0;for(let m=0;m<c;m++)for(let f=0;f<l;f++){const w=Math.cos(Math.PI*i*f/e)*Math.cos(Math.PI*r*m/s);let M=g[f+m*l];y+=M[0]*w,E+=M[1]*w,I+=M[2]*w}let L=b(y),P=b(E),q=b(I);u[4*i+0+r*d]=L,u[4*i+1+r*d]=P,u[4*i+2+r*d]=q,u[4*i+3+r*d]=255}return u};class R extends HTMLElement{constructor(){super();a(this,"isReady",!1);a(this,"loaded",!1);a(this,"sd");a(this,"mo");a(this,"checkReady",()=>{this.currentImageEl&&this.currentCanvasEl&&(this.ready(),this.mo.disconnect())});a(this,"onImageLoad",()=>{this.getAttribute("url")!==this.currentImageEl.src&&setTimeout(()=>{this.loaded=!0,this.render()},1500)});this.sd=this.attachShadow({mode:"open"}),this.sd.innerHTML='<slot name="preview"></slot>'}get currentImageEl(){return this.querySelector("img")}get currentCanvasEl(){return this.querySelector("canvas")}connectedCallback(){this.mo=new MutationObserver(this.checkReady),this.mo.observe(this,{subtree:!0,childList:!0,attributes:!1})}ready(){this.isReady=!0,this.currentImageEl.complete&&this.onImageLoad(),this.currentImageEl.addEventListener("load",this.onImageLoad),this.loaded||this.updatePreview()}attributeChangedCallback(s,n,o){!this.isReady||(s==="preview"?this.updatePreview():s==="url"&&(this.loaded=!1),this.render())}updatePreview(){const s=JSON.parse(this.getAttribute("preview"));O(this.currentCanvasEl,s)}render(){this.sd.innerHTML=\`<slot name="\${this.loaded?"image":"preview"}"></slot>\`}}a(R,"observedAttributes",["preview","url"]);customElements.get("uikit-image")||customElements.define("uikit-image",R);function O(t,e){const{w:s,h:n}=e;t.width=s,t.height=n;const o=H(e.blurhash,s,n),c=t.getContext("2d"),l=c.createImageData(s,n);l.data.set(o),c.putImageData(l,0,0)}
@@ -1,3 +0,0 @@
1
- {
2
- "extends": "next/core-web-vitals"
3
- }
@@ -1,34 +0,0 @@
1
- This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2
-
3
- ## Getting Started
4
-
5
- First, run the development server:
6
-
7
- ```bash
8
- npm run dev
9
- # or
10
- yarn dev
11
- ```
12
-
13
- Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14
-
15
- You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16
-
17
- [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18
-
19
- The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20
-
21
- ## Learn More
22
-
23
- To learn more about Next.js, take a look at the following resources:
24
-
25
- - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26
- - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27
-
28
- You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29
-
30
- ## Deploy on Vercel
31
-
32
- The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33
-
34
- Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.