PDFKit Can't load image in browser - javascript

I'm working with PDFKit to generate a PDF in the browser, and then send the blob data of that PDF to a new tab for the user to download. I really like PDFKit...it's pretty slick.
However, I'm running into an issue when I try and use the PDFDocument.image() function to "draw" an image file:
Uncaught TypeError: fs.readFileSync is not a function
I'm pretty familiar with Node, and so I recognized that method signature immediately - the browser doesn't have fs natively! I'm less familiar with Browserify, and opted to instead use the pre-built version of PDFKit to avoid having to integrate another dependency that I'm not even familiar with.
My only guess is that the developers of PDFKit haven't included a working fallback for using this particular feature in the browser without Browserify - would using Browserify even give me access to the fs module (again, never used it)? Is that my only option here? Am I missing a particular step required to get this feature working?
Currently I'm including the following JS files as dependencies for my generate_pdf.js file:
pdfkit.js
blob-stream.js
Is there a module that emulates fs that I also need? I'm not seeing that documented, but it's been a long day.

Well, there are some libraries (like this or this), but I would highly recommend to write your own fs.readFileSync.
Since you're not likely to access client's filesystem from the browser anyway, using some existing solution would imply adding an abstraction level, etc.
So, probably the simplest and the easiest solution would be to add
var fs = {
readFileSync: (path) => {
// magic
}
}
Why probably? Well...
If there are usages of many fs functions, you'd obviously want to do it with some library
Synchronous requests. I guess you're loading images from some url, so you'll have to use synchronous requests in the implementation of fs.readFileSync to achieve the desired result. It's not like a big deal, but you'll get warnings in console.
P.S. sorry, but there's a hight probability that you'll face more issues with that because it's much more common to create pdfs on the server-side. Wy not move to the backend? ;)

Related

Managing configs for client-side npm modules - is there a preferred/standard way to go about this?

My primary question is whether or not the 'config' should be in a separate JSON/rc format, or if a general withCustomConfig-like function makes more sense. I realize this may be a matter of opinion, but I'm interested in hearing what more experienced developers think, as my searches for more information on this topic are coming up completely empty and I'm sure there's a preferred/standard way of handling something like this.
Essentially, I'm building an npm package for the generation/parsing of markdown for a specific use-case. The package allows for custom configurations to the characters utilized in the structure of the markdown itself. Originally, I was just intending on having users apply changes to the config via a simple withCustomConfig function (that accepts a config object); however, I started wondering if setting it via a JS function was not ideal - as the config's state then generally appears to seem more transient/loosely-defined than a completely separate rc or JSON config. I realize that is a matter of perception, but I think many people would share the same sentiment. And this poses a large risk because any changes to the configuration post-production would result in existing markdown becoming unparseable.
So, I started looking into having users configure a separate JSON config file. In order to import that into the browser, I realized I'd have to parse the JSON and convert it into a JS module before the user builds their client side application, which was relatively easy thanks to packages like fs. I set-up a small CLI utility to regenerate the JS module and added a postinstall script which parses the config file.
Then I started wondering if I was over-engineering this library, considering it's bound to be a relatively small aspect in its users' application. I started wondering if it even really warranted a completely separate config file and all the logic associated with parsing that for the browser. In general, would a simple withCustomConfig function actually be preferred/more-standard, or would an rc file be preferred by most people in this use case?

bundling a small task to make all dependencies available in puppeteer?

I have been personally using puppeteer for a lot of deployment and UI testing tasks.
But the issue I face now is that the more supporting code I have the harder to make it available directly in the browser.
What I usually do is that I place all the code I will use in the browser in a single file, encode the whole module as text, make it available to the browser and use a dynamic import in the browser. You see where I am getting, hopefully...
If I try to add 3rd party libs then this whole setup falls apart because I can't make all dependencies available in a single file.
Question is: Anyone has used any patterns for that? Is bundling an option here? any examples? Thanks a lot...
as I suggested in my inquiry above, one solution for external packages is to load them in through a CDN.
So
var scriptElm = document.createElement('script');
scriptElm.src = 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js';
document.body.appendChild(scriptElm);
You'd have to ensure that it is properly loaded before trying to use it, but that should be easy enough.
EDIT:
If I am using CDN's I might just as well import them directly to the consumer file ex:
import lodash from 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js';

