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.com/zurb/foundation-sites/issues/7386
Essentially, when installing foundation-sites via NPM, there are references to a module "foundation" that is not found. The error:
Module not found: Error: Cannot resolve module 'foundation' in c:\Users\Matt\Documents\Projects\test\node_modules\foundation-sites\dist
@ ./~/foundation-sites/dist/foundation.js
Here's the package.json:
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server"
},
"author": "",
"license": "ISC",
"dependencies": {
"foundation-sites": "6.0.5",
"webpack": "~1.12.6",
"webpack-dev-server": "~1.2",
"jquery": "2.1.1"
}
}
And here is webpack.config.js:
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
main: "./app/js/main.js"
},
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" },
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
},
{ test: /\.vue$/, loader: 'vue' }
],
resolve: {
modulesDirectories: ['node_modules']
}
},
sassLoader: {
includePaths: [path.resolve(__dirname, "./node_modules/foundation-sites/scss/")]
},
devServer: {
proxy: {
'/api/*': {
target: 'http://localhost:4567',
secure: false
}
}
}
};
I can work around this by including foundation via bower instead, but I want to eliminate bower and use only NPM.
I'll post my complete workaround based on Mason Houtz and pharmakon's great answers in case it helps someone, since I struggled with it a bit, learning Webpack in the process.
In my case I had an added complication, because other jQuery plugins were somehow working only inside their own module, while outside their properties were
undefined
. Apparently they were using a local, duplicate jQuery object.Anyway, here's what you need to do:
Install scripts-loader:
npm install --save-dev script-loader
In Webpack's config:
Add new entry, let's call it
vendor
. This will compile a newvendor.js
whenever Webpack runs.Add
jquery
to externals. This makes sure any references tojquery
inside your main JS will be replaced with a reference to globaljQuery
variable, which is made available byvendor.js
above.Make sure every module that uses jQuery imports it:
The
externals
config above will replace it with a reference to globaljQuery
variable, instead of re-importing duplicate jQuery "properly". Optionally you could make use of ProvidePlugin, which will automatically do the above whenever it encounters jQuery in a module, saving you a few keystrokes. If you want that, put the following in Webpack's config:vendor.js
to your page, obviously before the main JS.It's quite possible there's an easier or more elegant way to do this, but I just wanted a quick, working solution, until Foundation hopefully fixes the issue soon.
For myself, I used this solution:
I'm using the Laravel framework, so first I added the
.webpackConfig (...)
method to thewebpack.mix.js
file:Note: To install
Foundation
I used the package https://github.com/laravel-frontend-presets/zurb-foundation. And added the code to loadFoundation
into the/resources/assets/js/bootstrap.js
file: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):Third, I created two files for including the
Foundation
plugins:1)
/resources/assets/js/plugins/foundation.plugin.js
2)
/resources/assets/js/plugins/foundation.util.mediaQuery.js
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
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
P.S. Sorry for my English ;-), I used Google Translate.
I have same problem, but I don't want have two .js files (vendor and app)!
For me, everything need be on a single file, so, I make this:
In webpack.conf.js, use externals (maybe have another way without external, but for me, this is sufficient):
create a file in your source folder (any name, like /libs/foundation.js):
now, you can use Foundation in any js using following syntax:
I was able to do this with webpack by essentially doing an end-run around loading it as a module.
This is basically a hack though, Foundation really needs to update its JS to be loadable as a commonJS module.
The problem stems from Foundation's JS referencing dependencies in erratic ways from within nested IFFEs in the souce code. Sometimes jQuery is the local jQuery parameter, sometimes it's $, sometimes it's window.jQuery. It's really a mixed-bag. The combination of all the different mechanisms means there's no single shimming solution other than to just load the thing non-modularly.
Honestly it's pretty much amateur hour in there, but as of this writing they just released the thing last week, so hopefully it'll be fixed soon.
Anyhoo... to the hack:
I make a separate vendor bundle and load all the amateur-hour 3rd party npm libraries there because I just get tired of fighting with all the various shimming mechanisms necessary to wrap poorly-shipped open-source npm package code.
My vendor bundle is a separate entry point that I register with webpack, and it contains all the libraries that do not play nice as modules.
Make sure you have script-loader installed
The !! means "Ignore all the other rules I already defined in the config". Using the script-loader tells webpack to load and execute the file in the window scope essentially the same as if you had just included a script tag on your page. (But it doesn't, obviously.)
You could get fancier and write your own resolve rules so that it checks just stuff in the foundation-library, but I didn't bother because I hope a library as pervasive as Foundation gets their act together in the near future so I can just delete this hack.
Also... in your main webpack configuration you will want to reference jQuery and any other global window variables loaded in this way as externals.
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
and the entry for style should be like this
require('style!css!foundation-sites/dist/css/foundation.min.css');
Just use the script-loader (
npm i script-loader
) and prefix your imports with ascript!
. Then it will be evaluated in the global scope.To load all js files from foundation use this
Like I do it in my entry point
You can check out my boilerplate project to try it out: https://github.com/timaschew/r3-foundation-boilerplate