Webpack Loaders - create and write files inside loader - javascript

Pretty much what the title suggests. I want to create a metadata file alongside every javascript file in my project. So I need a webpack loader that doesn't change the content at all, and just extracts some metadata and writes it to a file. What's the best way to do this? fs.writeFileSync seems to work fine, but I don't know if I should use it since it seems like some webpack guides recommend using something called memory-fs, webpack's in-memory filesystem.

So this took a while to find and seems rarely mentioned, but webpack loaders actually have a method this.emitFile specifically for this purpose. Here is some example usage:
function extractMeta(content) {
// extract and return metadata for file
}
module.exports = function(content) {
console.log('extracting metadata and writing to file');
// get source filename, strip file extension and append ".meta"
const filename = this.resourcePath.split('/').pop().split('.')[0] + '.meta'
this.emitFile(filename, extractMeta(content));
return content; // return the source file unchanged
};

Related

How to hook file requests from javascript in Electron to produce the correct path?

I'm creating an Electron app and in the process am trying to use some existing javascript and other files (css and other resources). My code is spread out across a number of packages, each package containing various of these files. Outside of Electron these files would be served from a server which provides a mapping from a flat list of files to the paths to each of these files and I am trying to implement similar "server-side" functionality in Electron's "back end", if there is such a thing.
Since Electron is getting these files from the file:// protocol it is not finding most of these files because everything is resolving relative to the path of the current javascript file and these files do not know about each other and thus cannot specify a hard-coded path.
Is there some mechanism in Electron to hook requests for files so that I can provide the path for it to look at? In my server-side code I do something where I have an object which maps file names to the paths they are in, and I feel like the solution would similarly be to intercept requests and tell Electron where to look for each file.
I found this question but the solution offered there won't work for me because my web app is a bit too dynamic and the requests are coming from deep in the code, not some user interface element I could trap.
You can accomplish this by intercepting the file protocol handler. If you have set up your file mappings into an object like so:
files = {
"file1.js": "/path/to/file1.js",
"file2.js": "/path/to/file2.js",
// etc.
}
Then in the createWindow function you will insert this code immediately after you instantiate the new BrowserWindow:
protocol.interceptFileProtocol("file", (req, cb) => {
var file = req.url.split("/")
file = file[file.length-1]
if (files[file]) {
console.log(`intercepting ${file} => ${files[file]}`)
cb({path:files[file]})
}
})
Note: The protocol references a const that you get from requiring electron, e.g. something like this:
const {app, BrowserWindow, protocol} = require("electron")
This code assumes that the file names are unique and are the only part of the path that matters. So for instance, not matter what path the code thinks "file1.js" is in, in the above example it will be redirected to /path/to/file1.js. If the requested file doesn't exist then the behavior is undefined and probably nothing will load.

node - Parse iptc data from image buffer

Trying to find a way to extract IPTC data from an image file buffer, there are existing libraries available on npm that allow you to open and read a file from the local filesystem but i am storing files on AWS S3 and would prefer to use buffers instead of creating unnecessary disk writes.
Not sure where to start, maybe start looking through how this module works:
https://www.npmjs.com/package/extract-iptc
And create my own module? Or is there an easier way that i've missed?
I was able to extract IPTC data by using
var iptc = require('node-iptc');
var iptc_data = iptc(imageData);
Also there's an isomorphic library exifr that works in both Node.js and browser. And it works with the new HEIC image format as well.
exifr.parse(input, {iptc: true}).then(output => {
console.log('IPTC', output)
})
It parses multiple formats (TIFF/EXIF, ICC, IPTC, XMP, JFIF) but IPTC isn't enabled by default so you need to enabled it in options as seen in the example.

How to load external configuration files in NodeJS dynamically

