System.js builder.buildStatic just outputs the filename - node.js

I have just simplified the source file to below, which works fine when I use System.import in a script tag.
import angular from "angular";
angular.element(document).ready(function () {
alert('Hello word');;
});
Below is my config.js
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "typescript",
paths: {
"npm:": "jspm_packages/npm/"
},
map: {
"angular": "npm:angular#1.5.2",
"typescript": "npm:typescript#1.8.9"
}
});
I have a gulp task to build it:
gulp.task('bundle:js', ['clean:js'], function () {
var builder = new Builder();
builder.loadConfig('./config.js').then(function () {
var destination = paths.coreJsDest;
builder.buildStatic(paths.srcRoot + 'js/ng/homepage', destination, {
minify: false,
sourceMaps: false,
runtime: false
});
});
});
But the output file contains the file name rather than JavaScript from the file and its imports:
(["1"], ["1"], function($__System) {
})
(function(factory) {
if (typeof define == 'function' && define.amd)
define(["D:/Projects/etc-etc/assets/js/ng/homepage.js"], factory);
else if (typeof module == 'object' && module.exports && typeof require == 'function')
module.exports = factory(require("D:/Projects/etc-etc/js/ng/homepage.js"));
else
throw new Error("Module must be loaded as AMD or CommonJS");
});

Doh, I just needed to change the baseUrl from "/" to "./".

Related

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.

SSR React - Load Class Names Before bundle.js loads

