How do I write a Webpack plugin to generate index.js files on demand? - plugins

In general, I want to know how to do code-generation/fabrication in a Webpack plugin on demand. I want to generate contents for files that do not exist when they are "required."
Specifically, I want a plugin that, when I require a directory, automatically requires all files in that directory (recursively).
For example, suppose we have the directory structure:
foo
bar.js
baz.js
main.js
And main.js has:
var foo = require("./foo");
// ...
I want webpack to automatically generate foo/index.js:
module.exports = {
bar: require("./bar"),
baz: require("./baz")
};
I've read most of the webpack docs. github.com/webpack/docs/wiki/How-to-write-a-plugin has an example of generating assets. However, I can't find an example of how to generate an asset on demand. It seems this should be a Resolver, but resolvers seem to only output file paths, not file contents.

Actually for your use case:
Specifically, I want a plugin that, when I require a directory, automatically requires all files in that directory (recursively).
you don't need a plugin. See How to load all files in a subdirectories using webpack without require statements
Doing code-generation/fabrication on demand can be done in JavaScript quite easily, why would you restrict your code generation specifically to only applied, when "required" by WebPack?
As NodeJS itself will look for an index.js, if you require a directory, you can quite easily generate arbitrary exports:
//index.js generating dynamic exports
var time = new Date();
var dynamicExport = {
staticFn : function() {
console.log('Time is:', time);
}
}
//dynamically create a function as a property in dynamicExport
//here you could add some file processing logic that is requiring stuff on demand and export it accordingly
dynamicExport['dyn' + time.getDay()] = function() {
console.log('Take this Java!');
}
module.exports = dynamicExport;

Related

Specifying window (global) variable type hinting in VSCode from external JS file without typescript

This may be a silly question but I really don't know where to look.
I'm creating a browser testing environment for a pretty large-scale API written in typescript. This API uses esbuild to build the typescript files into a /dist/ folder with a single index.js entry-point and its appropriate d.ts file.
I've created a /tests/ folder to hold some browser files that includes an index.html file with Mocha and Chai imported. It also imports /dist/index.js which is set globally to a window.myAPI variable.
In /tests/index.html:
import * as myAPI from "./dist/index.js"
Alongside index.html in the tests folder, there are separate JS files included for different tests that run things on window.myAPI... to do assertion tests.
search.test.js
book.test.js
navigate.test.js
I then run a server to host at the root. These separate tests are then imported from /tests/index.html. The separate tests look like this inside:
const { chai, mocha } = window;
const { assert } = chai;
describe("Search", function() {
describe("Setup", function() {
it("Setting URL should work", function() {
const call = myAPI.someCall()
assert.ok(call);
});
});
});
mocha.run();
Everything works, but I have no code hinting for myAPI. I'd like to be able to see what functions are available when I type myAPI, and what parameters they take, and what they should return - along with all my comments on each function.
In typescript you can do things like ambient declarations, but I don't want to make my tests typescript because then I add an unnecessary build step to the tests. But it would be as easy as:
/// <reference path = "/dist/index.d.ts" />
How can I tell VSCode that window.myAPI is an import of /dist/index.js and should import the types as well so I can see them ?
I'm open to different solutions to this, but I feel like this should be pretty simple. I don't know if ESLint is capable of doing something like this, but I tagged it because I feel it's relevant.
Thanks!

How to override an HTML file in a custom module

I am developing a custom module for a payment method in magento 2. Currently I am using cc-form.html from the vendor directory and the module is working fine. see below path.
vendor/magento/module-payment/view/frontend/web/template/payment/cc-form.html
Is there any way to override the HTML file?
Yes, there is. You can look in pub static to see how path to static asset constructed.
How it works
Every asset is accessible from the page by itenter code heres "RequireJS ID". It similar to real path, but varied.
For example file http://magento.vg/static/adminhtml/Magento/backend/en_US/Magento_Theme/favicon.ico.
It's real path is /app/code/Magento/Theme/view/adminhtml/web/favicon.ico.
It's RequireJS ID is Magento_Theme/favicon.ico. This means that file could be accessible via require("text!Magento_Theme/favicon.ico") or similar command.
You can find that RequireJS ID consist with module name and useful part of path (after folder web).
How can I replace a file
So you have file
vendor/magento/module-payment/view/frontend/web/template/payment/cc-form.html
On the page it loaded with src as
http://magento.vg/static/frontend/Magento/luma/en_US/Magento_Payment/template/payment/cc-form.html
So its RequireJS ID is
Magento_Payment/template/payment/cc-form.html
Side note: Inside UI components stuff it equals to Magento_Payment/payment/cc-form. Words "template" and ".html" are added automatically.
And now you can replace this file for application via RequireJS config
var config = {
"map": {
"*": {
"Magento_Payment/template/payment/cc-form.html":
"<OwnBrand>_<OwnModule>/template/payment/cc-form.html"
}
}
};
This code snippet you place in requirejs-config.js file in your module. That is all.

