Exclude folders from builds in Brocfile - javascript

Is there a way to exclude a folder from a build in a Brocfile (or any other place).
The use case is packaging, where I have an app made of sub-apps within pods. eg.
/app/modules/components
/app/modules/app1
/app/modules/app2
/app/modules/app3
I'd like to build them all when environment is set to 'development' or only eg. 'app1' when environment is 'app1'. Any suggestions?
I have tried different combinations of broccoli-file-remover, broccoli-funnel and broccoli-merge-trees to no avail.
var removeFile = require('broccoli-file-remover');
module.exports = removeFile(app.toTree(), {
paths: ['app/modules/pod1/', 'app/modules/pod2/']
});

Ah, so after actually thinking about this clearly, everything is actually working exactly as expected in my previous example.
I clearly wasn't paying enough attention. app.toTree() is far too late to perform this operation, as everything has already been built and concated.
Luckily, ember-cli does enable addons to modify the appropriate trees at various life cycle milestones.
See: https://github.com/ember-cli/ember-cli/blob/master/ADDON_HOOKS.md for more details on which hooks are currently available.
The hook that should do the trick is Addon.prototype.postprocessTree. Now we have two choices, we can build a standalone addon, via ember addon or we can create a light-weight in-repo addon via ember g in-repo-addon. Typically for these types of situations, I prefer in-repo-addons as they don't require a second project, but otherwise they are the same.
ember g in-repo-addon remove
we need to install broccoli-stew via npm install --save broccoli-stew
include it var stew = require('broccoli-stew');
add hook postprocessTree to the add-on
when the postprocessTree is for the type we care about, use broccoli-stew to remove the directories we no longer care care.
The resulting pull request: https://github.com/WooDzu/ember-exclude-pod/pull/1
Note: I noticed template wasn't one of the types available in postprocess, so I added it: https://github.com/ember-cli/ember-cli/pull/4263 (should be part of the next ember-cli release)
Note: we really do want an additional hook
Addon.prototype.preprocessTree, as to ignore the files before we
even build them. I have opened a related issue:
https://github.com/ember-cli/ember-cli/issues/4262
output of the above steps
var stew = require('broccoli-stew');
module.exports = {
name: 'remove',
isDevelopingAddon: function() {
return true;
},
postprocessTree: function(type, tree){
if (type === 'js' || type === 'template') {
return stew.rm(tree, '*/modules/pod{1,2}/**/*');
} else {
return tree;
}
}
};

I am pretty confident broccoli-stew's rm will handle this correctly.
https://github.com/stefanpenner/broccoli-stew/blob/master/lib/rm.js#L4-L40 there are even tests that test a very similar scenario: https://github.com/stefanpenner/broccoli-stew/blob/master/tests/rm-test.js#L48-L57
var stew = require('broccoli-stew');
module.exports = stew.rm(app.tree(), 'app/modules/{pod1,pod2}');
If this doesn't work, feel free to open an issue on broccoli-stew. Be sure to provide a running example though

This is really late, but I created a Broccoli plugin to do just this. It's available at https://www.npmjs.com/package/broccoli-rm.
(The trick is to detect whether an excluded path is a folder, and then use a glob match to make sure that none of the children of the folder get symlinked during copying.)
var rm = require('broccoli-rm');
var input = app.toTree();
module.exports = output = rm([input], {
paths: ['app/modules/pod1', 'app/modules/pod2']
});

Related

differentiate between make and package in Electron Forge config

