I am working on using Zurb Foundation with WebPack and NPM, without Bower.
The problem I am encountering is the same as this below:
https://github.c
This is the common place to land from web search with beginner questions related to the technologies mentioned in the question.
Here is my Zurb Foundation with SCSS and Webpack Example Project.
Feel free to clone it. It is licensed with the Unlicense.
Although, the module compatibility issues are resolved with recent (> 6.4) versions of the Zurb Foundation, a basic setup may still seem like black magic for a beginner. I think there must be other and probably better examples like mine somewhere, but I just couldn't find them. I'm adding the fruits of my learning journey here in the hopes that it will make somebody's ride a bit less bumpy.
If you carefully see the foundation-sites 6.2.0 modules, you will find the changes in path as following
So basically you have to changes in webpack confing files entry as following
module.exports = {
entry: ['script!jquery/dist/jquery.min.js',
'script!foundation-sites/dist/js/foundation.min.js',
'./app/app.jsx'
]
}
and the entry for style should be like this
require('style!css!foundation-sites/dist/css/foundation.min.css');
For myself, I used this solution:
I'm using the Laravel framework, so first I added the .webpackConfig (...)
method to the webpack.mix.js
file:
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css')
// By default, files from the directory "/node_modules" are not processed by the Babel loader,
// so in the Webpack configuration,
// an exception was added for loading from the directory "/node_modules/foundation-sites/js".
.webpackConfig({
module: {
rules: [{
// Section "// Babel Compilation." from "/node_modules/laravel-mix/src/builder/webpack-rules.js"
test: /\.jsx?$/,
// Thanks for the help with "exclude": http://qaru.site/questions/97960/import-a-module-from-nodemodules-with-babel-but-failed/624982#624982
exclude(file) {
if (file.startsWith(__dirname + '/node_modules/foundation-sites/js')) {
return false;
}
return file.startsWith(__dirname + '/node_modules');
},
use: [
{
loader: 'babel-loader',
options: Config.babel()
}
]
}]
}
});
Note:
To install Foundation
I used the package https://github.com/laravel-frontend-presets/zurb-foundation. And added the code to load Foundation
into the /resources/assets/js/bootstrap.js
file:
/**
* We'll load jQuery and the Foundation jQuery plugin which provides support
* for JavaScript based Foundation features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
try {
window.$ = window.jQuery = require('jquery');
require('foundation-sites/dist/js/foundation'); // 'foundation.min' can also be used if you like
// The app plugins for the Foundation
require('./plugins/entries/foundation');
} catch (e) {}
Secondly, I created the file /resources/assets/js/plugins/entries/foundation.js
(The file is included in the code above // The app plugins for the Foundation.
). In which I included my modules (example):
import { CropText } from '../cropText';
Foundation.plugin(CropText, 'CropText');
Third, I created two files for including the Foundation
plugins:
1) /resources/assets/js/plugins/foundation.plugin.js
// By default, files from the directory "/node_modules" are not processed by the Babel loader,
// so in the Webpack configuration,
// an exception was added for loading from the directory "/node_modules/foundation-sites/js".
import { Plugin } from 'foundation-sites/js/foundation.plugin';
export {Plugin};
2) /resources/assets/js/plugins/foundation.util.mediaQuery.js
// By default, files from the directory "/node_modules" are not processed by the Babel loader,
// so in the Webpack configuration,
// an exception was added for loading from the directory "/node_modules/foundation-sites/js".
import { MediaQuery } from 'foundation-sites/js/foundation.util.mediaQuery';
export {MediaQuery};
In the fourth, I created a file for my plugin using the Foundation
plugins template, which include 2 of the above files:
/resources/assets/js/plugins/cropText.js
'use strict';
import $ from 'jquery';
import { MediaQuery } from './foundation.util.mediaQuery';
import { Plugin } from './foundation.plugin';
/**
* CropText plugin.
* @plugin app.cropText
*/
class CropText extends Plugin {
/**
* Creates a new instance of CropText.
* @class
* @name CropText
* @fires CropText#init
* @param {Object} element - jQuery object to add the trigger to.
* @param {Object} options - Overrides to the default plugin settings.
*/
_setup(element, options = {}) {
this.$element = element;
this.options = $.extend(true, {}, CropText.defaults, this.$element.data(), options);
this.className = 'CropText'; // ie9 back compat
this._init();
}
/**
* Initializes the CropText plugin.
* @private
*/
_init() {
MediaQuery._init();
this.cropText();
}
/**
* Crops the text.
*/
cropText() {
var size = +this.options.cropSize;
$(this.$element).each(function(i, value) {
var $valueText = $(value).text(),
$valueHtml = $(value).html();
if($valueText.length > size){
$(value).html('<span>' + $valueText.slice(0, size).trim() + '</span>' + '...').wrapInner('<a></a>');
var revealId = '#' + $(value).attr('data-open');
if ($(revealId + ' .close-button').attr('data-close') != undefined) {
$(revealId + ' .close-button').before($valueHtml);
} else {
$(revealId).append($valueHtml);
}
new Foundation.Reveal($(revealId), {
'data-overlay' : false
});
} else {
$(value).removeAttr('data-open').removeAttr('tabindex');
}
});
}
}
/**
* Default settings for plugin
*/
CropText.defaults = {
/**
* The size of the cropped text.
* @option
* @type {number}
* @default 255
*/
cropSize: 255
};
export {CropText};
It's all. Next, I just need to include a standard JavaScript file in the HTML code of the page and initialize the Foundation (example):
/resources/views/layouts/app.blade.php
<script src=" {{ mix('/js/app.js') }} "></script>
<script>
$(document).foundation();
</script>
P.S. Sorry for my English ;-), I used Google Translate.
While @roberto's answer looks great, I wanted to provide a simpler solution (in which it does not require any extra vendor/foundation files).
In your webpack config use this:
// this will force the export of the jQuery 'foundation' function,
// which we'll use later on
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'
})
]
And in your index.js:
// thanks to the ProvidePlugin we don't need to
// > import $ from 'jquery';
// required 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 force-exported in the config
// above to the jQuery object in use in this file
$.fn.foundation = foundation;
// ready to go
$(document).ready(function() {
$(document).foundation();
…
});
NOTE #1 (thank you @mtyson)
You need to use the exports loader: $ npm install --save exports-loader
or $ npm install --save-dev exports-loader
NOTE #2
Since jQuery is not global inside single modules (or for some other reason that is beyond my understanding), there might be problems relying on data-
attributes for Foundation JS components. If that is the case, you can always use the pure javascript way as documented in Foundation docs.