How to create a Fusebox project with multiple html pages? - bundle

I'm new to bundlers and am currently learning about Fusebox. I really like it so far except that I can't figure out how to use it for a multi-page project. So far I've only been able to find a tutorial on how to do this using webpack, not for fusebox.
Input files in src folder:
index.html
index2.html
index.ts
Desired output in dist folder:
app.js
vendor.js
index.html
index2.html
Actual output in dist folder:
app.js
vendor.js
index.html
Here is my config in the fuse.js file:
Sparky.task("config", () => {
fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
hash: isProduction,
sourceMaps: !isProduction,
plugins: [
[SassPlugin(), CSSPlugin()],
CSSPlugin(),
WebIndexPlugin({
title: "Welcome to FuseBox index",
template: "src/index.html"
},
WebIndexPlugin({
title: "Welcome to FuseBox index2",
template: "src/index2.html"
},
isProduction && UglifyJSPlugin()
]
});
// vendor should come first
vendor = fuse.bundle("vendor")
.instructions("~ index.ts");
// out main bundle
app = fuse.bundle("app")
.instructions(`!> [index.ts]`);
if (!isProduction) {
fuse.dev();
}
});
Setting WebIndexPlugin twice within plugins doesn't work. What is the correct way to set up a multi-html page project with fusebox?

The WebIndexPlugin can not be configured, to output more than one html file.
But if you don't use a hash for the generated bundles (e.g.: output: "dist/$name.$hash.js"), you don't need the WebIndexPlugin -- you can remove it completly from the plugins option. Because you already know the names of the generated bundles (vendor.js and app.js) you can just include the following lines
<script src="vendor.js"></script>
<script src="app.js"></script>
instead of the placeholder $bundles.
If you want, that both html files are copied from your src directory into your dist directory, you can add the following lines to your fuse.js script:
const fs = require('fs-extra');
fs.copySync('src/index.html', 'dist/index.html');
fs.copySync('src/index2.html', 'dist/index2.html');
Note: Don't forget to add fs-extra:^5.0.0 to your package.json

Might not been the case when the question was asked, but WebIndexPlugin now can be specified multiple times and also takes optional bundles parameter where list of bundles to be included in html can be specified (all bundles are included by default).
For example 2 html files (app1.html, app2.html) where each includes a common library (vendor.js), and different entry points (app1.js and app2.js)
app1.html
vendor.js
app1.js
app2.html
vendor.js
app2.js
Config would look like this:
const fuse = FuseBox.init({
homeDir : "src",
target : 'browser#es6',
output : "dist/$name.js",
plugins: [
WebIndexPlugin({
target: 'app1.html',
bundles:['vendor', 'app1']
}),
WebIndexPlugin({
target: 'app2.html',
bundles:['vendor', 'app2']
})
]
})
// vendor bundle, extracts dependencies from index1 and index2:
fuse.bundle("vendor").instructions("~[index1.ts,index2.ts]")
// app1 and app2, bundled separately without dependencies:
fuse.bundle("app1").instructions("!>index1.ts")
fuse.bundle("app2").instructions("!>index2.ts")

Related

404 on i18n json files

I'm trying to enable i18n json files with SSR on assets folder following this docs:
https://sap.github.io/spartacus-docs/i18n/
But when enabled, all files in PT folder results 404 error.
Here's my provideConfig on spartacus-configuration.module.ts file:
and my assets folder:
Thanks for your time, have a nice day!
Looks like it's trying to load a bunch of json files that aren't in your directories.
What I did on mine was I provided original Spartacus translations then I added mine below that:
provideConfig(<I18nConfig>{
i18n: {
resources: translations,
chunks: translationChunksConfig,
fallbackLang: 'en'
},
}),
provideConfig(<I18nConfig>{
i18n: {
backend: {
loadPath: 'assets/i18n-assets/{{lng}}/{{ns}}.json',
chunks: {
footer: ['footer']
}
}
},
})
otherwise, you can try to add those files its complaining about (orderApproval.json, savedCart.json, etc) to your 'pt' folder (not sure what language that is but perhaps Spartacus doesn't come with translations for it)

RequireJS data-main does not load from html files at different paths

Using RequireJS successfully for a single page application for quite some time. Finally adding JS unit tests to exercise model classes. I have a single config for src modules and another for test modules. (I want to keep test files out of the shipping distribution)
I can load src from index.html and test from LocationTest.html only if both files are in the same top-level folder. I would like to move LocationTest.html inside the test folder, but no change to data-main or the test config file seems to work.
Here is the file layout for the happy path...
/www
- index.html
- LocationTest.html
- js
- src
- lib
- require.js
- require_src_config.js
- require_main.js
- require_test_config.js
- require_test.js
- model
- Location.js
- (other src model classes)
- test
- lib
- (jasmine libs)
- model
- LocationTest.js
- (other test model classes eventually)
index.html
...
<script type='text/javascript' data-main='js/src/lib/require_main' src='js/src/lib/require.js'></script>
...
LocationTest.html
...
<script type='text/javascript' data-main='js/src/lib/require_test' src='js/src/lib/require.js'></script>
...
js/src/lib/require_src_config.js
requirejs.config({
// Base URL for main application
baseUrl: 'js',
// Shortcuts to modules relative to baseUrl
paths: {
Location: 'src/model/Location'
(many other modules...)
}
});
js/src/lib/require_test_config.js
requirejs.config({
baseUrl: 'js',
// Paths (no extension)
paths: {
// Tests
LocationTest: 'test/model/LocationTest',
// Framework
jasmine: 'test/lib/jasmine/jasmine',
jasmineHtml: 'test/lib/jasmine/jasmine-html',
jasmineBoot: 'test/lib/jasmine/boot',
},
// Make external libraries compatible with requirejs (AMD)
shim: {
jasmineHtml: {
deps : ['jasmine']
},
jasmineBoot: {
deps : ['jasmine', 'jasmineHtml']
}
}
});
js/src/lib/require_main.js
requirejs(['./require_src_config'], function (require_src_config) {
(Application Code)
});
js/src/lib/require_test.js
requirejs(['./require_src_config'], function (require_src_config) {
requirejs(['./src/lib/require_test_config'], function (require_test_config) {
requirejs(['jasmineBoot'], function (require) {
requirejs(['LocationTest'], function (LocationTest) {
// Trigger Jasmine
window.onload();
});
});
});
});
The above all works, although I do not understand why I had to revise the path to require_config_test.js in require_test.js. The baseUrl for both configs is 'js'.
I would like to move LocationTest.html to js/test/model.
1) What should my data-main be set to?
2) How (and why) does this impact require_test.js settings?
3) Is there a better way to nest (or not) the configs for src and test to ensure src gets loaded first?
I was hoping to only have to set data-main to the path of the file with the entrypoint and be flexible to move things around. Thanks for your help!