I have an Electron Forge config file set up with many options and it all works automagically and beautifully (thanks Forge team!!). But I have found certain situations where I might want to handle a bare npm run package differently than a full npm run make (which as I understand it runs the package script as part of its process). Is there any way to programmatically detect whether the package action was run direct from the command line rather than as part of the make process, so that I can invoke different Forge configuration options depending? For example sometimes I just want to do a quick build for local testing and skip certain unnecessary time-consuming steps such as notarizing on macOS and some prePackage/postPackage hook functions. Ideally I'm looking for a way to do something like this in my Forge config file:
//const isMake = ???
module.exports = {
packagerConfig: {
osxNotarize: isMake ? {appleId: "...", appleIdPassword: "..."} : undefined
},
hooks: {
prePackage: isMake ? someFunction : differentFunction
}
}
You can do it by process.argv[1]:
let isMake;
if (process.argv[1].endsWith('electron-forge-make.js') {
isMake = true;
} else {
isMake = false;
}
module.exports = {
// ...
}
When calling process.argv, it returns an array with two strings: The first one with node.js directory and the second one with electron forge module directory.
The make module ends with electron-forge-make.js and package module ends with electron-forge-package.js. So you can look at the end of it and determine whether it's package or make.

Application modularity with Vue.js and local NPM packages

I'm trying to build a modular application in Vue via the vue-cli-service. The main app and the modules are separated projects living in different folders, the structure is something like this:
-- app/package.json
/src/**
-- module1/package.json
/src**
-- module2/package.json
/src**
The idea is to have the Vue app completely agnostic about the application modules that can be there at runtime, the modules themself are compiled with vue-cli-service build --target lib in a local moduleX/dist folder, pointed with the package.json "main" and "files" nodes.
My first idea (now just for development speed purposes) was to add the modules as local NPM packages to the app, building them with a watcher and serving the app with a watcher itself, so that any change to the depending modules would (I think) be distributed automatically to the main app.
So the package.json of the app contains dependencies like:
...
"module1": "file:../module1",
"module2": "file:../module2",
...
This dependencies are mean to be removed at any time, or in general be composed as we need, the app sould just be recompiled and everything should work.
I'm trying to understand now how to dynamically load and activate the modules in the application, as I cannot use the dynamic import like this:
import(/* webpackMode: "eager" */ `module1`).then(src => {
src.default.boot();
resolve();
});
Because basically I don't know the 'module1', 'module2', etc...
In an OOP world I would just use dependency injection retrieving classes implementing a specific interface, but in JS/TS I'm not sure it is viable.
There's a way to accomplish this?
Juggling with package.json doesn't sound like a good idea to me - doesn't scale. What I would do:
Keep all available "modules" in package.json
Create separate js file (or own prop inside package.json) with all available configurations (for different clients for example)
module.exports = {
'default': ['module1', 'module2', 'module3'],
'clientA': ['module1', 'module2', 'module4'],
'clientB': ['module2', 'module3', 'module4']
}
tap into VueCLI build process - best example I found is here and create js file which will run before each build (or "serve") and using simple template (for example lodash) generate new js file which will boot configured modules based on the value of some ENV variable. See following (pseudo)code (remember this runs inside node during build):
const fs = require('fs')
const _ = require('lodash')
const modulesConfig = require(`your module config js`)
const configurationName = process.env.MY_APP_CONFIGURATION ?? 'default'
const modules = modulesConfig[configurationName]
const template = fs.loadFileSync('name of template file')
const templateCompiled = _.template(template)
const generatedJS = templateCompiled({ `modules`: modules })
fs.writeFileSync('bootModules.js', generatedJS)
Write your template for bootModules.js. Simplest would be:
<% _.forEach(modules , function(module) { %>import '<%= module %>' as <%= module %><% }); %>;
import bootModules.js into your app
Use MY_APP_CONFIGURATION ENV variable to switch desired module configuration - works not just during development but you can also setup different CI processes targeting same repo with just different MY_APP_CONFIGURATION values
This way you have all configurations at one place, you don't need to change package.json before every build, you have simple mechanism to switch between different module configurations and every build (bundle) contains only the modules needed....
In an OOP world I would just use dependency injection retrieving classes implementing a specific interface, but in JS/TS I'm not sure it is viable.
Why not?
More than this, with JS/TS you are not restricted to use classes implementing a specific interface: you just need to define the interface (i.e. the module.exports) of your modules and respecting it in the libraries entries (vue build lib).
EDIT: reading comments probably I understood the request.
Each module should respect following interface (in the file which is the entry of the vue library)
export function isMyAppModule() {
return true;
}
export function myAppInit() {
return { /* what you need to export */ };
}
Than in your app:
require("./package.json").dependencies.forEach(name => {
const module = require(name);
if(! module.isMyAppModule || module.isMyAppModule() !== true) return;
const { /* the refs you need */ } = module.myAppInit();
// use your refs as you need
});

Separating/combining gulp task sources using yargs and gulp-if

