Cannot set property '__UglifyJsPlugin' of undefined - node.js

I am using the following plugin to paralelized the uglify step in webpack
https://github.com/tradingview/webpack-uglify-parallel
unfortunately, I get the following error:
Fatal error: Cannot set property '__UglifyJsPlugin' of undefined
Here's my webpack config:
/*jslint node: true */
var webpack = require("webpack"),
_ = require("lodash"),
path = require("path"),
fs = require("fs"),
os = require('os'),
UglifyJsParallelPlugin = require('webpack-uglify-parallel'),
webpackConfig,
commonsPlugin = new webpack.optimize.CommonsChunkPlugin('m-common-[chunkhash:8].js'),
dedupePlugin = new webpack.optimize.DedupePlugin(),
uglifyPlugin = new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
parallelUglify = new UglifyJsParallelPlugin({
workers: os.cpus().length
}),
sourceMapPlugin = new webpack.SourceMapDevToolPlugin('[file].map', null,
'[absolute-resource-path]',
'[absolute-resource-path]'),
fnCaseSensitivityPlugin = function () {
this.plugin('normal-module-factory', function(nmf) {
nmf.plugin('after-resolve', function(data, done) {
var parentDir = path.dirname(data.resource);
var resourceName = path.basename(data.resource);
fs.readdir(parentDir, function(err, files) {
if (err) {
done(err);
}
if (files.indexOf(resourceName) === -1) {
var realName = _.find(files, function(filename) {
return filename.toLowerCase() === resourceName.toLowerCase();
});
done(new Error('CaseSensitivityPlugin: `' + resourceName + '` does not match the corresponding file on disk `' + realName + '`'));
return;
}
done(null, data);
});
});
});
},
fnDonePlugin = function () {
this.plugin("done", function(stats) {
var statsByChunk = JSON.parse(JSON.stringify(stats.toJson())).assetsByChunkName;
webpackConfig.statsByChunk = statsByChunk;
for (var chunkName in statsByChunk) {
if (statsByChunk.hasOwnProperty(chunkName)) {
var nameIn = statsByChunk[chunkName][0],
gzName = nameIn.substring(0, nameIn.length - 2) + "gz.js";
webpackConfig.filesToCompress['./marvel-web/dist/' + gzName] = './marvel-web/dist/' + nameIn;
// The mrvlBuildOut object contains a set of name/value
// pairs to be used during HTML template processing.
// There are certain filenames we need to add to the
// mrvlBuildOut object as properties so that they can be
// injected into HTML templates that make use of them.
// The code below takes the nameIn string which will have
// one of 2 forms:
//
// Debug Builds:
// m-core-fixed.js
//
// Produciton Builds:
// m-core-<chunkid>.js
//
// It strips off everything after the last dash including the
// .js extension so we are left with the base filename. We then
// use that filename base to look up the name of the property
// we should set to that filename on the mrvlBuildOut object.
var map = webpackConfig.mrvlBuildOutFilePropMap,
propName = map[nameIn.replace(/-[^-]+\.js$/ , '')];
if (propName) {
webpackConfig.mrvlBuildOut[propName] = nameIn;
}
}
}
webpackConfig.webpackDoneListeners.forEach(function (fnCall) {
fnCall(statsByChunk);
});
});
};
webpackConfig = {
mrvlBuildOut: {
//gets filled in with m-common-[chunkhash] and m-web-[chunkhash]
},
mrvlBuildOutFilePropMap: {
"m-common": "marvelcommon",
"m-web": "marvelweb",
"m-blog": "marvelblog",
"m-gallery": "marvelgallery",
"m-landing": "marvellanding",
"m-unsupported": "marvelunsupported",
"m-login": "marvellogin",
"m-voice-chrome": "voicechrome",
"m-apps-chrome": "appschrome",
"m-viewpage-chrome": "viewpagechrome"
},
webpackDoneListeners: [],
filesToCompress: {
},
marvel: {
addVendor: function (name, path, noparse) {
this.resolve.alias[name] = path;
if (noparse) {
this.module.noParse.push(new RegExp(path));
}
this.entry.vendors.push(name);
},
addBuildOutFilePropMapEntry: function( filenameBase, propName ) {
if ( filenameBase && propName ) {
webpackConfig.mrvlBuildOutFilePropMap[filenameBase] = propName;
}
},
stats: {
colors: true,
modules: true,
reasons: false
},
entry: {
'm-web': './marvel-web/js/app.js',
'm-blog': './marvel-web/js/app-blog.js',
'm-gallery': './marvel-web/js/app-gallery.js',
'm-landing': './marvel-web/js/app-landing.js',
'm-unsupported': './marvel-web/js/app-unsupported.js',
'm-login': './marvel-web/js/app-login.js',
'm-voice-chrome': './marvel-web/js/app-voice-chrome.js',
'm-apps-chrome': './marvel-web/js/app-apps-chrome.js',
'm-viewpage-chrome': './marvel-web/js/app-viewpage-chrome.js',
vendors: []
},
resolve: {
modulesDirectories: [
'node_modules',
'marvel-web',
'marvel-web/js'
],
alias: {
// If you find yourself wanting to add an alias here, think
// about if it would be better for your component to live in
// marvel-core instead of in marvel-web. See the README.md in
// marvel-core for more info.
'marvel-apps': __dirname + '/marvel-web/js/apps.js',
'uuid': 'node-uuid'
}
},
output: {
path: 'marvel-web/dist',
filename: '[name]-[chunkhash:8].js',
chunkFilename: '[name]-[chunkhash:8].js'
},
module: {
noParse: [
/[\/\\].html$/
]
},
plugins: [
commonsPlugin,
dedupePlugin,
parallelUglify,
fnCaseSensitivityPlugin,
sourceMapPlugin,
fnDonePlugin
]
}
};
var libs_dir = __dirname + '/marvel-core/src/js/lib/';
webpackConfig.marvel.addVendor("jquery", libs_dir + "jQuery/jquery.min.js", true);
webpackConfig.marvel.addVendor("lodash", libs_dir + "lodash/lodash.min.js", true);
webpackConfig.marvel.addVendor("underscore", libs_dir + "lodash/lodash.min.js", true);
webpackConfig.marvel.addVendor("q", libs_dir + "q/q.js", true);
webpackConfig.marvel.addVendor("backbone", libs_dir + "backbone/backbone-min.js", false);//if we don't parse backbone then require is not found??
webpackConfig.marvel.addVendor("cookie", libs_dir + "cookie/cookie.js", true);
webpackConfig.marvel.addVendor("canvas-to-blob", libs_dir + "canvas-to-blob/canvas-to-blob.js", true);
webpackConfig.marvelDebug = {
watch: true,
keepAlive: true,
stats: webpackConfig.marvel.stats,
entry: webpackConfig.marvel.entry,
resolve: webpackConfig.marvel.resolve,
output: {
path: 'marvel-web/dist',
filename: '[name]-fixed.js',
chunkFilename: '[name]-fixed.js'
},
module: webpackConfig.marvel.module,
//devtool: "eval-source-map",
devtool: "source-map",
//devtool: "eval",
addBuildOutFilePropMapEntry: webpackConfig.marvel.addBuildOutFilePropMapEntry,
plugins: [
commonsPlugin,
dedupePlugin,
fnCaseSensitivityPlugin,
sourceMapPlugin,
fnDonePlugin
]
};
webpackConfig.marvelDebug.output.pathinfo = true;
module.exports = webpackConfig;

