Skip to content
This repository was archived by the owner on Mar 10, 2024. It is now read-only.

Commit 32a047a

Browse files
committed
perf: cleaning code
1 parent 5f1e629 commit 32a047a

File tree

9 files changed

+376
-341
lines changed

9 files changed

+376
-341
lines changed

nuxt.config.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export default {
2222

2323
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
2424
plugins: [
25+
{ src: "~/plugins/axios.js" },
26+
{ src: "~/plugins/utils.js" },
2527
{ src: "~/plugins/underscore.js", ssr: false },
2628
{ src: "~/plugins/code-editor.js", ssr: false, mode: "client" },
2729
],
@@ -30,7 +32,18 @@ export default {
3032
components: true,
3133

3234
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
33-
buildModules: ["@nuxtjs/tailwindcss", "@nuxtjs/google-fonts", "@nuxtjs/svg"],
35+
buildModules: [
36+
"@nuxtjs/tailwindcss",
37+
"@nuxtjs/google-fonts",
38+
"@nuxtjs/svg",
39+
[
40+
"nuxt-tailvue",
41+
{
42+
all: true,
43+
toast: { defaults: { containerClasses: ["top-auto", "bottom-0"] } },
44+
},
45+
],
46+
],
3447

3548
// Modules: https://go.nuxtjs.dev/config-modules
3649
modules: [

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@
1414
"@nuxtjs/google-fonts": "^2.0.0",
1515
"@nuxtjs/moment": "^1.6.1",
1616
"@nuxtjs/tailwindcss": "^4.2.1",
17+
"@zaengle/error-handler": "^1.0.2",
1718
"body-parser": "^1.20.0",
1819
"core-js": "^3.19.3",
19-
"cors": "^2.8.5",
2020
"date-fns": "^2.28.0",
2121
"dotenv": "^16.0.0",
2222
"express": "^4.17.3",
2323
"file-url": "^4.0.0",
2424
"filenamify": "^5.1.0",
2525
"filenamify-url": "^3.0.0",
26-
"got": "^12.1.0",
2726
"jszip": "^3.10.0",
2827
"lodash.template": "^4.5.0",
2928
"make-dir": "^3.1.0",
3029
"node-fetch": "^3.2.6",
3130
"nuxt": "^2.15.8",
3231
"nuxt-buefy": "^0.4.13",
32+
"nuxt-tailvue": "^1.0.95",
3333
"p-map": "^5.5.0",
3434
"puppeteer": "^14.4.1",
3535
"sass": "^1.49.7",

pages/index.vue

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@
463463

464464
<div class="flex items-center justify-end m-4 space-x-4">
465465
<b-button
466-
v-if="result.url"
466+
v-if="result && result.url"
467467
icon-left="download-outline"
468468
@click="download"
469469
type="is-success is-light"
@@ -491,7 +491,7 @@
491491

492492
<div class="h-full overflow-y-auto box bg-blueGray-900">
493493
<p class="title is-5">Website Screenshot</p>
494-
<div v-if="!result.url" class="mb-3">
494+
<div v-if="result == null" class="mb-3">
495495
<p class="title is-4">Capture a website screenshot online</p>
496496
<p class="mt-4 text-white subtitle is-6">
497497
Generate a full web-page screenshot with our service Site-Shot: Web
@@ -504,7 +504,7 @@
504504
<b-progress v-if="loading" type="is-info"></b-progress>
505505

506506
<embed
507-
v-if="result.url"
507+
v-if="result && result.url"
508508
:src="result.url"
509509
width="100%"
510510
style="height: 50vh"
@@ -569,10 +569,7 @@ export default {
569569
},
570570
imageFormats: ["png", "jpeg", "webp"],
571571
pdfFile: null,
572-
result: {
573-
url: null,
574-
filename: null,
575-
},
572+
result: null,
576573
loading: false,
577574
resolutions: [
578575
{
@@ -687,16 +684,9 @@ export default {
687684
mounted() {},
688685
methods: {
689686
async generateScreenshot() {
690-
if (
691-
this.selectedType == "multiple-imgs" ||
692-
!this.loading ||
693-
this.params.url !== null
694-
) {
687+
if (!this.loading) {
695688
this.loading = true;
696-
this.result = {
697-
url: null,
698-
filename: null,
699-
};
689+
this.result = null;
700690
this.pdfFile = null;
701691
const selectedType = this.selectedType;
702692
let mimeType = "";
@@ -708,40 +698,32 @@ export default {
708698
}
709699
710700
await this.$axios
711-
.post(
712-
"/api/screenshot",
713-
{
714-
...this.params,
715-
scale: this.params.scale / 100,
716-
size: [this.params.size],
717-
type: selectedType,
718-
mimeType,
719-
},
720-
{
721-
responseType: "blob",
722-
}
723-
)
724-
.then((response) => {
725-
let blob = new window.Blob([response.data], {
701+
.$post("/api/screenshot", {
702+
...this.params,
703+
scale: this.params.scale / 100,
704+
size: [this.params.size],
705+
type: selectedType,
706+
mimeType,
707+
})
708+
.then(({ base64, filename, success }) => {
709+
const blob = new window.Blob([this.convertBase64ToBlob(base64)], {
726710
type: mimeType,
727711
});
728712
729-
let headerLine = response.headers["content-disposition"];
730-
let startFileNameIndex = headerLine.indexOf('"') + 1;
731-
let endFileNameIndex = headerLine.lastIndexOf('"');
732-
let filename = headerLine.substring(
733-
startFileNameIndex,
734-
endFileNameIndex
735-
);
736-
737713
if (selectedType == "multiple-imgs") {
738-
const link = document.createElement("a");
739-
link.href = window.URL.createObjectURL(blob);
740-
link.download = filename;
741-
link.click();
714+
this.download({
715+
url: window.URL.createObjectURL(blob),
716+
filename: filename,
717+
});
742718
} else {
743-
this.result.url = window.URL.createObjectURL(blob);
744-
this.result.filename = filename;
719+
this.result = {
720+
url: window.URL.createObjectURL(blob),
721+
filename,
722+
};
723+
}
724+
725+
if (success) {
726+
this.$success("Screenshot generated successfully");
745727
}
746728
747729
this.loading = false;
@@ -752,11 +734,11 @@ export default {
752734
});
753735
}
754736
},
755-
download() {
756-
if (this.result) {
737+
download(result) {
738+
if (result || this.result) {
757739
const link = document.createElement("a");
758-
link.href = this.result.url;
759-
link.download = this.result.filename;
740+
link.href = result.url || this.result.url;
741+
link.download = result.filename || this.result.filename;
760742
link.click();
761743
}
762744
},
@@ -770,6 +752,27 @@ export default {
770752
urls.splice(index, 1);
771753
}
772754
},
755+
convertBase64ToBlob(base64Image) {
756+
// Split into two parts
757+
const parts = base64Image.split(";base64,");
758+
759+
// Hold the content type
760+
const imageType = parts[0].split(":")[1];
761+
762+
// Decode Base64 string
763+
const decodedData = window.atob(parts[1]);
764+
765+
// Create UNIT8ARRAY of size same as row data length
766+
const uInt8Array = new Uint8Array(decodedData.length);
767+
768+
// Insert all character code into uInt8Array
769+
for (let i = 0; i < decodedData.length; ++i) {
770+
uInt8Array[i] = decodedData.charCodeAt(i);
771+
}
772+
773+
// Return BLOB image after conversion
774+
return new Blob([uInt8Array], { type: imageType });
775+
},
773776
},
774777
watch: {
775778
"params.size"() {
@@ -784,6 +787,7 @@ export default {
784787
},
785788
selectedType() {
786789
this.params.url = null;
790+
this.result = null;
787791
this.params.urls = [
788792
{
789793
url: null,

plugins/axios.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import ErrorHandler from "@zaengle/error-handler";
2+
3+
export default ({ $axios, redirect, app }, inject) => {
4+
$axios.onError((error) => {
5+
const errorResponse = new ErrorHandler().setAll(error).parse();
6+
app.$error(
7+
error.response ? error.response.data.error : errorResponse.message
8+
);
9+
});
10+
};

plugins/utils.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export default ({ app }, inject) => {
2+
inject("error", (message) => {
3+
app.$toast.show({
4+
type: "danger",
5+
message,
6+
timeout: 5,
7+
progress: true,
8+
classToast: "bg-red-600",
9+
classTitle: "text-red-100",
10+
classMessage: "text-red-200 font-serif",
11+
classClose: "text-red-300",
12+
classTimeout: "bg-red-800",
13+
});
14+
});
15+
inject("success", (message) => {
16+
app.$toast.show({
17+
type: "success",
18+
message,
19+
timeout: 5,
20+
progress: true,
21+
classToast: "bg-green-600",
22+
classTitle: "text-green-100",
23+
classMessage: "text-green-200 font-serif",
24+
classClose: "text-green-300",
25+
classTimeout: "bg-green-800",
26+
});
27+
});
28+
};

server-middleware/utils.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
const fs = require("fs");
2+
const dateFns = require("date-fns");
3+
const path = require("path");
4+
5+
import { parse as parseUrl } from "url";
6+
import template from "lodash.template";
7+
import filenamifyUrl from "filenamify-url";
8+
import filenamify from "filenamify";
9+
import makeDir from "make-dir";
10+
11+
export function generateFilename(options, url) {
12+
let hash = parseUrl(url || options.url).hash ?? "";
13+
if (/^#!?\/?$/.test(hash)) {
14+
hash = "";
15+
}
16+
17+
const now = Date.now();
18+
const basename = fs.existsSync(url || options.url)
19+
? path.basename(url || options.url)
20+
: url || options.url;
21+
22+
const filenameTemplate = template(`${options.filename}.${options.format}`);
23+
let filename = filenameTemplate({
24+
crop: options.fullPage ? "" : "-cropped",
25+
date: dateFns.format(now, "yyyy-MM-dd"),
26+
time: dateFns.format(now, "HH-mm-ss"),
27+
size: options.size,
28+
width: options.width,
29+
height: options.height,
30+
url: `${filenamifyUrl(basename)}${filenamify(hash)}`,
31+
});
32+
33+
const filepath = path.join(__dirname + "/../screenshots", filename);
34+
35+
return {
36+
filepath,
37+
filename,
38+
};
39+
}
40+
41+
var CustomBufferBuilder = function () {
42+
this.parts = [];
43+
this.totalLength = 0;
44+
};
45+
46+
CustomBufferBuilder.prototype.append = function (part) {
47+
var tempBuffer = Buffer.from(part);
48+
this.parts.push(tempBuffer);
49+
this.totalLength += tempBuffer.length;
50+
this.buffer = undefined;
51+
};
52+
53+
CustomBufferBuilder.prototype.getBuffer = function () {
54+
if (!this.buffer) {
55+
this.buffer = Buffer.concat(this.parts, this.totalLength);
56+
}
57+
return this.buffer;
58+
};
59+
60+
export default CustomBufferBuilder;
61+
62+
export async function saveFile(save, filename, buffer, mimeType) {
63+
const filepath = path.join(__dirname + "/../screenshots", filename);
64+
if (save) {
65+
await makeDir(__dirname + "/../screenshots");
66+
await fs.writeFileSync(filepath, buffer);
67+
}
68+
69+
const base64 = buffer.toString("base64");
70+
const base64Image = `data:${mimeType};base64,${base64}`;
71+
72+
return {
73+
filename,
74+
filepath,
75+
mimeType,
76+
base64: base64Image,
77+
success: true,
78+
};
79+
}

0 commit comments

Comments
 (0)