Lets say I want to include all js files in a source folder concatenated in a specific order (using gulp-concat). However, I want to only include certain files if there is a production flag.
For example, in production I need these files:
modals.js
utilities.js
analytics.js
signup.js
cookies.js
However, for local and staging, I don't want these two:
analytics.js
cookies.js
Is it possible using yargs and perhaps gulp-if to specify this? I know that I could have two lists of sources, for instance:
if (argv.production) {
return gulp.src([
'modals.js',
'utilities.js',
'analytics.js',
'signup.js',
'cookies.js'
])
} else if (argv.staging) {
return gulp.src([
'modals.js',
'utilities.js',
'signup.js',
])
}
However, this would mean I'm not adhering to DRY principles, and just feels silly and prone to error. Can I somehow stitch these together as a single source that only includes things like analytics and cookies if the task has a production flag?
In an ideal world, I could inject gulp if statements inside the gulp.src array that would only include the production-only files if the correct flag were passed.
Some out-loud thinking:
- Should I just create two files here? One a base that includes everything necessary across environments, and then a production specific one, then combine those? Seems unnecessarily complex, but could solve the problem.
If your goal is to be a bit more DRY, you can give this a shot, since your set of staging files is a subset of the production files:
var base_list = ['modals.js', 'utilities.js', 'signup.js'];
if (argv.staging) {
return gulp.src(base_list);
} else if (argv.production) {
var prod_list = base_list.concat(['analytics.js', 'cookies.js']);
return gulp.src(prod_list);
}
Or more simplified (as long as only production needs the other files, and all other environments get the subset):
var file_list = ['modals.js', 'utilities.js', 'signup.js'];
if (argv.production) {
file_list = file_list.concat(['analytics.js', 'cookies.js']);
}
return gulp.src(file_list);
There might be some other gulp-specific best practices or tools that could come into play here, but some simple JavaScript might do the trick.

Minify Scripts/CSS in production mode with node.js