The plugin works in my project when I don't include a separate entry for the original UglifyJsPlugin. Try removing that and add its config to the UglifyJsParallelPlugin.

Related

Adding additional spec files to an angular project, not loading/defining correctly?

Caveat: I am not the author of this project. Whoever originally wrote this is no longer with the organization and I am seemingly the most knowledgeable on this topic at this point.
I know a little about javascript and unit tests, so I successfully added one .spec.js file. I tried adding a second one for another module, reusing a lot of the spec setup, and it immediately broke.
Project resources:
Nodejs 12.16.1
jasmine-node-karma: "^1.6.1"
karma: "^6.3.12"
Contents of ./karma.conf.js:
module.exports = function(config) {
config.set({
basePath: './public',
frameworks: ['jasmine', 'jquery-3.2.1'],
files: [
"../node_modules/angular/angular.js",
"../node_modules/angular-mocks/angular-mocks.js",
"../node_modules/bootstrap/dist/js/bootstrap.js",
"../public/**/*.js",
],
exclude: [
],
preprocessors: {
},
client: {
captureConsole: true
},
browserConsoleLogOptions: {
terminal: true,
level: ""
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['FirefoxHeadless', 'ChromeHeadlessNoSandbox', 'PhantomJS'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
},
FirefoxHeadless: {
base: 'Firefox',
flags: ['-headless'],
}
},
singleRun: false,
concurrency: Infinity
})
}
Originally I added ./public/controllers.spec.js to match the existing ./public/controllers.js. These unit tests pass and continue to do so.
Yesterday I added ./public/backups/backupcontrollers.spec.js to match ./public/backups/backupcontrollers.js.
Contents of ./public/backups/backupcontrollers.js:
/**
* Angular controller.
*/
'use strict'
const backupApp = angular.module('backup', [])
const backupTypePath = 'elasticsearch'
backupApp.controller('BackupFormController', ['$scope', '$filter', '$http', function ($scope, $filter, $http) {
console.log('Started BackupFormController')
$scope.itemInstances = []
$scope.fetchStatus = 'Ready!'
$scope.processSelection = function (item, backupType = backupTypePath) {
$scope.currentItem = item.metadata.name
$scope.getBackup(backupType)
console.log('currentItem after selecting from dropdown: ' + $scope.currentItem)
}
$scope.init = function (backupType = backupTypePath) {
$scope.refreshItemInstances(backupType)
console.log('currentItem after loading page for first time: ' + $scope.currentItem)
}
$scope.getBackup = function (backupType = backupTypePath) {
const path = `/v1/backup/${backupType}`
$scope.fetchStatus = `Fetching Backups for Item ${$scope.currentItem}...`
console.log(`Fetching backups for item from ${path}`)
$http.get('/api', { headers: { path: path, item: $scope.currentItem } })
.success(function (data, status, headers, config) {
console.log(`Got data from GET on path ${path}, HTTP status ${status}: ${JSON.stringify(data)}`)
if (typeof data === 'string' || data instanceof String) {
$scope.backups = data.split(/\r?\n/)
} else {
$scope.backups = data
}
$scope.fetchStatus = 'Ready!'
console.log('Done fetching backup list for item:' + $scope.currentItem + '!')
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
// Refresh the list of displayed Item instances
$scope.refreshItemInstances = function (backupType = backupTypePath) {
console.log('Fetching list of all items in the system ...')
$scope.fetchStatus = 'Fetching Items ... '
$http.get('/env')
.success(function (data, status, headers, config) {
console.log(data)
for (let i = 0; i < data.length; i++) {
$scope.itemInstances.push(data[i])
}
$scope.currentItem = $scope.itemInstances[0].metadata.name
console.log('Done fetching list of all items!')
console.log('currentItem after fetching list of all items: ' + $scope.currentItem)
$scope.fetchStatus = 'Ready!'
$scope.getBackup(backupType)
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
}])
Contents of ./public/backups/backupcontrollers.spec.js:
describe('BackupFormController', function () {
let $controller, $rootScope, $httpBackend
beforeEach(module('backup'))
const mockBackupString = 'string of backup data'
const mockBackupData = {
body: mockBackupString
}
const mockItemsUnsorted = [
{
metadata: {
name: 'prod-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'dev-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'integ-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
}
]
beforeEach(inject(function ($injector) {
$rootScope = $injector.get('$rootScope')
const $controller = $injector.get('$controller')
$httpBackend = $injector.get('$httpBackend')
const mockEnv = $httpBackend.when('GET', '/env')
.respond(mockItemsUnsorted)
const mockAPI = $httpBackend.when('GET', '/api')
.respond(mockBackupString)
const createController = function () {
return $controller('BackupFormController', { '$scope': $rootScope })
}
}))
describe('$scope.getBackup', function () {
beforeEach(function () {
spyOn(console, 'log')
})
it('should GET /api and set $scope.backups', function () {
controller = createController()
console.log('Dumping fetchStatus: ', $rootScope.fetchStatus)
$rootScope.init()
$httpBackend.flush()
expect($rootScope.backups).toEqual(mockBackupString)
expect(console.log).toHaveBeenCalled()
})
})
})
It seems like this new spec isn't working correctly at all; when I run npm test I see the normal successful tests from ./public/controllers.spec.js but also:
Chrome Headless 105.0.5195.125 (Mac OS 10.15.7) BackupFormController $scope.getBackup should GET /api and set $scope.backups FAILED
ReferenceError: createController is not defined
at UserContext.<anonymous> (backup/backupcontrollers.spec.js:51:7)
at <Jasmine>
This is the only output concerning ./public/backups/backupcontrollers.spec.js.
Has anybody run into this before? I found some posts regarding including angular-mocks, but as you can see in karma.conf.js, it's being included.

Problems initiating Web API File object in test with Babel and Jest

While trying to upgrade babel to v7 in an existing test setup with Jest and Enzyme, I have encountered a problem where Web API File is empty. Although it responds to methods like myFile.name.
Packages used:
babel => 7.6.4
jest => 24.9.0
babel-jest => 24.9.0
Not really an expert with babel, but this is my config
Babe config
const env = process.env.NODE_ENV;
const isProd = () => env === 'production';
const isDev = () => env === 'development';
const isTest = () => env === 'test';
const babelPresetEnvOptions = () => {
const options = {};
if (isTest()) {
options.targets = { node: 'current' };
} else {
// Disable polyfill transforms
options.useBuiltIns = false;
// Do not transform modules to CommonJS
options.modules = false;
}
if (isProd()) {
options.forceAllTransforms = true;
}
return options;
};
const presets = [
[require.resolve('#babel/preset-env'), babelPresetEnvOptions()],
[require.resolve('#babel/preset-react'), { development: isDev() }],
];
const plugins = [
[require.resolve('#babel/plugin-proposal-decorators'), { legacy: true }],
[require.resolve('#babel/plugin-proposal-class-properties'), { loose: true }],
require.resolve('#babel/plugin-proposal-object-rest-spread'),
require.resolve('#babel/plugin-transform-react-jsx'),
require.resolve('#babel/plugin-transform-runtime'),
];
if (isTest()) {
// Compiles import() to a deferred require()
plugins.push(require.resolve('babel-plugin-dynamic-import-node'));
} else {
// Adds syntax support for import()
plugins.push(require.resolve('#babel/plugin-syntax-dynamic-import'));
}
module.exports = api => {
api.assertVersion('^7.6');
return {
presets,
plugins,
};
};
Jest setup
"jest": {
"rootDir": "./webpack",
"setupFiles": [
"<rootDir>/test/jestsetup.js"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
"moduleNameMapper": {
"^.+\\.(css|scss)$": "identity-obj-proxy"
},
"transform": {
"^.+\\.(js|jsx)?$": "babel-jest"
}
},
Problem:
When I try to initiate a file object
const lastModified = 1511256180536;
const myImageFile = new File([''], 'pixel.gif', { type: 'image/gif', lastModified });
console.log(myImageFile); // Also results in => File {}
console.log(imageFile.name); // return 'pixel.gif'
The test snapshot fails as shown below, which I can't explain why.
- file={
- File {
- Symbol(impl): FileImpl {
- "_buffer": Object {
- "data": Array [],
- "type": "Buffer",
- },
- "isClosed": false,
- "lastModified": 1511256180536,
- "name": "pixel.gif",
- "type": "image/gif",
- Symbol(wrapper): [Circular],
- },
- }
- }
+ file={File {}}
Even a hint on this would be great.
Babel debug
#babel/preset-env: `DEBUG` option
Using targets:
{
"node": "12.11"
}
Using modules transform: auto
Using plugins:
syntax-async-generators { "node":"12.11" }
syntax-object-rest-spread { "node":"12.11" }
syntax-json-strings { "node":"12.11" }
syntax-optional-catch-binding { "node":"12.11" }
transform-modules-commonjs { "node":"12.11" }
proposal-dynamic-import { "node":"12.11" }
Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set.

Dynamic change protractor-result folder 'protractor-html-screenshot-reporter'

Here is my conf.js file.
var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
var reporter = new HtmlScreenshotReporter({
dest : '/opt/src/protractor/results/',
filename : 'index.html',
showSummary : true,
showQuickLinks : true,
showConfiguration : true,
cleanDestination : true,
ignoreSkippedSpecs : false,
reportOnlyFailedSpecs : false,
captureOnlyFailedSpecs : true,
});
exports.config = {
...
// Setup the report before any tests start
beforeLaunch: function() {
return new Promise(function(resolve){
reporter.beforeLaunch(resolve);
});
},
onPrepare: function () {
reporter.dest = '/opt/src/protractor/results/' + browser.params.directory + '/';
jasmine.getEnv().addReporter(reporter);
I would like to dynamicly change the destination directory by passing arguments :
Eg :
protractor conf.js --suite=MySuiteName --browser.params.directory=MyDirectory
All reports are generated in /opt/src/protractor/results/ instead of /opt/src/protractor/results/MyDirectory
Why I can't change Destination directory?
Thanks in advance. :)
Inside protractor-jasmine2-screenshot-reporter implement, it only read the destination folder by options.dest of the passed-in options when call new HtmlScreenshotReporter(options).
Thus changing reporter.dest won't change the destination folder when generate report files
Please try below code: (delay to init reporter instance in onPrepare, in which you can get the value of CLI argument: --browser.params.directory
var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
var reportOpts = {
dest : '/opt/src/protractor/results/',
filename : 'index.html',
showSummary : true,
showQuickLinks : true,
showConfiguration : true,
cleanDestination : true,
ignoreSkippedSpecs : false,
reportOnlyFailedSpecs : false,
captureOnlyFailedSpecs : true,
};
var reporter;
exports.config = {
onPrepare: function () {
// change reporter destination
reportOpts.dest = '/opt/src/protractor/results/' + browser.params.directory + '/';
// delay init reporter instance in onPrepare(), but beforelaunch()
reporter = new HtmlScreenshotReporter(reportOpts);
reporter.beforeLaunch(function(){
jasmine.getEnv().addReporter(reporter);
});
},
// Close the report after all tests finish
afterLaunch: function(exitCode) {
return new Promise(function(resolve){
reporter.afterLaunch(resolve.bind(this, exitCode));
});
}
};

requireJs - Jquery UI autocomplete does not work

Im getting the following error when I try to use jqueru autocomplete together with require js:
'cannot call methods on autocomplete prior to initialization; attempted to call method '/recruiter/temp-search/api/locations/get''
I have a module which initilizes my autocomplete:
define(['jqueryUi'],function($) {
function Location() {
this.autocompleteUrl = "/recruiter/temp-search/api/locations/get";
};
Location.prototype.initAutocomplete = function($txtTown, onSuccessDelegate, countryId, regionId, ignoredInputHandler, includeCountries) {
///<param name="$txtTown" type="jQuery">input text element to decorate with autocomplete</param>
///<param name="onSuccessDelegate" type="function">Invoked with upon item selection with selected value passed as a parameter</param>
///<param name="regionId" type="int">Region constraint. Defaults to null</param>
///<param name="countryId" type="int">Country Id. Defaults to UK id</param>
///<param name="ignoredInputHandler" type="function">
/// function(string term, function success(string term, {data, result, value}[] data), function failure(string term)) delegate
/// that is invoked on autocomplete requests before user input at leaset 2 chars
///</param>
var cId = countryId ? countryId : null;
var rId = regionId ? regionId : null;
var inclCountries = includeCountries === undefined ? false : includeCountries;
var onSuccess = onSuccessDelegate ? onSuccessDelegate : function() {};
$txtTown.autocomplete(this.autocompleteUrl, {
dataType: 'json',
parse: function(data) {
/* validation Location*/
/*To remove error field check on the parentsearch.js self.elements.searchLocation.on('keyup'*/
if ($txtTown.selector === "#Location") {
if (data.Locations.length == 0 && !data.IsPostcode && $txtTown.val().length > 0) {
var locationError = "We couldn't find the location you entered";
jQuery("[data-valmsg-for = 'Location']").text(locationError);
$('#Location').closest('.search-row').find('.search-error').show();
} else {
jQuery("[data-valmsg-for = 'Location']").text("");
}
}
/**/
var rows = [];
if ($.isArray(data.Locations)) {
var locations = data.Locations;
if (locations !== null) {
for (var i = 0; i < locations.length; i++) {
rows[i] = { data: locations[i], value: locations[i], result: locations[i] };
}
}
} else {
if (data.IsPostcode) {
onSuccess(data.Location, data.Postcode);
}
}
return rows;
},
extraParams: { countryId: cId, regionId: rId, includeCountries: inclCountries },
formatItem: function(row) { return row; },
width: 'auto',
minChars: 2,
delay: 100,
max: 10,
ignoredInputHandler: ignoredInputHandler,
selectFirst: false,
cacheLength: 1,
scroll: false
}).result(function(event, row) {
onSuccess(row);
});
};
return new Location();
});
It is being called like this:
location.initAutocomplete(this.elements.searchLocation, onSuccessAutocomplete, undefined, undefined, undefined, true);
here is my config file:
require.config({
paths: {
"JqueryAutocomplete": "../scripts/jquery/plugins/jquery.autocomplete",
"jqueryValidate": "../scripts/jquery/plugins/jquery.validate",
"jqueryUi": "../scripts/jquery/plugins/jquery-ui-1.10.3.custom",
"jquery": "../scripts/jquery/jquery-1.9.1",
"knockout": "../scripts/knockout/knockout-2.3.0",
"ko": "common/knockout-extensions"
},
shim: {
"JqueryAutocomplete": {
exports: "$",
deps: ['jquery']
},
"jqueryValidate": {
exports: "$",
deps: ['jquery']
},
"jqueryUi": {
exports: "$",
deps: ['jquery']
},
"knockout-extensions": {
exports: "knockout",
deps: ['knockout']
}
}
});

node assetmanager with more modules

I'm trying to set up assetmanager
for my blog that has three modules
default
login
admin
I tried like
assets.json
{
"css": {
"app":{
"public/src/dist/default/css/dist.min.css": [
"public/src/assets/default/css/*.css"
]
},
"login":{
"public/src/dist/login/css/dist.min.css": [
"public/src/assets/default/css/*.css"
]
},
"admin":{
"public/src/dist/admin/css/dist.min.css": [
"public/src/assets/admin/css/*.css"
]
}
}
}
express.js
assetmanager.init({
js: assets.js,
css: assets.css,
debug: (process.env.NODE_ENV !== 'production'),
webroot: 'public'
});
// Add assets to local variables
app.use(function(req, res, next) {
res.locals({
assets: assetmanager.assets
});
next();
});
console.log(assetmanager.assets);
but console.log(assetmanager.assets);
give me a empty array []
so is there a way to manage assetmanager
with more than one module ?
the best way I found up to now
is like in my controllers:
'use strict';
var assetmanager = require('assetmanager');
exports.render = function(config) {
var assets = require(config.sroot+'/config/assets.json');
assetmanager.init({
js: assets.js.app,
css: assets.css.app,
debug: (process.env.NODE_ENV !== 'production'),
webroot: 'public'
});
return function(req, res) {
res.render('layouts/default', {appTitle:'ilwebdifabio',assets:assetmanager.assets});
}
};
but it's quite ugly and I have
duplicate code :(
END UP
There is no way to use assetmanager module
in different modules (login,default,admin).
Modules are automatically cached by the Node.js application upon first load. As such, repeated calls to require() - the global method that loads modules - will all result in a reference to the same cached object.
so you end up ie if you use in a module
to the have the dedicate assets in all other module so
I worked it out with :
'use strict';
var _ = require('lodash');
module.exports = function (path,route) {
var env = (process.env.NODE_ENV === 'production') ? 'production' : null;
var debug = (env !== 'production');
var data = require(path+'/config/assets.json');
var assets = {
css: [],
js: []
};
var getAssets = function (pattern) {
var files = [];
if (_.isArray(pattern)) {
_.each(pattern, function (path) {
files = files.concat(getAssets(path));
});
} else if (_.isString(pattern)) {
var regex = new RegExp('^(//)');
if (regex.test(pattern)) {
// Source is external
//For the / in the template against 404
files.push(pattern.substring(1));
} else {
files.push(pattern);
}
}
return files;
};
var getFiles = function () {
var current = data[route];
_.each(['css', 'js'], function (fileType) {
_.each(current[fileType], function (value, key) {
if (!debug) {
assets[fileType].push(key);
} else {
assets[fileType] = assets[fileType].concat(getAssets(value));
}
});
});
};
var getCurrentAssets = function(){
return assets;
};
getFiles();
return {
getCurrentAssets: getCurrentAssets
};
};
in the controller
var assetmanager = require(config.sroot+'/utils/assetsmanager')(config.sroot,'app');
res.render('layouts/default', {
assets:assetmanager.getCurrentAssets()
});
There is a new version of assetmanager 1.0.0 that I believe accomplishes what you're trying to do more effectively. In the new version you can break apart your assets into groups so that you can support multiple layouts. The github has a complete example here but essentially your asset files ends up looking something like this:
{
"main": {
"css": {
"public/build/css/main.min.css": [
"public/lib/bootstrap/dist/css/bootstrap.css",
"public/css/**/*.css"
]
},
"js": {
"public/build/js/main.min.js": [
"public/lib/angular/angular.js",
"public/js/**/*.js"
]
}
},
"secondary": {
"css": {
"public/build/css/secondary.min.css": [
"public/css/**/*.css"
]
},
"js": {
"public/build/js/secondary.min.js": [
"public/js/**/*.js"
]
}
}
}
And then in your layouts you just include the group you want. Hopefully that helps out.

Resources