ember-cli exclude a directory beneath "tests" from being watched by "ember serve"

Is there a way to exclude a subdirectory of "tests" from being watched by ember serve?
ex. I have a dir under "tests" called "selenium".
If 'ember serve' is running and I do "echo xyz > bam" in the selenium folder,
the ember serve console will output "file changed selenium/bam" and rebuild the app.
I would like to understand if there is a way to exclude the entire selenium dir without moving it out of the tests folder ( even though for now I am moving the dir)
either:
You can use broccoli-unwatched-tree.
Just add var seleniumTree = new UnwatchedTree('tests/selenium'); to your Brocfile.js before you add that tree to your application with module.exports = app.toTree(seleniumTree);
You can continue to use this tree just like any of the others, but due to the way it is implemented the standard Broccoli::Watcher class will not check it for file changes.
or:
You could also implement this functionality yourself by adding an object that exports the read() and cleanup() functions that are expected by the broccoli watcher, leaving the cleanup() function empty as is done for broccoli-bower.
// Almost the same as using a plain string for a tree; but unlike a plain
// string, Broccoli won't watch this
function UnwatchedTree (dir) { this.dir = dir }
UnwatchedTree.prototype.read = function (readTree) { return this.dir }
UnwatchedTree.prototype.cleanup = function () { }

sails.js setup: How to make a node module available across the sails project (controller / model, etc)?

I just getting started with SailsJS as my first web framework on Node. Let's say I wanna add MomentJS in and use across the app. How to set it up?
you can use the bootstrap.js (in config/)
like:
module.exports.bootstrap = function (cb) {
sails.moment = require('moment');
cb();
};
in all Sails-Files you can use
sails.moment()
now.
If you're trying to include your node_modules into the client side, such as jQuery, AngularJS or one of the various many font libraries, then you can npm install them as normal, but just to be sure in sails you edit your tasks/config/copy.js and add a new block, example:
grunt.config.set('copy', {
dev: {
files: [{
expand:true,
cwd: './node_modules/font-awesome/fonts',
src: ['**/*'],
dest: '.tmp/public/fonts'
}
}
});
LESS can be #imported like normal without being copied around. Other assets will need to be copied as above. If you're using the sails linker then don't forget to add your JS paths to tasks/pipeline.js too (if necessary).
You can read more here:
http://ash.zi.vc/sails/2016/02/02/including-client-side-node-modules-in-my-sails-application/
It's not directly obvious how to sync npm modules to the web accessible directories.
SailsJS is no different to any other NodeJS app. So on top of your (say) Controller.js file, you do
var m = require("moment");
And you're good to go. #mdunisch's method will obviously let you use the moment package throughout your app, without having to do "require" in each file.

TypeLite generate external modules?

I am trying to generate external modules rather than a type definition file. I believe I need to do the following:
Change the extension of the file to .ts instead of .d.ts.
Generate one file per module.
Add the key word "Export" in front of each interface and enum.
I was easily able to change the extension of the file by changing the "output extension" setting in the tt file.
I cannot figure out how to split the modules into separate files.
I cannot figure out how to add the Export key word to each interface.
TypeLITE doesn't support generating multiple files. This feature has been requested by several users, but I am not aware of a simple way to generate multiple files from the single tt file.
export keyword can't be added without changing source code of the library (TsGenerator.cs). This is very specific requirement, so I probably won't add it to the library.
TypeLite is a good project but lacking in Documentation and examples, it's open source so anyone can contribute and make it better.
As for creating a file per class i solved it using the code below.
private static void GenerateTypeScriptContracts(string assemblyFile, string outputPath)
{
// Clean TS Folder
System.IO.DirectoryInfo di = new DirectoryInfo(outputPath);
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
// --
var assembly = Assembly.LoadFrom(assemblyFile);
// If you want a subset of classes from this assembly, filter them here
var models = assembly.GetTypes();
foreach (var model in models)
{
var generator = new TypeScriptFluent()
.WithConvertor<Guid>(c => "string")
.WithMemberFormatter((identifier) => Char.ToLower(identifier.Name[0]) + identifier.Name.Substring(1));
generator.ModelBuilder.Add(model);
// Generate TS interface definitions
var tsClassDefinitions = generator.Generate(TsGeneratorOutput.Properties | TsGeneratorOutput.Fields);
File.WriteAllText(Path.Combine(outputPath, "I" + model.FullName.Replace("ProjectName.DtoModels.", "") + ".ts"), tsClassDefinitions);
}
}