I have a web app that runs in node. All the (client) Javascript/CSS files are not minified at the moment to make it easier to debug.
When I am going into production, I would like to minify these scripts. It would be nice to have something like:
node app.js -production
How do I serve the minified version of my scripts without changing the script tags in my html files? There should be something like: if I am in production, use these 2 minified(combined) scripts, else use all my unminified scripts..
Is this possible? Maybe I am thinking too complicated?
You might be interested in Piler. It's a Node.js module that delivers all the JavaScript (and CSS) files you specify as usual when in debug mode, but concatenated and minified when in production mode.
As a special feature, you can force CSS updates via Socket.io in real-time to appear in your browser (called "CSS Live Updated" in Piler), which is quite awesome :-).
The trick is that inside your template you only have placeholders for the script and link elements, and Piler renders these elements at runtime - as single elements in debug mode, and as a dynamically generated single element in production mode.
This way you can forget about creating concatenated and minified versions of your assets manually or using a build tool, it's just there at runtime, but you always have the separated, full versions when developing and debugging.
you could use 2 separate locations for your static files
Here's some express code:
if (process.env.MODE === "production") {
app.use(express['static'](__dirname + '/min'));
} else {
app.use(express['static'](__dirname + '/normal'));
}
and start node with
MODE=production node app.js
Furthermore, if you don't want to duplicate all your files, you could take advantage of the fact that express static router stops at the first file, and do something like this instead:
if (process.env.MODE === "production") {
app.use(express['static'](__dirname + '/min')); // if minized version exists, serves it
}
app.use(express['static'](__dirname + '/normal')); // fallback to regular files
Using the same name for minimized or not is going to cause problem with browser caching, though.
I want to share my final solution with you guys.
I use JSHTML for Express (enter link description here)
In my main node file I use a special route:
app.get('/**:type(html)', function (req, res, next) {
var renderingUrl = req.url.substring(1, req.url.lastIndexOf("."));
//TODO: Find a better solution
try{
var assetUrl = req.url.substring(req.url.lastIndexOf("/") + 1, req.url.lastIndexOf("."));
var assets = config.getResourceBundle(assetUrl);
assets.production = config.getEnviroment() === "production";
res.locals(assets);
res.render(renderingUrl);
}catch(e){
res.redirect("/");
}
});
As you can see, I get my assets from config.getResourceBundle. This is a simply function:
exports.getResourceBundle = function(identifier){
switch(enviroment){
case "development":
return devConfig.getResourceBundle(identifier);
case "production":
return prodConfig.getResourceBundle(identifier);
default:
return devConfig.getResourceBundle(identifier);
}
}
And finally an example for an asset file collection is here:
exports.getResourceBundle = function (identifier) {
return resourceBundle[identifier];
};
resourceBundle = {
index:{
cssFiles:[
"resources/dev/css/login.css",
"resources/dev/css/logonDlg.css",
"resources/dev/css/footer.css"
],
jsFiles:[
"resources/dev/js/lib/jquery/jquery.183.js",
"resources/dev/js/utilities.js",
"resources/dev/js/lib/crypto.3.1.2.js"
]
},
register:{
cssFiles:[
"resources/dev/css/login.css",
"resources/dev/css/modalDialog.css",
"resources/dev/css/footer.css"
],
jsFiles:[
"resources/dev/js/lib/jquery/jquery.183.js",
"resources/dev/js/utilities.js",
"resources/dev/js/lib/crypto.3.1.2.js",
"resources/dev/js/lib/jquery.simplemodal.js",
"resources/dev/js/xfiles.register.js"
]
}
(...)
I have 2 folders. dev / prod. grunt will copy the minified files into prod/.. and deletes the files from dev/...
And if the NODE_ENV variable is set to production, I will ship the minified versions of my scripts/css.
I think this is the most elegant solution at the moment.
There are build tool plugins for you, may help you gracefully solve this problem:
For Gulp:
https://www.npmjs.org/package/gulp-useref/
For Grunt:
https://github.com/pajtai/grunt-useref
Another Node.js module which could be relevant is connect-cachify.
It doesn't seem to do the actual minification for you, but it does let you serve the minified version in production, or all the original scripts in development, without changing the templates (thanks to cachify_js and cachify_css).
Seems it's not as feature-rich as Piler, but probably a bit simpler, and should meet all the requirements mentioned in the question.

How to set a including path in the Gjs code?

As i could see, the Gjs imports, loads only /usr/share/gjs-1.0 and /usr/lib/gjs-1.0 by default. I want to modularize an application, like we can do with node, but i must find modules relative to the script file.
I found this two ways to add include paths:
gjs --include-path=my-modules my-script.js
GJS_PATH=my-modules gjs my-script.js
...but both are related to the current directory, not to the file (obliviously), and they needed to be declared on the command line, making this unnecessarily complex.
How can i set a including path in the Gjs code? (So i can make this relative to the file)
Or... There is another way to import files from anywhere, like in python?
(Please, you don't need to propose to use a shellscript launcher to solve the --include-path and GJS_PATH problem. That is obvious, but less powerful. If we do not have a better solution, we survive with that.)
You need to set or modify imports.searchPath (which is not obvious because it doesn't show up with for (x in imports)print(x)). So this:
imports.searchPath.unshift('.');
var foo = imports.foo;
imports the file “foo.js” as the foo object.
This is compatible with Seed, although there imports knows it has a searchPath.
(Earlier versions of this answer were substantially less accurate and more inflammatory. Sorry).
As Douglas says, you do need to modify imports.searchPath to include your library location. Using . is simple, but depends on the files always being run from the same directory location. Unfortunately finding the directory of the currently executing script is a huge hack. Here's how Gnome Shell does it for the extensions API
I've adapted this into the following function for general use:
const Gio = imports.gi.Gio;
function getCurrentFile() {
let stack = (new Error()).stack;
// Assuming we're importing this directly from an extension (and we shouldn't
// ever not be), its UUID should be directly in the path here.
let stackLine = stack.split('\n')[1];
if (!stackLine)
throw new Error('Could not find current file');
// The stack line is like:
// init([object Object])#/home/user/data/gnome-shell/extensions/u#u.id/prefs.js:8
//
// In the case that we're importing from
// module scope, the first field is blank:
// #/home/user/data/gnome-shell/extensions/u#u.id/prefs.js:8
let match = new RegExp('#(.+):\\d+').exec(stackLine);
if (!match)
throw new Error('Could not find current file');
let path = match[1];
let file = Gio.File.new_for_path(path);
return [file.get_path(), file.get_parent().get_path(), file.get_basename()];
}
Here's how you might use it from your entry point file app.js, after defining the getCurrentFile function:
let file_info = getCurrentFile();
// define library location relative to entry point file
const LIB_PATH = file_info[1] + '/lib';
// then add it to the imports search path
imports.searchPath.unshift(LIB_PATH);
Wee! now importing our libraries is super-easy:
// import your app libraries (if they were in lib/app_name)
const Core = imports.app_name.core;

Categories

Resources