gatsby.js - advanced starter - Implement 2 url prefixes (2 different sections of site)?

It looks as though if you put your jsx files in the 'pages' folder of most gatsby starters, the urls follow the directory structure out of the box, so you can implement whatever urls you need (http://blah.com/foo/post1, http://blah.com/bar/post2) just by nesting folders in the source tree (pages/foo/post.jsx, pages/bar/post2.jsx).
The issue
I used the gatsby advanced starter (https://github.com/Vagr9K/gatsby-advanced-starter). It puts all content files not in pages/, but in a top-level content/ folder and I can't figure out the wiring to replicate foo/xxx, bar/xxx urls even after creating content/foo/post1.md, content/bar/post2.md folders.
It does have a siteconfig.js that sets a single path prefix, but I want two different prefixes for the 2 different sections of the site, so I just set it to "/" for now (builds seem to ignore whatever value I set for this config param anyway, so... shrug).
What I tried
I tried adding path to the frontmatter of the .md files and set it to the parent foldername. This was completely ignored (in any case I don't think that's what I want... I'd like to keep the generated slug as part of the url).
Separated use of gatsby-source-filesystem one for each subfolder hoping it would change graphql graph to recognize 2 separate data sources but it made no difference.
What am I doing wrong?
It looks as though if you put your jsx files in the 'pages' folder of most gatsby starters, the urls follow the directory structure out of the box [...]
That's not specific to Gatsby starters, that's Gatsby's default behaviour. Every js/jsx file in src/pages will be a page.
but in a top-level content/ folder
It still has the src/pages folder for normal pages. But the content folder holds the files will be transformed with the src/templates in gatsby-node.js to pages. Or in other words: The contents of the content folder get programmatically created with the defined template in gatsby-node.js (and the template lies in src/templates).
The path/url get's defined in the createPage function here: gatsby-nodeL144. This line is referencing the edge.node.fields.slug which gets queried in the GraphQL above here. The field gets added in the onCreateNode function. More specificially the slug field in the onCreateNodeField function. There you see that it gets passed a slug that gets defined above.
Create two folders in your src/content folder, e.g. blog and projects. Make sure that you have both of them defined in your gatsby-config.js:
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'blog',
path: `${__dirname}/content/blog`,
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'projects',
path: `${__dirname}/content/projects`,
},
},
In your gatsby-node.js add after the fileNode definition the line:
const pathPrefix = fileNode.sourceInstanceName
The sourceInstanceName is that what we defined as the name in gatsby-config entries.
Then you can alter the line to:
createNodeField({ node, name: "slug", value: `/${pathPrefix}${slug}` });
createNodeField({ node, name: 'sourceInstanceName', value: pathPrefix });
The second line is helpful if you then want to query only for one of the two folders, e.g.:
export const pageQuery = graphql`
query BlogQuery {
allMarkdownRemark(filter: { fields: { sourceInstanceName: { eq: "blog } } }
) {
edges {
node {
... etc
}
}
}
}
`

How to combine `css-modules` with normal `sass`, preferably in `webpack`

TLDR: How to combine css-modules with normal sass, preferably in webpack.
The Setup:
I am working on the styling build process for an e-commerce website. The site's styles are currently done in sass along with the js through a gulp browserify build process.
I have recently added a single page app that is built using react with webpack and babel. Inside of that application I am taking advantage of css-modules provided by webpack to scope the class names to each react component.
The problem:
I would like to incorporate the styles from the webpack css-modules build in with the main styling bundle for the site. To do this, I was considering building a webpack configuration to build the styles for the whole site. The problem I have is how to get the styles which are currently built by the single page webpack configuration and inject just the style chunk into a global webpack configuration that handles styles for the whole site. I should mention that I would like to keep the two configurations as separate as possible
The Questions:
Is there a proper way of having decoupled webpack builds where one is still able to use chunks from the other?
If so, how do I do it so that the css-module setup stays in the single page configuration, and the extract-text-webpack part along with a boring sass build goes into a global configuarion?
If not, how should I go about having one section of sass go through the css-modules workflow, and still combine it with the bundle from the rest of the site.
Thanks in advance.
EDIT
based on #Alexandr Subbotin's answer, I have updated my webpack to look something like the code below. I did have to change names and paths because of the code belongs to my employer, so there may be slight errors.
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const JSDIR = './build/js/';
const STYLES = './build/css/bundle.css';
module.exports = {
entry : {
'styles' : './src/styles.scss',
'app' : './src/index.js',
// a javascript file that includes the root of the single page app.
'single-page' : './src/single-page/styles-entry.js',
},
output : {
path : JSDIR,
filename : '[name].js', // normally compiles my
publicPath: 'http://localhost:8080/',
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader : 'babel-loader',
query : {
presets: [
'react','es2015','stage-0',
]
},
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract('style?sourceMap', 'css?-url&sourceMap!sass?sourceMap'),
exclude : /\/single-page\//,
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract(
'style?sourceMap',
'css?-url&modules&importLoaders=1&localIdentName=SinglePage__[name]__[local]!sass?sourceMap'
),
include : /\/single-page\//,
}
]
},
plugins : [
new ExtractTextPlugin(STYLES, {
allChunks : true,
}),
],
resolve : {
alias: {
"eventEmitter/EventEmitter": "wolfy87-eventemitter",
},
extensions: ['', '.js','.jsx'],
},
}
If I understood your question you want to apply css-modules only to one part of your application and leave simple sass building process in other parts.
To do this you can use exclude and include options in loaders. I.e. if you have your single page application inside single-page directory your webpack config can be:
module: {
entry: {
// it is your global sass styles
application_css: './css/application.scss',
// it is main file of your SPA bundle. Somewhere inside you will use require('./styles.scss') that should be processed by css-modules
spa_index: './single-page/index.js'
},
loaders: [
...,
{
// This loader will build all your sass that are not in `single-page` directory
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
exclude: /\/single-page\//
},
{
// This loader will handle all your css module in `single-page` directory
test: /\.scss$/,
loader: 'style!css?modules!sass',
include: /\/single-page\//
},
],
...
}
So, in this case all css from single-page/ will use css modules, and the rest won't.
EDIT:
If you take a look in API section of ExtractTextPlugin documentation you find
The ExtractTextPlugin generates an output file per entry, so you must use [name], [id] or [contenthash] when using multiple entries.
In your example you have have two chunks with css (styles and single-page), but only one output ./build/css/bundle.css. If you change your output to ./build/css/[name].css your will have two css files: styles.css with your global css and single-page.css with SPA styles.