In a NodeJS application I would like to load configuration data (reports to be generated) from external files dynamically. I can load them statically by using require('path/config');
But I do have parts of the configuration that need to be refreshed on a regular schedule and, to make it all more complicated, these configuration files contain a function that must be executable.
One such report looks as follows:
const report = {
name : 'Report 3',
description : 'Very simple report.',
// Some properties
preprocessor : function() {
},
// Some more properties
};
module.exports = report;
When using require to re-load the report it is basically not reloaded. Even if I change something, it stays the same. (Reason: require() uses caching and rightfully it does.)
What is a good way (maybe an external library) to re-load external configuration files that contain executable functions?
I would use fs. If you have complete control over the configuration files (otherwise it's dangerous) you can use eval.
var fs = require('fs');
var file = fs.readFileSync(filename);
var module = {}
eval(file);
// You can access report in module.exports
If you don't want to block your application (usually recommended) you should use the async version and provide callbacks.
To circument caching problems, I now use the library require-without-cache. Seems to do the job.

How to read content from a file stored locally in javascript?

Windows 8 app development requires a file access and i'm using html with javascript. I read the msdn articles and other questions posted here. But every answer points to accessing file read via user input in html file. But I want to access the file contents like using java FileIO.
My operation would be requiring reading first line from a file into a variable...Kindly help me on this.
I'd assume the link posted in similar question (here https://stackoverflow.com/a/13131746/173100) helps. Just note that you can't read an arbitrary file from the file system, the allowed locations include the app's install location, app's local data folder and a bunch of predefined folders described in the linked MSDN article (http://msdn.microsoft.com/en-us/library/windows/apps/hh967755.aspx). Most likely you're interested in http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.storagefile.getfilefromapplicationuriasync.aspx .
In practice, you could read the first line of the file foo.txt located in your app's install directory (= in your app's package) as follows:
Windows.Storage.StorageFile.getFileFromApplicationUriAsync("ms-appx:///foo.txt").done(
function(file) {
// Assuming file has content here, better error handling probably needed
var lines = file.split("\n");
var firstLine = lines[0];
// Do something with the firstLine variable
},
function(error) {
// Error occurred, handle it here
}
);

Drupal Filefield won't upload javascript files?

I've got a site where individual pages might require some javascript or CSS files hooked into their heads. I'm trying to keep everything client side when it comes to managing this process, rather than getting on the FTP and sorting everything out in the code so I need to be able to upload css and js files.
I've got CCK filefield up and running, and it works with css files, but it refuses to upload .js files. It instead seems to view every .js as ".js.txt" and then the file appears on the server as thisismyfile.js.txt
Not ideal...
Does anyone know how to work around this. Is it a mime type problem with Drupal or the server, or is Drupal set up to avoid script uploads and n00b hack attacks.
Once the files are uploaded I intend to use PHP mode on the page or node to call drupal_add_css and drupal_add_js.
Looking at the field_file_save_file() function in field_file.inc from filefield module, you can find the following snippet
// Rename potentially executable files, to help prevent exploits.
if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
$file->filemime = 'text/plain';
$file->filepath .= '.txt';
$file->filename .= '.txt';
}
So yes, it's a 'security thing', as Jeremy guessed.
You could patch that RegEx for an immediate 'fix', but that would remove this otherwise useful security check completely for all filefields used on the site.
So a more specific workaround might be a better approach. Since you want to add the files via drupal_add_js() calls from code anyways, you might as well do the renaming there, adding some kind of verification to make sure you can 'trust' the file (e.g. who uploaded it, whatever).
Edit: Concerning options to rename (and alternatives) when calling drupal_add_js():
For renaming the file, look into the file_move() function. A problem with this would be that it won't update the corresponding entry in the files table, so you would have to do that also, if the move operation succeeded. (The filefield just stores the 'fid' of the corresponding entry in the files table, so you'd need to find it there by 'fid' and change the 'filename', 'filepath' and 'filemime' entries according to your rename/move)
Alternatively, you could just load the content of the *.js.txt file and add that string with the 'inline' option of drupal_add_js(). This would be less 'elegant' and could be a performance hit, but if those are not important criteria in your specific case, it is less trouble.
Yet another option would be just passing the *.js.txt file as is to drupal_add_js(), ignoring the 'wrong' extension. A short local test showed that this works (at least in firefox). This might be the 'least effort' solution, but would need some additional testing concerning different browser behavior concerning usage of 'misnamed' js files.
Allowing Drupal to upload javascript files would be a security risk, which is also why it doesn't allow you to do it, but instead appends the .txt extension. The reason is that js files are executable along with php, pl, py, cgi, asp. So if Drupal could upload those files to the server, it would be possible for evil doers to upload a file and run it doing all kinds of nasty things on your server, basically anything is possible. Best thing would be to find a different way of uploading files which are secure.
I had a similar need, and found a way to get around the security by first changing the 'allow_insecure_uploads' variable value by running this line of code in your hook_install:
variable_set('allow_insecure_uploads', 1);
Then in a module add this function
/**
* Implementation of FileField's hook_file_insert().
*/
function MODULE_NAME_file_insert(&$file) {
//look for files with the extenstion .js.txt and rename them to just .js
if(substr($file->filename, -7) == '.js.txt'){
$file_path = $file->filepath;
$new_file_path = substr($file_path, 0, strlen($file_path)-4);
file_move($file_path, $new_file_path);
$file->filepath = $file_path;
$file->filename = substr($file->filename, 0, strlen($file->filename)-4);
$file->filemime = file_get_mimetype($file->filename);
$file->destination = $file->filepath;
$file->status = FILE_STATUS_TEMPORARY;
drupal_write_record('files', $file);
}
What this does is in the hook_insert call it checks if a file has the extension ".js.txt". If it does it copies it to a new location and renames it. This is after the security check so its ok. I don't think you need to worry about the cache clear deleting your js files as long as you don't put them in the files/js directory. Create your own directory for you module and you should be ok.
I faced this situation when I wanted to allow .js file to be upload as is (without .txt and with 'application/javascript' mimetype) for a specific field. Also, I didn't wanted to alter Drupal core... of course.
So I needed to create a module implementing hook_file_presave(). This also work for Multiupload File Widget, since its hook is on file_save().
Note that you would have to replace MYMODULE_NAME and MYFIELD_NAME by your own values.
function MYMODULE_NAME_file_presave($file) {
// Bypass secure file extension for .js for field_additional_js field only
if((isset($file->source) && strpos($file->source, "MYFIELD_NAME") !== FALSE) && substr($file->filename, strlen($file->filename) - 7) == ".js.txt") {
// Define new uri and save previous
$original_uri = $file->uri;
$new_uri = substr($file->destination, null, -4);
// Alter file object
$file->filemime = 'application/javascript';
$file->filename = substr($file->filename, null, -4);
$file->destination = file_destination($new_uri, FILE_EXISTS_RENAME);
$file->uri = $file->destination;
// Move fil (to remove .txt)
file_unmanaged_move($original_uri, $file->destination);
// Display message that says that
drupal_set_message(t('Security bypassed for .js for this specific field (%f).', array('%f' => $file->filename)));
}
}
Drupal also "munges" javascript files. To prevent Drupal from automatically adding underscores to the filename there is a hidden variable that is checked before the filename is "munged".
Setting the variable to 1 solves the issue for me (along with altering the REGEX in includes/file.inc).
I hate hacking core, but this seems like a poor design to me. Javascript files are not server side scripts like php, py, pl, cgi, and asp.
You can use the allowed file extensions settings to prevent php and other server side scripts from being uploaded.
eg:
variable_set('allow_insecure_uploads', 1);
See:
http://api.drupal.org/api/function/file_munge_filename/6
So uploading .js files to the files directory is pretty much impossible.
Even if you manage to get .js files uploaded cleanly, these files will get deleted when the cache is cleared.
Any js files that live inside the files directory will be deleted whenever the drupal_clear_js_cache() function is executed.
http://api.drupal.org/api/function/drupal_clear_js_cache/6
So Drupal sees .js files living in the file uploads directory as temporary.
Now I understand why they are appending ".txt", it is to prevent them from being removed when the cache is cleared.
So as a compromise I guess I will just be uploading .js files manually (via FTP) to the /misc folder. :(

Categories

Resources