Webpack: Loading external JSON without bundling - javascript

I'm building my first one-page site using redux + deku and I need to internationalize it. I want to have a json file with all the texts, something like this:
# http://mysite.me/assets/i18n.json
{
"en": {
"greeting": "Hello"
},
"es": {
"greeting": "Hola"
}
}
Ideally I can require it in my boot file:
const T = require('/assets/i18n.json')
setTranslation(T)
But it mustn't be bundled in the same file, it should remain an external dependencies and it should load at runtime, so that I can edit it without needing to recompile the entire app!
Is it possible with webpack? Is my only option to include it directly in the HTML?
<script type="text/javascript" src="i18n.js"></script>
<script type="text/javascript" src="app.js"></script>
For now this last solution is ok, but I was thinking on splitting the translations per main components, therefore the ability to include it directly through js would be nice.
Thanks to anyone who will help :)

One option would either to not require the file but instead fetch (or some other request method) and then exclude JSON from webpack.
The other way would be to split the code using the common chunks plugin for webpack. Your webpack config would look something like this:
entry: {
app: './index.jsx',
i18n: [
'en',
'fr',
'...others'
]
},
output: {
path: '/path/to/dist/',
filename: '[name].js'
}
See the official docs for more information

Related

webpack: How to inject the JS chunks in the a YAML file

I'm using webpack to modernize a legacy MVC application (symfony 1.4)
I would like to inject the JS chunks and the CSS file in a YAML file that contains several other settings.
Here is an example:
default:
foo: bar
.
.
stylesheets: [ style.db80006f5e14f38456ef.css ]
javascripts: [ runtime.d8969ec83f67a36c8877.js, npm.material.db07856eff6817abe7f2.js, main.db80006f5e14f38456ef.js ]
.
.
The html-webpack-plugin supports plugin as well. I was wondering if it would be possible with my own plugin for the html-webpack-plugin to inject the CSS files and JS files in a YAML file instead of an HTML template. I'm not sure if the html-webpack-plugin is the way to go since I don't want to manipulate an HTML file.
Maybe there is another possibility to get the names and the order of the JS chunks, plus the CSS file.
Thanks a lot in advance!
html-webpack-plugin is the way to go, you can provide your "base" yaml file as a template, and provide a templateContent function that will generate your yaml content.
Something like this:
new HtmlWebpackPlugin({
templateContent: function(params) {
return `
default:
stylesheets: [ ${params.htmlWebpackPlugin.files.css.join(',')} ]
javascripts: [ ${params.htmlWebpackPlugin.files.js.join(',')} ]
`;
},
filename: 'path-to/where/to/save/your.yaml',
inject: false, // prevents from the plugin to auto-inject html tags
});

Importing JS files outside Webpack