I am attempting to create a SSR react app with Firebase hosting and Cloud Functions. My components are using className to declare classes. My server-rendered html does not include these, it only has the data-reactid elements.
It is not until the bundle.js is loaded that the real class="example-class" is loaded.
I do not want to wait for the bundle.js to download before the classes are loaded. I'd rather not code with both
class="kitten-image" className="kitten-image"
because that seems like a waste. I have not been able to find anything that either transforms the CSS files to have the data-reactid identifiers, or to automatically include the class="kitten-image" on the server-side during the compile process with babel.
Overview: My server-side compiled code injects the babel compiled react components into an index.html template file, which is sent via express app on http request on Firebase functions. The index.html file includes hard-coded references to the webpack processed styles.css and bundle.js in the firebase hosting public folder.
Thus, my server-side rendered HTML should immediately be able to reference the styles.css sheet - however, the classes are not in the html until the bundle.js is loaded (which is the problem).
Server-side rendered HTML before bundle.js loads
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>React Server Side Rendering - Firebase Hosting</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="root"><div data-reactroot="" data-reactid="1" data-react-checksum="1473597379"><h1 data-reactid="2">Hello World!</h1><p data-reactid="3"><!-- react-text: 4 -->This is a kitten: <!-- /react-text --><br data-reactid="5"/><img src="/media/kitten.jpg" alt="Kitten" data-reactid="6"/></p></div></div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
HTML after bundle.js loads
Note that class="kitten-image" has been added.
<!DOCTYPE html>
<html><head>
<meta charset="UTF-8">
<title>React Server Side Rendering - Firebase Hosting</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="root"><div data-reactroot="" data-reactid="1"><h1 data-reactid="2">Hello World!</h1><p class="intro" data-reactid="3"><!-- react-text: 4 -->This is a kitten: <!-- /react-text --><br data-reactid="5"><img src="/media/kitten.jpg" alt="Kitten" class="kitten-image" data-reactid="6"></p></div></div>
<script type="text/javascript" src="bundle.js"></script>
</body></html>
Folder Structure
App Component Example
see className
import React, { Component } from 'react';
import kitten from "./kitten.jpg";
import "./App.scss";
class App extends Component {
render() {
return (
<div class="main">
<h1>Hello World!</h1>
<p className="intro">This is a kitten: <br /><img src={kitten} alt="Kitten" className="kitten-image" /></p>
</div>
);
}
}
export default App;
Babel Compiled Component
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var kitten = "/media/kitten.jpg";
var App = function (_Component) {
_inherits(App, _Component);
function App() {
_classCallCheck(this, App);
return _possibleConstructorReturn(this, (App.__proto__ || Object.getPrototypeOf(App)).apply(this, arguments));
}
_createClass(App, [{
key: "render",
value: function render() {
return _react2.default.createElement(
"div",
{ "class": "main" },
_react2.default.createElement(
"h1",
null,
"Hello World!"
),
_react2.default.createElement(
"p",
null,
"This is a kitten: ",
_react2.default.createElement("br", null),
_react2.default.createElement("img", { src: kitten, alt: "Kitten" })
)
);
}
}]);
return App;
}(_react.Component);
exports.default = App;
Server index.js
import React from "react";
import { renderToString } from "react-dom/server";
import App from "../shared/App";
import express from "express";
import * as fs from "fs";
import * as functions from "firebase-functions";
const index = fs.readFileSync(__dirname + '/../../index.template.html', 'utf8');
const app = express();
app.get('**', (req, res) => {
const html = renderToString(<App />);
const finalHtml = index.replace('<!-- ::APP:: -->', html);
res.set('Cache-Control', 'public, max-age=600, s-maxage=1200');
res.send(finalHtml);
});
export let ssrapp = functions.https.onRequest(app);
//app.listen(3006, () => { console.log('Listening on 3006.'); });
Server index.js babel compiled
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ssrapp = undefined;
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _server = require("react-dom/server");
var _App = require("../shared/App");
var _App2 = _interopRequireDefault(_App);
var _express = require("express");
var _express2 = _interopRequireDefault(_express);
var _fs = require("fs");
var fs = _interopRequireWildcard(_fs);
var _firebaseFunctions = require("firebase-functions");
var functions = _interopRequireWildcard(_firebaseFunctions);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var index = fs.readFileSync(__dirname + '/../../index.template.html', 'utf8');
var app = (0, _express2.default)();
app.get('**', function (req, res) {
var html = (0, _server.renderToString)(_react2.default.createElement(_App2.default, null));
var finalHtml = index.replace('<!-- ::APP:: -->', html);
res.set('Cache-Control', 'public, max-age=600, s-maxage=1200');
res.send(finalHtml);
});
var ssrapp = exports.ssrapp = functions.https.onRequest(app);
//app.listen(3006, () => { console.log('Listening on 3006.'); });
Webpack
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const autoprefixer = require("autoprefixer");
const extractSass = new ExtractTextPlugin({
filename: "public/styles.css",
disable: process.env.NODE_ENV === "development"
});
// Webpack settings unique to browser-side script
const browserConfig = {
entry: './src/browser/index.js',
devtool: "source-map",
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: [/\.svg$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: "file-loader",
options: {
name: "public/media/[name].[ext]",
publicPath: url => url.replace(/public/, "")
}
},
{
test: /\.scss$/,
use: extractSass.extract({
use: [
{ loader: 'css-loader', options: { sourceMap: true } },
{
loader: 'postcss-loader',
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
ident: 'postcss',
sourceMap: true,
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
{ loader: 'sass-loader', options: { sourceMap: true } }
],
// use style-loader in development
fallback: "style-loader"
})
}
]
},
plugins: [
extractSass
],
output: {
filename: './public/bundle.js',
path: __dirname
}
}
module.exports = [browserConfig];
I was initially using Babel because I was having issues compiling via webpack with the Google Cloud / firebase modules. It was trying to bundle in everything unnecessarily.
I created a separate webpack server-side configuration. This does a few things to work correctly.
1.I'm using the "webpack-node-externals" package which is designed to exclude node modules for backend compilation. Without this, my generated JS file was enormous. My backend has a whole node_modules folder, so it does not need these items bundled.
2.I added the false statements to __dirname and __filename - I don't know what this does or how it works, but it fixed my issue with opening and reading my html template file server-side.
3.The file-loader does not actually copy the files, with emit: false
The Real Fix: The .scss tester uses css-loader/locals This was key! It generates the correct class names on the server and places them in the components when rendering! It also does not bundle / copy and files in this configuration, since the browser side config does that.
I was using the following plugin in my .babelrc file with the babel compile method. This breaks the image / file transfer process in webpack and must be removed from .babelrc
"plugins": [["transform-assets-import-to-string", {
"baseDir": "",
"baseUri": "/media"
}]],
Revised Webpack
const serverConfig = {
entry: "./src/server/index.js",
target: "node",
externals: [nodeExternals()], // exclude node_modules
node: {
__dirname: false,
__filename: false
},
output: {
filename: "./functions/src/server/server.js",
libraryTarget: "commonjs2"
},
module: {
rules: [
{
test: [/\.svg$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: "file-loader",
options: {
name: "public/media/[name].[ext]",
publicPath: url => url.replace(/public/, ""),
emit: false
}
},
{
test: /\.scss$/,
use: [
{ loader: 'css-loader/locals' },
{ loader: 'sass-loader' }
]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
}
};

Cannot set property '__UglifyJsPlugin' of undefined

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.

require.js listener or callback

I am loading a 3rd party script that simply creates an overlay on a site it has been loaded onto. It works fine but sites using require.js seem to have intermittent issues I'm assuming with async loading some js files. Is there any type of callback or way to create a module in the DOM as sort of a listener to see if require.js is done loading?
I tried this but not even close:
define(function() {
alert('test');
return {};
});
and
define('myModule',
function () {
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
};
return myModule;
});
console.log(myModule);
I ended up just creating a secondary require.config file and loading the module with require if require is detected, seems to work fine.
if(typeof require === 'function') {
var base = 'http://' + someDomainVar;
function getJSTreeURL() {
var url = base + '/js/libs/jstree.min';
return url;
}
function getModuleURL() {
var url = base + '/module';
return url;
}
var reqTwo = require.config({
context: "instance2",
baseUrl: "instance2",
paths: {
'jq': 'http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min',
'jqTree': getJSTreeURL(),
'module': getModuleURL()
},
shim: {
'jq': {
exports: 'jq'
},
'jqTree': {
deps: ['jq'],
exports: 'jqTree'
},
'module': {
deps: ['jq', 'jqTree'],
exports: 'module'
}
}
});
reqTwo(['require', 'jq', 'jqTree'],
function(require, jq, jqTree) {
setTimeout(function() {
require(['module'],
function(module) {
console.log('loaded');
}
);
}, 0);
});

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