Sage 9 + webpack

Hi,
very nice work!
Everything works perfectly except I am having issues with importing jQuery dependencies like masonry…
In sage 8 I added them in bower and they were included and compiled in main.js,
In sage 9 I added masonry in package.json like this :

"dependencies": { "babel-runtime": "^6.5.0", "bootstrap": "^4.0.0-alpha.2", "jquery": "^2.1.4", "tether": "^1.2.0", "masonry-layout" :"4.1.0" }

, then npm install successfully…

But it seems js file from masonry is not included in main.js / main.js.map after doing successfully
npm run build

Is there another way to include third part dependencies ?
Am I doing right ?

Thanks!

You can find some information on the Masonry website on how to use the library with webpack.

http://masonry.desandro.com/extras.html#webpack

As for using it with Sage, on my current project I imported Masonry in my scripts/main.js :

import Masonry from 'masonry-layout';
import jQueryBridget from 'jquery-bridget';

And to use it as a jQuery plugin :

// Load Events
$(document).ready(function() {

  // Masonry
  jQueryBridget( 'masonry', Masonry, $ );

  new Router(Sage).loadEvents();
});

Thanks for answer,
the only way I found to make it works is to use import with path :frowning:
import 'masonry-layout/dist/masonry.pkgd.js'; import 'jquery-bridget/jquery-bridget.js'; import 'imagesloaded/imagesloaded.pkgd.js';

I had issue when using :
import Masonry from 'masonry-layout'; import jQueryBridget from 'jquery-bridget';

I get a Uncaught TypeError: (0 , _jqueryBridget2.default) is not a function error … even if webpack compiles successfully.

It seems to be the same for all dependencies added in node package,
I need to import 'path/file.js'; in main.js

If you can explain I’d love to understand…

Thanks again.

I think this could be solved by tweaking how webpack import masonry and jquery-bridget. Try adding a loader element to webpack.config.js loaders.

{
        test: /(masonry-layout|jquery-bridget)/,
        loader: 'imports?define=>false&this=>window'
},

Then I am able to import them like this:

import Masonry from 'masonry-layout';
import jQueryBridget from 'jquery-bridget';
import imagesLoaded from 'imagesloaded';

Documentation here: https://github.com/webpack/imports-loader

Or instead of tweaking webpack.config.js, you could do it this way:

import Masonry from 'imports?define=>false&this=>window!masonry-layout';
import jQueryBridget from 'imports?define=>false&this=>window!jquery-bridget';
import imagesLoaded from 'imagesloaded';

Thanks !
I really have to learn more about webpack config … it seems to be more and more used.
Can you explain the difference between this way and the way bootstrap js files are imported with import + full path ?
import 'bootstrap/dist/js/.../....js';

If someone has issue when compiling webfonts,
it may be because you are using otf font file…

otf file type was simply missing to webpack.config.js file … just add it

{ test: /\.(ttf|eot|otf|svg)(\?.*)?$/, loader: 'file?' + qs.stringify({ name: '[path][name].[ext]' }) },

1 Like

I’m trying to get my head around the whole new Webpack configuration and I’m starting to see the advantages of this module based approach.

I’m far from understanding everything yet, but I thought the biggest advantage of Webpack would be splitting up your javascript in view/page specific chunks (like described here in 3. “entry” — String Vs Array Vs Object).

Right now Sage 9 is still using a single main.js file with the DOM-based routing. Is this done deliberately because you think the advantages of separate chunks don’t weigh up to the disadvantages of enqueuing multiple js files? Or is it up to you to add entry points in config.json and enqueue them in your templates yourself?

Furthermore, is it correct behaviour that running npm run watch deletes the dist folder and results in a 404 on the CSS:
https://localhost:3000/app/themes/sage-9/dist/styles/main.css Failed to load

Thanks for all your hard work on sage 9, looking forward working with it!

One of the advantages of using webpack is that you can require the other bundles dinamically via ajax with require.ensure() from your main entry point. This means you can leverage the dom-based routing and still achieve multiple bundles that will only be loaded when the page requires it.

And yes, npm run watch serves all your assets from the development-server built in webpack.

Furthermore, is it correct behaviour that running npm run watch deletes the dist folder and results in a 404 on the CSS:
https://localhost:3000/app/themes/sage-9/dist/styles/main.css Failed to load

This is also because when you run the watch server, the CSS is inlined in your main.js. So the main.css file is not served.

So you would use this kinda setup?

var Sage = {
	// All pages
	'common': {
		init: function() {
			// JavaScript to be fired on all pages
			require.ensure(['./views/Common.js'], function(require) {
				require('./views/Common.js');
			});
		},
		finalize: function() {
			// JavaScript to be fired on all pages, after page specific JS is fired
		}
	},
	// Home page
	'home': {
		init: function() {
			// JavaScript to be fired on the home page
			require.ensure(['./views/Home.js'], function(require) {
				require('./views/Home.js');
			});
		},
		finalize: function() {
			// JavaScript to be fired on the home page, after the init JS
		}
	},
	// About us page, note the change from about-us to about_us.
	'about_us': {
		init: function() {
			// JavaScript to be fired on the about us page
			require.ensure(['./views/AboutUs.js'], function(require) {
				require('./views/AboutUs.js');
			});
		}
	}
};

Which results in this file output when running npm run build:

└── dist
       ├─ 2.scripts
       │      ├─ 2.js // containing views/common.js
       │      └─ 2.js.map
       ├─ 3.scripts
       │      ├─ 3.js // containing views/home.js
       │      └─ 3.js.map
       ├─ 4.scripts
       │      ├─ 4.js // containing views/about.js
       │      └─ 4.js.map
       ├─ scripts
       │      ├─ customizer.js
       │      ├─ customizer.js.map
       │      ├─ main.js
       │      └─ main.js.map
       └─ styles

This approach looks like the best. Does it work as should?

Hi there,

Sorry for the delay!
Yes, as far as I know that would be working correctly!

No problem. I can confirm that it does work correctly!

When running npm run build only main.js is enqueued and in my example common.js (2.js) gets loaded on every page. On the homepage common.js (2.js) & home.js (3.js) are loaded and on the about us page, common.js (2.js) & about.js (4.js) are loaded.

When running npm run build:production the chunks are loaded correctly too, even with hashed filenames!

The only problems I’m having is when running the watch command npm run watch:

Mixed Content: The page at 'https://localhost:3000/' was loaded over HTTPS, but requested an insecure script 'http://localhost:3000/app/themes/sage-9/dist/2.scripts/2.js'. This request has been blocked; the content must be served over HTTPS.

The required chunks from the main.js are blocked.
I have setup my WP site with Trellis with SSL enabled:

ssl:
  enabled: true
  provider: self-signed

Also I’m wundering if we could maintain just 1 dist/scripts folder instead of a separate folder for each required chunk (dist/2.scripts, dist/3.scripts, dist/4.scripts etc)?

You can fix this by editing the host var in your Watch.js file to https:

// Internal variables
var host = 'https://localhost',
    port = config.devPort || '3000',
    compiler;

What do you guys see the likelihood of Webpack being adopted to Sage’s core project?

Hi Guys I’ve got a odd thing happening with Webpack and I hope that someone can help?

I’ve been working fine on a project without issue, but now when I run ‘npm run watch’ it runs and the page loads, but with no css or js being sent to the page, so I’m left with just html.

I’ve not changed anything in the config files. It’s very odd

Sage 9 uses webpack…

Ahh, I missed this: https://github.com/roots/sage/pull/1625
Nice!

Update:

I think it maybe to do with this bug with WebPack but I’m not sure as yet. I would be greatfull for any help.