Load file contents before any transformation - javascript

I'm trying to use Webpack with React to build a documentation site, and I'd like to be able to show the example code alongside the example. I'd rather do this dynamically so I never forget to sync up, but I'd rather it not be a separate step in the build process. Of course, I figured I couldn't do this at run-time with fs.readFile or something for a number of reasons (it would be browser-side and the file wouldn't exist anyways).
So I thought I'd try raw-loader. That gave me the post-babel result, which is... better than nothing, but I want the original source. raw-text-loader gave me the same thing. Is there anything I can do to get the original source code?
Is there anything I can do to get the t

Oh, maybe not the most intelligent thing, but I had to import using
import ExampleText from '!raw!./Example.js'
instead of
import ExampleText from 'raw!./Example.js'
Sorry if that was obvious. =)

Related

How does bad importing works in javascript

I have 3 Vue files, each with a script section. When I am importing the chance js library correctly, all the 3 scripts print a defined object for console.log(chance).
But when I do a bad import,
import {chance} from 'chance'; //<=this is not correct, but works for other files
instead of
import {Chance} from 'chance'; //<=this is the correct one
the first script prints undefined, and after, the second and the third script prints the same object printed previously.
Does anyone know how this works?
Reading some documentation with export and import may provide some answers.
For the rest, take the time to learn how JS works in this section.
In the end, there is no general answer to that question. It depends on how the library is written.

What to do when no export is needed in TypeScript file

