NPM + Zurb Foundation + WebPack: Cannot resolve mo

2019-01-31 08:25发布

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.

9条回答
时光不老,我们不散
2楼-- · 2019-01-31 09:23

Here is how I am using the hack. I put foundation and jquery in a separate entry point called vendor and loaded them with the script-loader. The only relevant bits are in the vendor entry point.

var path = require('path');
var webpack = require('webpack');
var hotMiddlewareScript = 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true';
var autoprefixer = require('autoprefixer');

module.exports = {
  name: 'main',

  devtool: 'eval',

  entry: {
    client: [
      path.resolve(__dirname, 'client', 'index.js'),
      hotMiddlewareScript
    ],
    vendor: [
      'font-awesome/css/font-awesome.css',
      'foundation-sites/dist/foundation-flex.css',
      '!!script!jquery/dist/jquery.min.js',
      '!!script!foundation-sites/dist/foundation.min.js',
    ]
  },

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: '/dist/'
  },

  resolve: {
    modulesDirectories: ['node_modules', './client'],
    extensions: ['', '.js', '.jsx']
  },

  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
    new webpack.ProvidePlugin({'$': 'jquery', jQuery: 'jquery'})
  ],

  module: {
    loaders: [
      { test: /\.(js|jsx)$/, loaders: ['react-hot', 'babel-loader'], exclude: /node_modules/, include: path.resolve(__dirname, 'client') },
      { test: /\.scss$/, loader: "style!css!autoprefixer-loader?browsers=last 2 versions!sass" },
      { test: /\.css$/, loader: "style!css" },
      // { test: /\.(png|jpg|jpeg|gif)$/, loader: 'file-loader?name=images/[name].[ext]' },
      { test: /\.(webm|mp4|mov|m4v|ogg)$/, loader: 'file-loader?name=videos/[name].[ext]' },
      { test: /\.(eot|svg|ttf|woff|woff2)/, loader: 'file-loader?name=fonts/[name].[ext]' }
    ]
  }
};
查看更多
迷人小祖宗
3楼-- · 2019-01-31 09:24

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.

查看更多
SAY GOODBYE
4楼-- · 2019-01-31 09:31

It works fine for webpack if you can tell it to ignore the define test for the troublesome code below:

  if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
     module.exports = Reveal;
  if (typeof define === 'function')
     define(['foundation'], function() {
     return Reveal;
  });

The best way to do that is to use the imports-loader and set define to false.

require('foundation-sites/js/foundation.core.js');
require('foundation-sites/js/foundation.util.keyboard.js');
require('foundation-sites/js/foundation.util.box.js');
require('foundation-sites/js/foundation.util.triggers.js');
require('foundation-sites/js/foundation.util.mediaQuery.js');
require('foundation-sites/js/foundation.util.motion.js');
require('imports?define=>false!foundation-sites/js/foundation.reveal.js');
查看更多
登录 后发表回答