Karma/Jasmine - Test Files not loading in Base, Module Not Defined

I'm having a hell of a time with Karma/Jasmine. I'm just trying to run the example specs from Jasmine's site.
When I run jasmine on command line, the tests run fine. However, if I try to run them using Karma test runner, I have a multitude of problems.
Here's My File Structure
Here's my karma.conf.js file:
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine', 'requirejs'],
// list of files / patterns to load in the browser
files: [
'node_modules/requirejs/require.js',
'**/test-main.js', {
pattern: 'spec/jasmine_examples/*.js',
included: false
}
],
// list of files to exclude
exclude: ['**/*conf.js'],
...port,browser etc.
Here's my test.main.js file
var allTestFiles = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file) {
if (TEST_REGEXP.test(file)) {
// Normalize paths to RequireJS module names.
allTestFiles.push(pathToModule(file));
}
});
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: '/base',
// dynamically load all test files
deps: allTestFiles,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
});
When I run karma start, I get a 404 that PlayerTest.js and SongTest.js are not under base/. However they are loaded and located in base/spec/jasmine_examples. In addition, PlayerTest.js throws an error "module not defined".
Honestly, what am I doing wrong?
I think you need to refer to the karma-requirejs and the karma-jasmine plugins in the karma.conf.js file -
config.set({
plugins: [
'karma-jasmine',
'karma-requirejs'
],
From karma doc, it states:
Please note just about all frameworks in Karma require an additional plugin/framework library to be installed (via NPM).
Additional information can be found in plugins.
You will not need to have require.js in the files section.

Resources