How to postpone code evaluation in browser?

I am developing pretty big SPA (final ~30MB) and unfortunately one of requirements is that an app has to be released as one big html file. I use webpack to connect all pieces together.
Currently I am facing a problem with performance (some libraries are quite big ones). They "eat" a lot of ram and affects loading time due to code evaluation in browser. I would like to postpone it and evalute only these modules which are necessary at main screen of app.
My idea is to use the same mechanism like webpack does for sourcemaps:
https://webpack.js.org/configuration/devtool/ (eval-source-map)
Webpack simply puts code within eval("code of module") which prevents automatic evaluation by Javascript engine. Of course this code can't be minified and there is also sourcemap attached as base64 to the end. I would like to do same without sourcemaps and including uglification. Moreover I have an idea to reduce size of application by compressing sources so eventually it would be eval(gz.decompress("code of module")).
It will be a huge change in application so before I am going to reinvent a wheel I would like to ask you:
Does it make sense from problem point of view?
Do you know any existing solutions?
Do you suggest to use any existing components from webpack like:
https://webpack.github.io/docs/code-splitting.html
or write own solution from scratch (loader/plugin).
Don't do that what you want!
If you do want to find a weird trick to get what you want, try including your big JS file dynamically. See here or google jquery getscript. No additional Webpack actions required.
If not, please, continue reading.
You're dealing with the problem from the wrong perspective.
First, make sure you are doing all the obvious HTML/HTTP stuff:
You're downloading the gzip-ed version of the file (if not, google http script gzip)
You're including the <script> tag at the end of the body. This will start downloading and parsing JS only after HTML has been rendered.
Then, the most important, try to figure out where is the 30MB coming from. It's unlikely a fair sum of all your big fat dependencies. Usually, it's a particular bloated library (or two). Make sure you use got instead of request because the least is bloated. Find alternatives for the out-sized dependencies.
No single SPA in the world should have a 30MB JS bundle. I'm assuming your project isn't very large because otherwise it would be business critical and you would invest into providing a decent back-end strategy (e.g. code splitting, dead code elimination, etc.).
1) The similar problem can be solved with Webpack code splitting functionality.
The idea is that you don't load route specific code and libraries until the user accesses the specific page.
2) Take a look at this: script-ext-html-webpack-plugin, looks very promising to do these kinds things. For example, defer options would be for modules or scripts that you want to delay the execution. Async would be for scripts that you want to execute as HTML gets executed. Be careful though about race conditions.
3) You mentioned that you use libraries that are so big, make sure you use Webpack with tree shaking. If you use the old Webpack (version 1.*) which does not have tree shaking, you should try to optimize imports manually. For example, instead of import _ from 'lodash' it would be import map from 'lodash/map'.
4) You also mentioned that it is the ram that is the problem, so how compression can help ram? compression can help the browser to retrieve it faster.
5) The other idea would be:
Load the scripts that you need for the home page
execute them. at this point, the user sees the functioning page
then behind the scenes load other scripts slowly without the user to notice it.
evaluate loaded code as it will become needed for the user.

running javascript plugins in node

I'm not sure if this is possible without some serious tweaking but is it possible to run javascript plugins server side with node...
more specifically
I would like to run the dymo javascript sdk from node (the printer is attached to the server)
that way any device can print from the server.
I have tried using https://github.com/tojocky/node-printer as a workaround however it doesnt work in my situation (works with my laserjet though)
I have tried just requiring the file that failed miserably.
if this is possible can you just point me in the right direction I have been searching the google and even been corresponding with dymo developers however I havent gotten much help from them.
so the simplest way to put it: Can you run clientside javascript plugins from server side? if not is there a way to write a middleware that will act as a bridge?
here is the plugin file(before I modify it more): http://irwinproject.com/jss/Dymo.js
its a bunch of craziness. I am trying to modify it to work as a module
UPDATE: I have gotten most of the functions running properly however I have hit a bit of a snag their sdk requires active x which I dont understand because I'm on a mac and it works
can someone explain to me how active x can function client side on a mac? (i thought that was windows only) and also is there anyway to implement the same framework(activex or other) through node
if I understand this correctly active x is used as an abstraction layer between javascript and hardware
You have to return your object or functions with module.exports, also try to verify you are requiring your file with . so node knows is a local module.
Check this SO post with a highly upvoted answer :
What is the purpose of Node.js module.exports and how do you use it?
module.exports is the object that's actually returned as the result of
a require call.
The exports variable is initially set to that same object (i.e. it's a
shorthand "alias"), so in the module code you would usually write
something like this....

