foundation / foundation-sites

The most advanced responsive front-end framework in the world. Quickly create prototypes and production code for sites that work on any kind of device.
https://get.foundation
MIT License
29.66k stars 5.48k forks source link

How to include a simple plugin (e.g. fancybox or any other) into Foundation 6.4 (Webpack)? #10411

Closed phifa closed 5 years ago

phifa commented 7 years ago

I set up foundation with the cli template and wanted to include the jquery plugin fancybox. In previous versions without webpack, I would include the path to my fancybox bower plugin in config.yml.

How does it work now with webpack?

Do I need to add it in config.yml?

  # Paths to JavaScript entry points for webpack to bundle modules
  entries:
    - "src/assets/js/app.js"
    - "node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js"

Or in my app.js like this?

$(document).foundation();
import fancybox from '../../../node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js';

really confused about how to include it and nothing works thus far. Have been trying different things. I am not too familiar with webpack, but I guess that is now a prerequisite for using foundation.

What is the best practise or at least, how can I make this work?

IamManchanda commented 7 years ago

cc @kball By the way myself also interested for knowing the answer to it ;)

kball commented 7 years ago

The latter is how I'd do it - will set up a sample project and verify exact config for you

kball commented 7 years ago

Fancybox expects window.jQuery to be defined. There also appears to be some sort of inconsistency when using an es6 import given it's not an es6 module, so I used a node style require instead (webpack groks both). In the end this is what it took to get this to work in my app.js:

window.jQuery = $;
require('@fancyapps/fancybox/dist/jquery.fancybox');
phifa commented 7 years ago

Thanks @kball. Wouldn't it make sense to restructure things a little bit? Maybe like so:

This is what my app.js now looks like:

// Framework  
import $ from 'jquery';
import whatInput from 'what-input';
import './lib/foundation-explicit-pieces';

// User
require('./lib/fancybox');
require('./lib/justifiedGallery');
require('./lib/classie');
require('./lib/header');
require('./lib/counter');

This is my lib/foundation-explicit-pieces.js:

import $ from 'jquery';
window.$ = $;

import { Foundation } from 'foundation-sites/js/foundation.core';
import { rtl, GetYoDigits, transitionend } from 'foundation-sites/js/foundation.util.core';
import { Box } from 'foundation-sites/js/foundation.util.box'
import { onImagesLoaded } from 'foundation-sites/js/foundation.util.imageLoader';
import { Keyboard } from 'foundation-sites/js/foundation.util.keyboard';
import { MediaQuery } from 'foundation-sites/js/foundation.util.mediaQuery';
import { Motion, Move } from 'foundation-sites/js/foundation.util.motion';
import { Nest } from 'foundation-sites/js/foundation.util.nest';
import { Timer } from 'foundation-sites/js/foundation.util.timer';
import { Touch } from 'foundation-sites/js/foundation.util.touch';
import { Triggers } from 'foundation-sites/js/foundation.util.triggers';
import { Abide } from 'foundation-sites/js/foundation.abide';
import { Accordion } from 'foundation-sites/js/foundation.accordion';
import { AccordionMenu } from 'foundation-sites/js/foundation.accordionMenu';
import { Drilldown } from 'foundation-sites/js/foundation.drilldown';
import { Dropdown } from 'foundation-sites/js/foundation.dropdown';
import { DropdownMenu } from 'foundation-sites/js/foundation.dropdownMenu';
import { Equalizer } from 'foundation-sites/js/foundation.equalizer';
import { Interchange } from 'foundation-sites/js/foundation.interchange';
import { Magellan } from 'foundation-sites/js/foundation.magellan';
import { OffCanvas } from 'foundation-sites/js/foundation.offcanvas';
import { Orbit } from 'foundation-sites/js/foundation.orbit';
import { ResponsiveMenu } from 'foundation-sites/js/foundation.responsiveMenu';
import { ResponsiveToggle } from 'foundation-sites/js/foundation.responsiveToggle';
import { Reveal } from 'foundation-sites/js/foundation.reveal';
import { Slider } from 'foundation-sites/js/foundation.slider';
import { SmoothScroll } from 'foundation-sites/js/foundation.smoothScroll';
import { Sticky } from 'foundation-sites/js/foundation.sticky';
import { Tabs } from 'foundation-sites/js/foundation.tabs';
import { Toggler } from 'foundation-sites/js/foundation.toggler';
import { Tooltip } from 'foundation-sites/js/foundation.tooltip';
import { ResponsiveAccordionTabs } from 'foundation-sites/js/foundation.responsiveAccordionTabs';

Foundation.addToJquery($);
// Add Foundation Utils to Foundation global namespace for backwards compatibility.
Foundation.rtl = rtl;
Foundation.GetYoDigits = GetYoDigits;
Foundation.transitionend = transitionend;
Foundation.Box = Box;
Foundation.onImagesLoaded = onImagesLoaded;
Foundation.Keyboard = Keyboard;
Foundation.MediaQuery = MediaQuery;
Foundation.Motion = Motion;
Foundation.Move = Move;
Foundation.Nest = Nest;
Foundation.Timer = Timer;

