I would like to import some foundation js files in a webpack app.
In my entry js file I do the following:
import 'foundation-sites/js/foundation.core.js'; // this works
import 'foundation-sites/js/foundation.tabs.js'; // this works
import 'foundation-sites/js/foundation.reveal.js'; // this fails
The last one fails with the following error:
ERROR in ./~/foundation-sites/js/foundation.reveal.js
Module not found: Error: Cannot resolve module 'foundation' in /home/kai/Projects/myapp/node_modules/foundation-sites/js
@ ./~/foundation-sites/js/foundation.reveal.js 474:4-476:6
So it seems there is a problem with all files that contain the code define(['foundation'] ... as foundation is not defined anywhere.
I installed foundation-sites (v6.0.5) using NPM.
How do I import those files that have the define(['foundation'] correctly?
The same obviously happens when adding foundation.min.js or foundation.js. Have you found a workaround?
ERROR in ./~/foundation-sites/dist/foundation.js
Module not found: Error: Cannot resolve module 'foundation' in
/home/kirsebaer/testproject/node_modules/foundation-sites/dist
@ ./~/foundation-sites/dist/foundation.js 2045:4-2047:6 3747:4-3749:6 3932:4-3934:6 4145:4-4147:6 5619:4-5621:6 7027:4-7029:6
+1
You guys have done so much nice work in allowing us to modularly import SCSS, it's a tragedy that I can't use this library because your javascript is essentially un-importable as a CommonJS module. This is going to severely limit its adoption in both webpack and browserify build environments.
+1
+1
+1
For now this is the biggest problem for me and the reason why I can't completely switch to foundation.
Can't imagine why JS modularity is so bad, while SASS modularity is so good...
Would love to see ES2015 modules support, but any other webpack compatible modules support will do the job.
Seeing the same problem. Having to use Bower to work-around it so far.
Added a StackOverflow question: http://stackoverflow.com/questions/34297788/npm-zurb-foundation-webpack-cannot-resolve-module-foundation
@MTyson
I posted my temporary workaround on your StackOverflow entry. Enjoy
+1
@Nerdinacan Thanks, you put me on the right track! I've posted my workaround on the StackOverflow question adding some steps and explanation, hope you don't mind.
+1
+1
My solution using a single js file (no need a app.js and vendor.js): http://stackoverflow.com/a/34611081/4794469
+1 here... it took me a while to find this post. i took on one of the workarounds posted above. Anyone have any ideas what is the problem with the current JS base? As I can see the module definitions are there, but webpack seems to have a problem with the 'foundation' dependency.
(p.s. I'm a babel/webpack/commonjs noob so be nice if I'm talking silly here)
+1
I've noticed on the SCSS side switching from v5.x to v6.x there were compiling issues; the root file (foundation.scss) didn't automatically pull dependencies. Did webpack work with v5?
Actually, yeah, I rolled back to v5 and things are working. I had to expose jQuery and $ as globals, but that was the only kludge. I just did:
$ = jQuery = require('jquery');
At the head of my entry file.
+1
+1
@tomByrer
that's an other story. you can just delete the mixin around the import and you`re good to go... or just use the mixin in your style.scss
UPDATED: feb 29 2016
A simpler solution (no vendor.js, no externals, simply an alias).
1 - Use this in your webpack config:
// this will force the export of the jQuery 'foundation' function, which we'll use later
loaders: [
{
test: /(foundation\.core)/,
loader: 'exports?foundation=jQuery.fn.foundation'
},
],
// this makes sure that every module can resolve define(['foundation']) calls
resolve: {
extensions: ['', '.js'],
alias: {
foundation: 'foundation-sites/js/foundation.core'
}
},
// this makes sure 'jQuery' is available to any jQuery plugin you might want to load
// (including Foundation files) regardless of how they are written
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
]
2 - In your index.js:
// thanks to the ProvidePlugin we don't need to
// > import $ from 'jquery';
// import core foundation files
import { foundation } from 'foundation-sites/js/foundation.core';
import 'foundation-sites/js/foundation.util.mediaQuery';
/* import here any additional module */
// we need to attach the function we exported above to the jQuery object in use in this file
$.fn.foundation = foundation;
// ready to go
$(document).ready(function() {
$(document).foundation();
…
});
Thanks for the nice solution @mjsarfatti! :+1:
Got it working after installing babel-loader and exports-loader. I also had to quote the $ key in the ProvidePlugin options object to get it working.
But a single module is still complaining about jQuery missing:
import 'foundation-sites/js/foundation.util.triggers'
The bundle contents look like webpack does not inject jQuery here. Do you know how to solve this problem?
Hey guys, it's much easier than you think ;)
Just npm i script-loader and prefix the import with a script! everywhere where you need to load the script in the global scope. No need to configure externals, aliases or ProvidePlugins in webpack.
If you want to load everything from foundation it would look like this:
import 'script!jquery'
import 'script!what-input'
import 'script!foundation-sites'
You can checkout my boilerplate project https://github.com/timaschew/r3-foundation-boilerplate
@tomByrer
I've noticed on the SCSS side switching from v5.x to v6.x there were compiling issues; the root file
Didn't see any errors. It's working fine with v6 in my boilerplate project.
@keimlink can you try modifying the loaders > test as such:
test: /foundation\.(core|utils)/ (or even simply test: /foundation/)
@timaschew great, even better! My solution can actually cause problems when you attach foundation plugins to elements via _data-_ attributes instead of with pure javascript, yours could solve that.
where and how does one declare $(document).foundation(); ?
inside an angular2 app
I guess you would still declare it inside the $(document).ready(function() { ... }) call
I'm going with @timaschew's solution for now, seems to be working.
@medihack so is this solved for you, can this issue be closed?
@timaschew This thread is just a collection of different workarounds/hacks to circumvent the initial problem. IMO @Nerdinacan described it in the best way:
it's a tragedy that I can't use this library because your javascript is essentially un-importable as a CommonJS module
So my expectation is that the zurb people will come up with a fix or explain what should be fixed so that someone else can do it.
@mjsarfatti Thanks for the update! Will try it ASAP and post feedback here!
This thread is just a collection of different workarounds/hacks
@keimlink It's a decision of the authors which module types they want to support and maintain.
Of course they could provide to bundle foundation with the UMD format. But this doesn't make sense in combination with modular components (tabs, accordion, magellan), because every file would be exist additionally in the generated UMD format.
It would only make sense for the file (in the dist directory) which contains all the components.
But in that case there is no support for picking/selecting particular components but this is what CommonJS should be, so this case doesn't make sense as well.
If there is a library, which is only available in one module type, in this case: using the global window scope - doesn't fit in your build pipeline, you need to use an adapter.
Every good bundler provides adapters: browserify and webpack and for webpack it's the script-loader it does exactly this job.
This thread is just a collection of different workarounds/hacks
So these solutions of browserify and webpack are no hacks, they are adapters.
@timaschew I disagree, it's a pity that in 2016 such a big project still hasn't adopted UMD. Every module should require the core and the core should require jquery. I'm not saying it's easy, it's very possible that adopting UMD would require a big rewrite and for this reason they haven't done it yet. But it has to be done or someone else will come forward (see lodash - which I can import function by function in my project - vs the monolithic underscore)
@mjsarfatti In your solution, why do you need to do : import $ from 'jquery'; in index.js if you already declared jquery in :
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
?
Can't you remove this import line?
Good catch, in fact you most probably don't in this case.
I import it by default in all my projects (I don't always need the ProvidePlugin) and it became an automation I guess :) I haven't tested it but it should definitely work without that import.
@timaschew I finally tested your solution, and while it looked great I could not find a way to make it work when you import jQuery plugins written using the UMD alongside others written in the "legacy" way (in my specific case _scrollToFixed_ and _selectize_).
At least when you define the script-loader in the webpack config: there might be a way if you specify which loader to use inline case by case, but I wanted a universal solution. The error I got was a "require is not defined", very weird.
@keimlink please disregard my previous reply :) I revised my code above, you just need to add 'window.jQuery': 'jquery' to the ProvidePlugin
@mica16 you are most definitely right, I commented out that line and obviously it works.
Thanks for the update @mjsarfatti ! I will test it as soon as I have the time!
I haven't tried it so far, but it seems release 6.2 has converted everything to ES2015 which should also solve the import problem.
I'm very new to webpack and foundation. im trying to get foundation 6.2 work with webpack and npm. Can someone help me out here.
in my webpack.config.js
module: {
loaders: [{
test: /(foundation\.core)/,
loader: 'exports?foundation=jQuery.fn.foundation'
}],
resolve: {
extensions: ['', '.js'],
modulesDirectories: ['node_modules'],
alias: {
foundation: 'foundation-sites/js/foundation.core'
}
},
},
plugins: debug ? [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
] :
then in my index.js my webpack entry file
require('!!script!jquery/dist/jquery.min.js');
require('!!script!foundation-sites/js/foundation.core.js');
require('!!script!foundation-sites/js/foundation.accordion.js');
require('!!script!foundation-sites/js/foundation.util.keyboard.js');
require('!!script!foundation-sites/js/foundation.util.motion.js');
$.fn.foundation = foundation;
// ready to go
$(document).ready(function() {
$(document).foundation();
});
but im getting index.js: Uncaught ReferenceError: foundation is not defined
what im doing wrong here??
@fchengpc this is what I'm doing, based on what's been described in this thread (I'm on 6.1.x though, not sure if it makes a difference):
import 'script!jquery'
import 'script!foundation-sites'
$(document).ready(function ($) {
$(document).foundation();
});
I'm not doing anything specific in the webpack file.
Try
var foundation = require('!!script!foundation-sites/js/foundation.core.js');
or possibly adding foundation to your provide plugin
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
foundation: 'Foundation'
})
@anselmdk Thanks you. finally got it working now. You are right nothing special in webpack config.(i took most of stuff out). Here is what i have in entry file.
require('script!jquery');
foundation = require('foundation-sites/dist/foundation.min.js');
$(document).ready(function($) {
$(document).foundation();
});
not sure why i need to require jquery again. since i do use (webpack.ProvidePlugin) in webpack config. But if i took it out it throw jQuery undefined error. (assume b/c foundation use $, JQuery and window.jQuery
@priedthirdeye I actually end up use both. first ProvidePlugin in webpack config file then define foundation variable in entry file.
Hope this help out someone the future.
@fchengpc that's cool. It could be that you're getting away with calling Foundation directly, because you're using 6.2. I'll try that out when I upgrade.
I'm able to get Foundation 6 working with webpack if I use the scripts-loader via @timaschew's method. But I'm unable to specify the files I want explicitly. I have to include the entire JS library.
So, in short this works:
import 'script!jquery'
import 'script!what-input'
import 'script!foundation-sites';
but this doesn't:
import 'script!jquery'
import 'script!what-input'
import '!!script!foundation-sites/js/foundation.core.js';
import '!!script!foundation-sites/js/foundation.util.box.js';
import '!!script!foundation-sites/js/foundation.util.keyboard.js';
import '!!script!foundation-sites/js/foundation.util.mediaQuery.js';
import '!!script!foundation-sites/js/foundation.util.motion.js';
import '!!script!foundation-sites/js/foundation.util.timerAndImageLoader.js';
import '!!script!foundation-sites/js/foundation.util.touch.js';
import '!!script!foundation-sites/js/foundation.util.triggers.js';
import '!!script!foundation-sites/js/foundation.abide.js';
import '!!script!foundation-sites/js/foundation.accordion.js';
import '!!script!foundation-sites/js/foundation.accordionMenu.js';
import '!!script!foundation-sites/js/foundation.drilldown.js';
import '!!script!foundation-sites/js/foundation.dropdown.js';
import '!!script!foundation-sites/js/foundation.dropdownMenu.js';
import '!!script!foundation-sites/js/foundation.equalizer.js';
import '!!script!foundation-sites/js/foundation.interchange.js';
import '!!script!foundation-sites/js/foundation.magellan.js';
import '!!script!foundation-sites/js/foundation.offcanvas.js';
import '!!script!foundation-sites/js/foundation.orbit.js';
import '!!script!foundation-sites/js/foundation.responsiveMenu.js';
import '!!script!foundation-sites/js/foundation.responsiveToggle.js';
import '!!script!foundation-sites/js/foundation.reveal.js';
import '!!script!foundation-sites/js/foundation.slider.js';
import '!!script!foundation-sites/js/foundation.sticky.js';
import '!!script!foundation-sites/js/foundation.tabs.js';
import '!!script!foundation-sites/js/foundation.toggler.js';
import '!!script!foundation-sites/js/foundation.tooltip.js';
When including files specifically, the dropdownMenu doesn't work. It returns this error:
foundation.core.js:189 TypeError: Cannot read property 'Feather' of undefined.
However, when importing individually there are other JS components that do work (orbit and interchange, for example).
does it help if you put the dropdown import to the end or change the order somehow?
@timaschew no, changing the order doesn't have any effect and still returns the same error: foundation.core.js:189 TypeError: Cannot read property 'Feather' of undefined(…)
This is how I currently do it using Foundation 6.2.1
var foundation = require("babel!foundation-sites/js/foundation.core");
require('babel!what-input/what-input.js');
require("babel!foundation-sites/js/foundation.util.mediaquery.js");
require("babel!foundation-sites/js/foundation.util.nest.js");
require("babel!foundation-sites/js/foundation.util.box.js");
require("babel!foundation-sites/js/foundation.util.keyboard.js");
require("babel!foundation-sites/js/foundation.util.motion.js");
require("babel!foundation-sites/js/foundation.util.timerandimageloader.js");
require("babel!foundation-sites/js/foundation.util.touch.js");
require("babel!foundation-sites/js/foundation.util.triggers.js");
require('babel!foundation-sites/js/foundation.offcanvas.js');
require('babel!foundation-sites/js/foundation.dropdownMenu.js');
require('babel!foundation-sites/js/foundation.dropdown.js');
require('babel!foundation-sites/js/foundation.equalizer.js');
// Related dependencies From package.json
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.6.0",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"gulp-babel": "^6.1.2",
[...]
I'm sure there's other ways to do it, but this is what works for me after many wasted hours trying to get it to work.
@priedthirdeye that is the best solution to be used with
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
Thanks for all the support here! Could we get this documented somewhere in the repo. Then I'd anyone comes and submits an issue or question on our (webpack) repo, we can link them to a solution.
@TheLarkInn @priedthirdeye @agualbbus We'd happily accept a PR to the docs adding this, perhaps on this page? (http://foundation.zurb.com/sites/docs/installation.html)
File found here: https://github.com/zurb/foundation-sites/blob/develop/docs/pages/installation.md
The problem I ran into specifically was Uncaught TypeError: $(...).foundation is not a function, in other words, $.fn.foundation wasn't being set. I tried every solution here and across the internet, and couldn't get anything to work.
I managed to get it working (after some code diving) by essentially pulling out the jQuery plugin code from ./js/foundation.core.js#253 and doing this:
// Foundation Sites Initialisation
// FIXME: Currently breaks, see: https://github.com/zurb/foundation-sites/issues/7386.
import 'what-input';
import 'foundation-sites';
$.fn.foundation = function(method) {
var type = typeof method,
meta = $('meta.foundation-mq'),
noJS = $('.no-js');
if(!meta.length){
$('<meta class="foundation-mq">').appendTo(document.head);
}
if(noJS.length){
noJS.removeClass('no-js');
}
if(type === 'undefined'){//needs to initialize the Foundation object, or an individual plugin.
Foundation.MediaQuery._init();
Foundation.reflow(this);
}else if(type === 'string'){//an individual method to invoke on a plugin or group of plugins
var args = Array.prototype.slice.call(arguments, 1);//collect all the arguments, if necessary
var plugClass = this.data('zfPlugin');//determine the class of plugin
if(plugClass !== undefined && plugClass[method] !== undefined){//make sure both the class and method exist
if(this.length === 1){//if there's only one, call it directly.
plugClass[method].apply(plugClass, args);
}else{
this.each(function(i, el){//otherwise loop through the jQuery collection and invoke the method on each
plugClass[method].apply($(el).data('zfPlugin'), args);
});
}
}else{//error for no class or no method
throw new ReferenceError("We're sorry, '" + method + "' is not an available method for " + (plugClass ? functionName(plugClass) : 'this element') + '.');
}
}else{//error for invalid argument type
throw new TypeError(`We're sorry, ${type} is not a valid parameter. You must use a string representing the method you wish to invoke.`);
}
return this;
};
$(document).foundation();
I should be able to do the same hack, sans the copy-pasting, if the jQuery plugin function is exported in the Foundation module for AMD. I suspect this would be kind of gross though, especially since it would require the user manually assigning $.fn.foundation.
It looks as though @nueverest solved this in https://github.com/vuejs-templates/webpack/issues/254 with the config
externals: {
foundation: 'Foundation'
},
in webpack.conf
Can some of the other folks who are running into this check this solution out? If it works we'll add it to the docs
I'm struggling with this issue as well. The externals solution didn't work for us :/
In webpack.config
sassLoader: {
includePaths: [
path.resolve(srcPath, 'node_modules/foundation-sites/scss/'),
path.resolve(srcPath, 'node_modules/motion-ui/src/'),
path.resolve(srcPath, "node_modules"),
]
},
resolve: {
//tells webpack where to look for modules
modulesDirectories: ['node_modules',],// 'bower_components'],
extensions: ['', '.js', '.jsx'],
alias: {
foundation: 'foundation-sites/js/foundation.core'
}
},
in main.scss
// @import "../../node_modules/foundation-sites/scss/foundation";
// Webpack allows you to use ~ to import from module directories:
@import "~foundation-sites/scss/foundation";
@import "gh_settings";
$fa-font-path: "~font-awesome/fonts";
@import "~font-awesome/scss/font-awesome";
// where the $fa-font-path variable is seen in font-awesome/scss/_variables.scss
// $fa-font-path: "../fonts" !default;
// As is described overhere: http://fontawesome.io/get-started/
// You need to @include the pieces you want to use. For example, to include everything:
// http://foundation.zurb.com/sites/docs/sass.html#adjusting-css-output
// @include foundation-everything(true);
@include foundation-global-styles;
@include foundation-grid;
@include foundation-flex-grid;
@include foundation-typography;
@include foundation-button;
@include foundation-forms;
// @include foundation-range-input;
@include foundation-accordion;
@include foundation-accordion-menu;
@include foundation-badge;
@include foundation-breadcrumbs;
@include foundation-button-group;
@include foundation-callout;
@include foundation-close-button;
@include foundation-menu;
@include foundation-menu-icon;
@include foundation-drilldown-menu;
@include foundation-dropdown;
@include foundation-dropdown-menu;
@include foundation-flex-video;
@include foundation-label;
@include foundation-media-object;
@include foundation-off-canvas;
@include foundation-orbit;
@include foundation-pagination;
@include foundation-progress-bar;
// @include foundation-progress-element;
// @include foundation-meter-element;
@include foundation-slider;
@include foundation-sticky;
@include foundation-reveal;
@include foundation-switch;
@include foundation-table;
@include foundation-tabs;
@include foundation-thumbnail;
@include foundation-title-bar;
@include foundation-tooltip;
@include foundation-top-bar;
@include foundation-visibility-classes;
@include foundation-float-classes;
// @include foundation-flex-classes;
@import "motion-ui";
@include motion-ui-transitions;
@include motion-ui-animations;
React index.js begin
//load jquery and foundation in the window scope
import 'script!jquery'
import 'script!what-input'
import 'script!foundation-sites'
import './styles/index.css'
$(document).foundation();
I's work for us
After banging my head against the wall for hours, I finally figured out what was causing this issue for us. We were using both the ProvidePlugin and the script-loader at the same time. When we removed the following lines from our webpack config, it was resolved:
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
Hope this helps someone!
If I'm understanding this properly, there are workarounds, but moving Foundation to ES2016 true dependency management is the real fix. This is a pretty large project, but I think important. We're about to release 6.3... I'd like to target this for version 6.4.
Maybe open a new issue for that and add it to the milestone? It would allow people to track the progress specific to the transition easier, under a title that reflects the intent.
@SShrike done here: #9438
This has been a wonderful thread to read. But I'm totally lost re: script-loader and importing foundation js.
Thanks to @shtalinberg for posting long code snippets, but I feel like I need the entire files to make sense of it.
And @timaschew I visited your repo but couldn't find anything relating to script-loader and your recommended "import script!jquery" syntax. I'm sure I'm misunderstanding.
In the webpack entry file, index.js
import 'script!jquery'
import 'script!what-input'
import 'script!foundation-sites'
and this throws an error:
5:1 error Unexpected '!' in 'script!jquery'. Do not use import syntax to configure webpack loaders import/no-webpack-loader-syntax
6:1 error Unexpected '!' in 'script!what-input'. Do not use import syntax to configure webpack loaders import/no-webpack-loader-syntax
7:1 error Unexpected '!' in 'script!foundation-sites'. Do not use import syntax to configure webpack loaders import/no-webpack-loader-syntax
First project I'm trying to use Foundation in, and damn did I pick a good one.
Use 'script-loader!jquery' now instead of just 'script!jquery'.
As a reference, checkout vue-foundation. It is for Vuejs also however you can just reference the foundation portions of the config.
We've just merged #9965 which moves all of Foundation's javascript to true module dependency, and actually uses webpack for our internal builds, so this will be well and truly fixed in the 6.4 release, scheduled for mid to late May.
I know this is old but its high on "the googles". The solutions above worked for me with some modifications.
I installed script loader and removed weback.provideplugin, then I used the inline script loader with the minified files since it would be more complicated to minify them later in line.
https://github.com/webpack-contrib/script-loader
webpack ^3.4, foundation-sites ^6.4, script-loader ^0.7
import 'script-loader!jquery/dist/jquery.min.js';
import 'script-loader!foundation-sites/dist/js/foundation.min.js';
$(document).ready(() => {
$(document).foundation();
});
I took solution from https://github.com/vue-foundation/vue-foundation/blob/master/src/foundation.js and it works fine for me.
import jQuery from 'jquery';
import { Foundation } from 'foundation-sites/js/foundation.core';
import { Tooltip } from 'foundation-sites/js/foundation.tooltip';
import { Box } from 'foundation-sites/js/foundation.util.box';
Foundation.addToJquery(jQuery);
Foundation.Box = Box;
Triggers.init(jQuery, Foundation);
Foundation.plugin(Tooltip, 'Tooltip');
// and so on
@Londeren I absolutely love you man.
@Londeren God bless you.
I've used some of the above workarounds in the past but was hoping to get to something clearner with Foundation 6.4.4, but unfortunately it throws this issue when I try to build it in a setup using create-react-app:
Failed to minify the code from this file:
./node_modules/foundation-sites/js/foundation.util.core.js:24
Read more here: http://bit.ly/2tRViJ9
I do see this is a known issue (related discussion: #10987), just wanted to note here for future searchers.
@michaelaflores Thanks future searcher here.
@Londeren - thank you, I made a foundation.js file based on
https://github.com/vue-foundation/vue-foundation/blob/master/src/foundation.js that I import in my entry point and it works. One thing to note - I wanted to use Sticky and was having troubles.
I commented out:
//Triggers.init(jQuery, Foundation);
and added:
Foundation.plugin(Triggers, "Triggers");
Foundation.plugin(MediaQuery, "MediaQuery");
and then Sticky worked for me. Also, for folks asking, I simply initialized foundation in my entry point script:
$(document).ready(() => {
$(document).foundation();
});
Thanks @littlered that helped a lot. Thought I was never going to get this working!
Most helpful comment
+1
You guys have done so much nice work in allowing us to modularly import SCSS, it's a tragedy that I can't use this library because your javascript is essentially un-importable as a CommonJS module. This is going to severely limit its adoption in both webpack and browserify build environments.