YUICompressor or similar in PHP?

I've been using yuicompressor.jar on my test server for on-the-fly minimisation of changed JavaScript files. Now that I have deployed the website to the public server, I noticed that the server's policies forbid the use of exec() or its equivalents, so no more java execution for me.
Is there a decent on-the-fly JS compressor implemented in PHP? The only thing resembling this that I was able to find was Minify, but it's more of a full-blown compression solution with cache and everything. I want to keep the files separate and have the minimised files follow my own naming conventions, so Minify is a bit too complex for this purpose.
The tool, like yuicompressor, should be able to take either a filename or JavaScript as input and should either write to a file or output the compressed JavaScript.
EDIT: To clarify, I'm looking for something that does not have to be used as a standalone (i.e. it can be called from a function, rather than sniffing my GET variables). If I just wanted a compressor, Minify would obviously be a good choice.
EDIT2: A lot has changed in the five years since I asked this question. Today I would strongly recommend separating the front-end workflow from the server code. There are plenty of good tools for JS development around and except for the most trivial jQuery enhancements it's a better idea to have a full workflow with automated bundling, testing and linting in place and just deploy the minified bundles rather than the raw files.
Yes there is, it's called minify.
The only thing in to worry about in the way of complexity is setting up a group, and there's really nothing to it. Edit the groupsConfig.php file if you want multiple JS/CSS in one <script> or <link> statement:
return array(
'js-common' => array('//js/jquery/jquery-1.3.2.min.js', '//js/common.js', '//js/visuals.js',
'//js/jquery/facebox.js'),
'css-common' => array('//css/main.css', '//css/layout.css','//css/facebox.css')
);
To include the above 'js-common' group, do this:
<script type="text/javascript" src="/min/g=js-common"></script>
(i know i was looking for the exact same thing not knowing how to deal directly with the jar file using php - that's how i ended up here so i'm sharing what i found)
Minify is a huge library with tons of functionalities. However the minifying part is a very tiny class : http://code.google.com/p/minify/source/browse/trunk/min/lib/Minify/YUICompressor.php
& very very easy to use :
//set the path to the jar file
Minify_YUIcompressor::$jarFile=_ROOT.'libs/java/yuicompressor.jar';
//set the path to a writable temp folder
Minify_YUIcompressor::$tempDir=_ROOT.'temp/';
//minify
$yourcssminified=Minify_YUIcompressor::minifyCss($yourcssstringnotminified,$youroptions)
same process for js, if you need more functionalities just pick from the library & read the source to see how you can make direct call from your app.
I didn't read the question well, since minify is based on using the jar files, the op can't use it anyway with his server config
Minify also include other minifying methods than yui, for example:
http://code.google.com/p/minify/source/browse/trunk/min/lib/JSMinPlus.php?r=443&spec=svn468
Try Lissa:
Lissa is a generic CSS and JavaScript loading utility. Lissa is an extension of the YUI PHP Loader aimed at solving one of the current loader limitations; combo loading. YUI PHP Loader ships with a combo loader that is capable of reducing HTTP requests and increasing performance by outputting all the YUI JavaScript and/or CSS requirements as a single request per resource type. Meaning even if you needed 8 YUI components which ultimately boil down to say 13 files you would still only make 2 HTTP requests; one for the CSS and another for the JavaScript. That's great, but what about custom non-YUI resources. YUI PHP Loader will load them, but it loads them as separate includes and thus they miss out on benefits of the combo service and the number of HTTP requests for the page increases. Lissa works around this limitation by using the YUI PHP Loader to handle the loading and sort of YUI and/or custom resource dependencies and pairs that functional with Minify.

Categories