I had a problem while making some demo files using TypeScript, each file is considered to run alone (no import or export needed).
The problem is that the files leaked to each other as they all went global (I'll appreciate if someone explains why this happened). I found a few ways to get rid of this as wrapping them in a module or a namespace, or even exporting an empty object.
What I need to know is the best practice that should be done in this situation? which solutions is considered the best? especially that I thought I can face the same situation if I have multiple files that are required for their side-effects only or something.
I had a problem while making some demo files using TypeScript
What I need to know is the best practice that should be done in this situation? which solutions is considered the best? especially that I thought I can face the same situation if I have multiple files that are required for their side-effects only or something.
The only time I've experienced it in my long career as well is with demo files. I had this when creating TypeScript deep dive so I would put in some junk at the top of the file e.g. see const
export var asdfasdfasfadf = 123;
Why its not a concern
You do not see it happening in real world code because you start you brain with module mind set. E.g.
In a file with zero dependencies you are normally thinking : What am I going to export
In a file where you are going to action something you are normally thinking: What will I need to import. As simple as import fs from 'fs' makes it a module 🌹

Execute NormalModule at build time, after it is built by loaders, then save to json file

I am coding a plugin that, for specific modules, will try to execute the module generated at build time in order to save the result to a json file.
For that, I am tapping into compilation.hooks.succeedModule, which receives a NormalModule object already built. Then I am trying to eval the source replacing webpack variables like __webpack_public_path__.
While it kind of works, this approach feels terribly wrong. Like I am missing something.
Is there a nice way to execute modules at build time from a NormalModule object having basic access to vars like __webpack_public_path__? Maybe Webpack offers a better way to do these kind of things?
Ok, yeah, sounds like you can solve this another way, I've done similar stuff where I needed to change what a module output, write stuff to disk, trigger side effects, etc. It sounds like you want loaders rather than a plugin. The run-loader (https://www.npmjs.com/package/webpack-run-loader) executes the module it loads and exports or returns the result.
You can write a custom loader that you chain to run after responsive-loader, and run-loader, and which receives the JSON from run-loader and writes it to disk where you want it (as a side effect), and then returns an empty string so that nothing is added to the build. The end result would be that requiring this module in your app gets your image files created (by responsive-loader), and the JSON written out to disk where you need it (by your custom loader). Alternately you could skip run-loader and in your custom loader use regex to just grab the JSON from the output of responsive-loader. Using regex on code generated by a project dependency seems fragile, but as long as you have your dependency versions locked down it can work just fine in practice, and it's a bit simpler conceptually than adding run-loader to the pipeline.
If you're writing webpack plugins I imagine you're comfortable writing loaders as well, but if not they're pretty straightforward -- just a function that accepts source code from the loader that came before it and returns code, and does whatever you want in between. The docs aren't bad for the API, but looking at the source of a few published loaders is helpful, too. It might look roughly (just spitballing from memory) like:
// img-info-logging-loader.js
// regex version, expects source arg to be output of responsive-loader
import * as fs from 'fs';
export const imgInfoLoggingLoader = (source) => {
const jsonFinderRegex = /someregexto(match)onsource/;
const desiredJSON = source;
const matchArr = jsonFinderRegex.exec(desiredJSON);
if (!matchArr[1]) {
throw new ReferenceError('json output not found in loader source.');
} else {
const imgConfigJsonString = matchArr[1];
// you would write a fn to generate a filename based on the
// source, or based on the module's filename, which is available
// via the webpack loader api
const fileNameToWrite = getFileNameTowrite();
try {
// async might be preferable depending on your webpack
// performance needs
fs.writeFileSync(fileNameToWrite, imgConfigJsonString);
} catch (err) {
throw new Error(`error writing ${fileNameToWrite}`);
}
}
// what the loader inserts into your JS asset: empty string
return '';
}
EDIT:
Since per your comment you are looking to output a single JSON object with all of the image info in it, you would want a slightly different approach that does use a plugin (this is the most elegant way I know to do it, there may be others). As far as I know a plugin is the only way to 'do something' when webpack is done loading modules.
You still want a custom loader that is extracting the JSON from the output of the responsive-loader, as described above. It won't write each to disk, though. Instead your loader will call a method on the following module:
You also write a json-collector.js that is just a little node module that you will use to hold on to the JSON object you're building. This bit is awkward because it's separate from the loader but the loader needs it. This collector module is simple, though, and if you wanted to be cleaner you could turn it into a more generic module and treat it as a proper, separate node dependency. All it is is an object with a method for adding JSON data, which appends it to an internal JSON object, and one for reading out the collected data, which returns the JSON.
And then you have a plugin that hooks into the end of the build (I think there's one for 'build sealed' that I've used). When that hook is reached, you know webpack has no more modules to load, so the plugin now calls the 'read' method on the json-collector, gets the JSON object from it and writes that to disc.
This solution doesn't fit the standalone plugin/standalone loader convention in webpack but if that doesn't bother you it's actually pretty straightforward, each of the three pieces has a simple job to do. I've used this pattern multiple times and it's worked for me.

ES6 Importing working differently in different files

I have two different files in the same folder, both with the same code for importing in them.
import { PartialOne, PartialTwo } from 'components/partials'
console.log(PartialOne);
In the first file, the importing works correctly and the PartialOne function is displayed in the console. In the second, PartialOne is logged as undefined.
To make sure, I also tried:
import * as partials from 'components/partials'
console.log(partials);
And it returned an object-esque thing that had PartialOne and PartialTwo as properties. So, I'm pointing to the right exported file in both files that are trying to import it, but something is getting messed up, and can't figure out what.
I'm not sure what's going on so it's hard to know what to search for in Google/SO, but if there's another related SO question that would be helpful to have too.
(From the comment by loganfsmyth):
Check if there is a cycle in your dependency graph. That usually leads to issues like this, e.g. the export class ParitalOne {} line hasn't run yet, so the value shows as undefined

How do you fix file load order problems using Meteor.startup?

Many resources on the internet (including here) suggest using Meteor.startup to fix dependency issues caused by the order in which JS files load. However, nobody spells out exactly how this is accomplished.
Specifically, it seems like file order dependency is the reason I can't get my posts.coffee collection to recognize permissions defined in my permissions.coffee. I think this is happening because posts.coffee is in /lib/collections, whereas permissions.coffee is in /lib, and files in subdirectories get loaded first. (Incidentally, I would prefer /collections to be in the root directory, but I had to move it into /lib previously to solve a similar problem.)
Here is my posts.coffee:
#Posts = new Meteor.Collection('posts')
Posts.allow(
update: ownsDocument
remove: ownsDocument
)
Meteor.methods(
...
And here is my permissions.coffee:
#ownsDocument = (userId, doc)->
doc && doc.userId == userId
(This is all from the "Discover Meteor" book tutorial, by the way, around these commits, except in CoffeeScript.)
My question: Assuming my analysis of the problem is correct, how would you solve it using Meteor.startup? This answer is hard for me to interpret; one interpretation is that I should wrap Posts.allow(...) in Meteor.startup somehow, but that seems really clumsy. Maybe I'm wrong, but it seems like there should be one general/config file with all the necessary startup code, and specific controllers should remain ignorant of it.
BTW, I realize I could hack a solution by taking advantage of Meteor's default file load ordering rules (e.g. /lib first; subdirectories first; main.* last; alphabetically), but that's a really inelegant solution to what should be a simple problem. I don't want to have to append "a" in front of a filename or create spurious directories just to get it load before another file.
One last note: I'm using CoffeeScript, and I wonder if the way CS handles global scope has something to do with it. (E.g., instead of defining my Posts collection as a JS variable without the var keyword, in CS I have to define is as #Posts, which I believe makes it a property of the window.)
Yes, you do just that:
Meteor.startup ->
Posts.allow(
...
)
Basically, any piece of code that uses a variable defined in another file should be preceded by Meteor.startup ->, unless you are sure that the loading order is correct (the variable is in lib, for example).
Yes, the loading order is poorly chosen.
I highly suggest you consider working entirely out of smart packages. That's how Meteor itself is largely written.
I go into more detail here: http://www.matb33.me/2013/09/05/meteor-project-structure.html

Categories

Resources