Refer to static json data from javascript and grunt - javascript

I have some const values, which are used throughout the application as well as by jade for static code generation.
I was defining the data in file (const.js) as below.
my.const = (function () {
return {};
}());
my.const.testType = Object.freeze({
main: {key: 1, value: "Main"}
});
I include this file with script tag, and the variables are accessible to my application.
But, I do not find a way to read this file, and access the data object, my.const in jade. For that, I have to create a json file and configure grunt as
jade: {
dist: {
options: {
pretty: true,
data: function(dest, src) {
console.log(dest, src);
return grunt.file.readJSON('app/const.json');
}
},
files: [...
I use grunt-contrib-jade plugin.
I cannot use const.js as it needs to be a valid json file (api). So, I have to keep and maintain 2 files (js and json) with same data. How can I either
read the js file (const.js) with grunt and access the data (my.const) OR
include the data from json file, statically so that scripts below can acccess the data. Simply including json file gives error (Uncaught SyntaxError: Unexpected token :)
or is there a better way (any grunt plugin to generate the js file, ...). I cannot think any.
Thanks.

Assuming you are using node js, in your const.js file, add at the bottom:
.
.
if(module && module.exports) {
module.exports = m;
}
At the top of your grunt file, require the const.js file:
var m = require('../path/to/const.js');
And then, in your grunt configuration data function:
data: function(dest, src) {
console.log(dest, src);
return m;
}

Related

Can't resolve css url from webpack asset librarymodule

I was able to output an assets library and many other libraries that work as remote federated modules and as deep import libraries in case I am not connecting to a remote or I am not using webpack in the consumer end.
The issue is now that all my assets exports a module, that either have the raw data as uri or the string that points to the right asset. Eg: the bird.svg is outputed to dust with it's hash plus the modules that resolves to the file bird-[hash].svg.
The above is great from javascript but not so much for css. Now I can't rewrite the url() to point to the right remote path which would be sg like:
//since I don't know when the assets will change names I can't refer to it directly. So I would need to first read the string from the bird.js module. Append the publicPath and then rewrite the url.
.someClass {
background-image: url('/assets/bird.js')
}
//the above won't work for obvious reasons.
Só, the question is how can I solve this? Or is there any loader for this? I checked the resolve url loader but it does not seem to be what need.
Ok I resolved this issue, by passing additional data as variable to sass-loader. That way I can evaluate the actual name of the files, and put it as a sass map before and handle it from sass.
//I am using glob to return an object with all the assets.
//This can probably be automated better. That would be an easier way.
//But this way works for me in all 3 scenarios, node, browser and federated module.
//Also has caching ootb for the assets.
const assetsPaths = {
...glob.sync('../assets/dist/img/**.node.js').reduce(function (obj, el) {
obj['img/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {}), ...glob.sync('../assets/dist/fonts/**.node.js').reduce(function (obj, el) {
obj['fonts/' + path.parse(el).name] = '../../assets/dist/' + require(el).default;
return obj
}, {})
};
//...
{
loader: 'sass-loader',
options: {
additionalData: "$assets: '" + assetsMap + "';",
sourceMap: true,
sassOptions: {
outputStyle: "compressed",
},
}
},
//...
you also need to disable url rewriting
{
loader: 'css-loader',
options: {
url: false,
}
},
then you can use assets map in your sass files:
#font-face {
font-family: 'Some Font';
src: local('Some Font');
src: url("#{map-get($assets, SomeFont)}");
}
You will need probably have your project setup sort like a mono repo and you also need to build those assets library with two bundles.
One for node so you can use the string path to your actual assets when bundling you sass/whatever.
And another for normally loading it from the browser.
update:
Instead of doing all this I just used the manifest generated from 'webpack-manifest-plugin' to build the $assets map to be used in sass.
const assetsManifest = JSON.parse(fs.readFileSync('../assets/dist/manifest.json'));
const assetsMapFn = asset => `'${asset[0]}':'${asset[1]}'`;
const assetsMap = `(
${Object.entries(assetsManifest).map(assetsMapFn).join(',')}
); `;
If anyone knows a better way to do this please reply or comment.

How to dynamically require JSON files in Webpack?

I have a bunch of json files that I need to dynamically require:
export const allLanguages = R.fromPairs(availableLanguages.map(language => {
return [
language,
{
translation: require('./' + language + '.json'),
formats
}
] as [Language, any]
}))
But I get Error: Cannot find module './ar.json' when running webpack --watch, and I can see that the json files have not been copied to the build directory.
So I tried adding {from: 'common/i18n/*.json'} to CopyWebpackPlugin arguments, and now the json files are copied to the correct place, but I still get Error: Cannot find module './ar.json' when running webpack --watch. It seems they are copied after the build, not before it, and hence the error.
There seems to be feature request for allowing copying files before the build for CopyWebpackPlugin: https://github.com/webpack-contrib/copy-webpack-plugin/issues/195
What is the correct way to handle this in Webpack?

Using RequireJS with node to optimize creating single output file does not include all the required files

I use the FayeJS and the latest version has been modified to use RequireJS, so there is no longer a single file to link into the browser. Instead the structure is as follows:
/adapters
/engines
/mixins
/protocol
/transport
/util
faye_browser.js
I am using the following nodejs build script to try and end up with all the above minified into a single file:
var fs = require('fs-extra'),
requirejs = require('requirejs');
var config = {
baseUrl: 'htdocs/js/dev/faye/'
,name: 'faye_browser'
, out: 'htdocs/js/dev/faye/dist/faye.min.js'
, paths: {
dist: "empty:"
}
,findNestedDependencies: true
};
requirejs.optimize(config, function (buildResponse) {
//buildResponse is just a text output of the modules
//included. Load the built file for the contents.
//Use config.out to get the optimized file contents.
var contents = fs.readFileSync(config.out, 'utf8');
}, function (err) {
//optimization err callback
console.log(err);
});
The content of faye_browser.js is:
'use strict';
var constants = require('./util/constants'),
Logging = require('./mixins/logging');
var Faye = {
VERSION: constants.VERSION,
Client: require('./protocol/client'),
Scheduler: require('./protocol/scheduler')
};
Logging.wrapper = Faye;
module.exports = Faye;
As I under stand it the optimizer should pull in the required files, and then if those files have required files, it should pull in those etc..., and and output a single minified faye.min.js that contains the whole lot, refactored so no additional serverside calls are necessary.
What happens is faye.min.js gets created, but it only contains the content of faye_browser.js, none of the other required files are included.
I have searched all over the web, and looked at a heap of different examples and none of them work for me.
What am I doing wrong here?
For anyone else trying to do this, I mist that on the download page it says:
The Node.js version is available through npm. This package contains a
copy of the browser client, which is served up by the Faye server when
running.
So to get it you have to pull down the code via NPM and then go into the NPM install dir and it is in the "client" dir...

Embed resources in kotlin js

In kotlin jvm (or in java, for what it matter) one can read resource content through the resource input stream.
Is there a way to do it in kotlin js?
Right now I'm requesting the resource with an ajax call but It would be best to have the resources automatically embedded in the compiled javascript to avoid further server roundtrips.
I'm aware of the triple quote string literal but It's not what I'm looking for.
Thanks for your suggestions
You may add embedded data to javascript file by webpack.
For example:
1) add file test.json to directory src/main/resources with content:
{
"test123": 123
}
2) add directory src/main/resources to be resolve modules in webpack:
resolve: {
modules: [
path.resolve("src/main/resources")
]
}
3) add to main method code:
//require is external function: "external val require: dynamic"
println(JSON.stringify(require("test.json")))
And in output you will see: {"test123":123}
If you open webpack bundle, you will see that full file content of test.json is embedded to it like this:
function(t){t.exports={test123:123}}
Here's what I did to include svg files embedded in the JS file in Kotlin 1.5.31 + Webpack 5. Let's suppose we have a SVG file named star.svg in your src/jsMain/resources folder.
Project Root Folder/webpack.config.d/files.js (The files.js name doesn't matter)
config.module.rules.push(
{
test: /\.(svg)$/i,
type: 'asset/source'
}
);
Then in your code...
#JsModule("./star.svg")
#JsNonModule
external val star: dynamic
fun main() {
console.log(star)
}
The print output is the contents of the star.svg file!
If you are curious about other available "type", check out https://webpack.js.org/guides/asset-modules/

Ordening files in Grunt with external file

I'm configuring Grunt with grunt-contrib-concat to concatenate like 20 javascript files. They have to be in a specific order and I'm wondering if there is a neat way to do this, without messing up my Gruntfile.js.
What I did and what worked well, was declaring an variable called 'libraries' with a function which returned a string with all the files in the right order.
var libraries = new (function () {
return [
'/javascript/libs/jquery.min.js',
'/javascript/libs/jquery.address.js',
'/javascript/libs/jquery.console.js'
];
});
And then concat (simplified, just an example):
concat: {
libs: {
files: {
'libs.js' : [libraries],
},
},
main: {
files: {
'main.js' : [main]
}
}
},
So when I call 'libraries' in my task configuration everything works fine, but I would like to declare this list in a separate file.
Unfortunately I couldn't find anything, nor do I know if this is even possible. Hope that someone could help me out! Thanks in advance :-)
I found a solution! Since Grunt is build on NodeJS, it's possible to use module.exports. What I did was setting an external file called libraries.js, which is in my Grunt directory.
var exports = module.exports = {};
exports.customLibrary = function () {
return [
// Path to a library
// Path to another library
// and so on...
];
};
exports.mainScripts = function () {
return [
// Path to a library
// Path to another library
// and so on...
];
};
Then I import this module by declaring a variable in Gruntfile.js
var libraries = require('../javascript/libraries.js');
To use the methods declared in libraries.js I set two more variables which returns a string with all the necessary files in the desired order:
var customLibrary = libraries.customLibrary();
var mainScripts = libraries.mainScripts();
I use these variables to define the source in the concat task. Hope this is helpful!

Categories