So, i have a script that creates a global object
(function() {
window.GlobalThing = {}
})();
This script will also fill this object attributes
if (!GlobalThing .Resource) { GlobalThing .Resource = require('./Resource'); }
Then, some other scripts that are not bundled with webpack need to use this GlobalThing. I`ve tryed to make it global using ProvidePlugin for example:
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
'GlobalThing': path.join(__dirname,"Path/GlobalThing.js")
})
],
I've tryed adding an Alias as well
resolve: {
alias: {
'GlobalThing': path.join(__dirname,"Path/GlobalThing.js")
}
}
I have tryed doing something like this in the end of my GlobalThing.js file as well:
(function(){
window.GlobalThing = GlobalThing;
})();
Then i had to import to run the script, so i got a random js file inside the webpack to test it:
import GlobalThing from "GlobalThing ";
Still, it seems some scripts cannot seethe GlobalThing. If i bundle everything up with webpack, it works, but i didnt want to as our app is very old and have some very old stuff. Is there a way i can expose GlobalThing to those older scripts ?
ProvidePlugin takes a module name (i.e. string) and internally uses require to load it. So that wont help you in loading your own script.
That said, following should work:
Keep the GlobalThing script out of webpack bundling
Make sure the script itself is copied to the output folder
Make sure the index.html (or whatever html page you are using) has the scripts in the order GlobalThingScript.js followed by webpack bundle.js
To give you more insight:
When webpack bundles the scripts other than GlobalThingScript.js, it doesnt even know there is something called GlobalThing. It just bundles the other files.
That would mean it is upto you to make sure the GlobalThingScript.js is also made it to the final output folder. Also, the html source should use <script> tags to include the GlobalThingScript.js before webpack bundle.js.
In case problem persists, please do edit the OP to include the html source.
Hope that helps.

Webpack to simply compile a bunch of Pug templates to HTML

Im getting started with webpack but one thing I cannot for the life of me work out is how to take a folder (with possible nested folders), full of .pug templates, and simply compile them to static html and put them in the output folder, maintaining any nested folder structure for each output html file that was in the source templates folder...
I dont want to have to manually specify each individual .pug file, and I definitely dont want webpack to try and parse the .pugs into JS and then attempt to require/import any of the imgs/fonts etc in the pug files and then complain about it, Im just after a basic, static 1:1 compile, pug file in, html file out. Why is it so hard to do that?
Use pug-html-loader to convert .pug to .html file. Use file-loader to copy the file to desired location. Don't use html-loader as you don't want to process resources used by the generated file.
You will end up something like this in your loader rules (untested, webpack 1 syntax, you may need to tweak it for webpack 2)
{
test: /\.pug$/,
loaders: ['file-loader?name=[path][name].html', 'pug-html-loader?pretty&exports=false']
}
Next you need to require all your pug files in your entry file
function requireAll (r) { r.keys().forEach(r); }
requireAll(require.context('./', true, /\.pug$/));
This can be done very simply with only html-webpack-plugin and pug-loader.
webpack.config.js
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// No javascript entrypoint to evaluate. Let the plugin do the heavy lifting
entry: {},
// Translate Pug to HTML
module: { rules: [ { test: /\.pug$/, use: 'pug-loader' } ] },
// Save HTML to file
plugins: [ new HTMLWebpackPlugin({ template: './src/index.pug' }) ]
};
./src/index.pug
doctype html
html(land="en")
head
include path/to/another.pug
...
Got this information from https://extri.co/2017/05/23/using-htmlwebpackplugin-and-pug/ and you can also go further to import css and javascript as normally done with html-webpack-plugin.

Systemjs builder remove file extension

I have couple of es6 modules. add.js, sub.js and calc.js.
calc.js imports add.js and sub.js.
I am building them with grunt and SystemJS builder. My grunt configuration for this looks like -
systemjs: {
es6: {
options: {
baseURL: "/",
configFile: "config.js",
},
files: [{
"src": ["src/main/calc.js"],
"dest": "dist/calc.js"
}]
}
}
Once the grunt build is done, it creates the resultant calc.js and in that file I can see this :
System.register("src/main/calc.js", [..
..................
I don't want the .js in that name. I want it something like :
System.register("src/main/calc", [..
What should I do? Am I missing some configuration ?
This naming behavior is by design. bundle() creates a bundle for SystemJs to use in the browser, so the names must match the file names that SystemJs will be attempting to load. If you are trying to avoid SystemJs in the browser, buildStatic() is what you are looking for.
There is paths option for the builder.
paths: {
"src/main/calc": "src/main/calc.js"
}
FYI, there is map option. I thought map would be the option for the purpose but it never worked for me.

Require.js to load same script on multiple pages

I'm just learning about Require.js. Lets say I have the following pages:
pageA.html
pageB.html
For page A, I need to load the following scripts:
taco.js
hamburger.js
For page B, I need to load the following scripts:
taco.js
salad.js
superman.js
In order to do this using basic require.js loading, I think I would do this:
<!-- pageA.html contains:
<script data-main="/scripts/pageAScripts" src="/scripts/require.js"></script>
which is:
// pageAScripts.js
require(["/scripts/taco", "/scripts/hamburger"]);
and also
<!-- pageB.html contains:
<script data-main="/scripts/pageBScripts" src="/scripts/require.js"></script>
which is:
// pageBScripts.js
require(["/scripts/taco", "/scripts/salad", "/scripts/superman"]);
So now I have a main entry point for each page. But what I'm worried about is using taco.js in multiple places. Because when I use require.js's Optimizing solution in my build script, it creates pageAScripts.js (containing taco.js, hamburger.js) and pageBScripts.js (containing taco.js, salad.js and superman.js).
So now the code for taco.js is loaded twice for the user through the "optimization" process. In my case, taco.js is a pretty large file and having the user end up downloaded the data twice is undesirable.
What am I missing about the workflow here? I'm still pretty new to require.js so I'm sure there is something.
You can use the example of the multipage project. Adapting the RequireJS build config there to yours:
{
baseUrl: '.',
dir: '../build', // This is where the output will go.
modules: [
{
name: 'scripts/taco'
},
{
name: 'scripts/pageAscripts',
exclude: ['scripts/taco']
},
{
name: 'scripts/pageBscripts',
exclude: ['scripts/taco']
}
]
}
This is a minimal adaptation of what the multipage project example provides. At the end of the build you'll have 3 bundles: build/scripts/pageAscripts that contains code only for page A, build/scripts/pageBscripts that contains code only for page B, and build/scripts/taco that contains only the taco module and all its dependencies.
You can load taco.js as separate file and in build file tell requirejs to not to include taco.js as part of build file.
In you require config specify the path for taco.js -
requirejs.config({
paths: {
'taco': 'path/to/taco'
}
});
And require taco.js in your pageAScript.js and pageBScript.js as follows -
require(['taco'], function (taco) {
});
And in your build file tell requirejs not to include taco as part of build file using empty:
({
baseUrl: ".",
name: "page(A/B)Script",
out: "page(A/B)Script.js",
paths: {
taco: "empty:"
}
})
You can find more about this here.
And now you can load the taco.js on pageA.html and pageB.html using script tag.
<script type="text/javascript" src="path/to/taco/js"></script>
Here taaco.js will be loaded for first page and for second page it will be loaded from browser cache.

Categories

Resources