// Touch and Triggers previously were almost purely sede effect driven, so no // need to add it to Foundation, just init them.
Touch.init($);
Triggers.init($, Foundation);
Foundation.plugin(Abide, 'Abide');
Foundation.plugin(Accordion, 'Accordion');
Foundation.plugin(AccordionMenu, 'AccordionMenu');
Foundation.plugin(Drilldown, 'Drilldown');
Foundation.plugin(Dropdown, 'Dropdown');
Foundation.plugin(DropdownMenu, 'DropdownMenu');
Foundation.plugin(Equalizer, 'Equalizer');
Foundation.plugin(Interchange, 'Interchange');
Foundation.plugin(Magellan, 'Magellan');
Foundation.plugin(OffCanvas, 'OffCanvas');
Foundation.plugin(Orbit, 'Orbit');
Foundation.plugin(ResponsiveMenu, 'ResponsiveMenu');
Foundation.plugin(ResponsiveToggle, 'ResponsiveToggle');
Foundation.plugin(Reveal, 'Reveal');
Foundation.plugin(Slider, 'Slider');
Foundation.plugin(SmoothScroll, 'SmoothScroll');
Foundation.plugin(Sticky, 'Sticky');
Foundation.plugin(Tabs, 'Tabs');
Foundation.plugin(Toggler, 'Toggler');
Foundation.plugin(Tooltip, 'Tooltip');
Foundation.plugin(ResponsiveAccordionTabs, 'ResponsiveAccordionTabs');
module.exports = Foundation;

$(document).foundation();

And this is for example my fancybox.js:

import $ from 'jquery';
window.jQuery = $;
require('@fancyapps/fancybox/dist/jquery.fancybox');

$('a[data-fancybox="cl-group"]').fancybox({
    baseClass: 'fancybox-custom-layout',
    margin: 0
});

This way, the app.js functions like the app.scss and all JS is in separate files/modules.

kball commented 7 years ago

@phifa I like that idea a lot - I think getting to a best practice with the new JS approach is going to take a little figuring, but this looks good to me.

phifa commented 7 years ago

@kball yeah, my solution is most likely not the best. I am not experienced with webpack at all, just trying to figure this out.

I think for foundation to succeed on the longrun, this is a critical topic to tackle. There are many guys like me out there using foundation, but have not been exposed to webpack. We cannot afford to loose them and we cannot afford to not win the newbies who are just starting out with web development. They will run to Bootstrap the minute they have the feeling it is easier to use - not because it's better.

By including webpack, we have added another layer of complexity to foundation. We need to lower all the entry barriers to get people on board. I think this is why I am proposing the above idea and I invite people with more experience and knowledge to improve upon the idea, like I said, this is most likely not the best solution/practise.

Also I noticed long transpiling time, sometimes a minute for webpack/babel/gulp to parse the JS files and reload the browsersync. I think it was @rafibomb that mentioned the speed gain through the use of webpack. Thus far, everything is slower than before.

kball commented 7 years ago

@phifa would you like to submit a PR to the zurb stack with the new structure you proposed?

phifa commented 7 years ago

sure, no problem, do we want more eyes on this first, or you think it is a safe approach? also regarding transpile time? mabe you can test it first.

york-xtrem commented 7 years ago

I've been building my own workflow for a week because just like when the javascript task was done with Gulp. The construction time seems a little tedious for a minute. This is not productive if you are developing.

Already with Gulp separate the structure into three directories:

This way when I changed something in Common or Main, Babel and concatenate took a second or even less.

I'm totally new to webpack, but I think you could move this to webpack. Here they speak of three methods:

Https://robertknight.github.io/posts/webpack-dll-plugins/

Of course this would be for development, unless it will make it easier to make a lazy load on Foundation users. So that you could have (Using DllPlugin or Code splitting ):

But there would have to be two Gulp tasks:

Const webpackConf = require ('../ conf / webpack.conf');
Const webpackDistConf = require ('../ conf / webpack-dist.conf');

Gulp.task ('webpack: dev', done => {
  WebpackWrapper (false, webpackConf, done);
});

Gulp.task ('webpack: dist', done => {
  Process.env.NODE_ENV = 'production';
  WebpackWrapper (false, webpackDistConf, done);
});

Function webpackWrapper (watch, conf, done) {
  Const webpackBundler = webpack (conf);

  Const webpackChangeHandler = (err, stats) => {
    If (err) {
      GulpConf.errorHandler ('Webpack') (err);
    }
    Gutil.log (stats.toString ({
      Colors: true,
      Chunks: false,
      Hash: false,
      Version: false
    }));
    If (done) {
      Done ();
      Done = null;
    } Else {
      Browsersync.reload ();
    }
  };

  If (watch) {
    WebpackBundler.watch (200, webpackChangeHandler);
  } Else {
    WebpackBundler.run (webpackChangeHandler);
  }
}

'Webpack: dev' -> vendor.bundle.js and main.bundle.js 'Webpack: dist' -> bundle.js

york-xtrem commented 7 years ago

My references on DllPlugin:

dobromir-hristov commented 7 years ago

You can use the webpack ProvidePlugin to shim jQuery for older plugins. https://webpack.js.org/plugins/provide-plugin/ Then you can import any plugin you need as normal.

DanielRuf commented 6 years ago

Hm, never had such issues with the current templates. Some jQuery plugins do not export the namespace or class name and do not bind window to root in the UMD / AMD wrapper that they use sometimes. In this case we host a modified version where we define window as root.

Using require with the ES6 module structure can introduce problems and needs a different babel config.

DanielRuf commented 5 years ago

Closing as we did not receive any further updates regarding this issue. If there are still issues please open a new issue.