NPM + Zurb Foundation + WebPack:无法解析模块'基础'

时间:2015-12-15 19:30:34

标签: npm zurb-foundation webpack

我正在使用Zurb Foundation和WebPack和NPM,没有 Bower。

我遇到的问题与以下相同:

https://github.com/zurb/foundation-sites/issues/7386

基本上,当通过NPM安装基础站点时,会引用未找到的模块“基础”。错误:

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 

这是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"
  }
}

这是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
            }
        }
    }
};

我可以通过凉亭包括基础来解决这个问题,但我想要消除凉亭,只使用NPM。

10 个答案:

答案 0 :(得分:16)

我有同样的问题,但我不想要两个.js文件(供应商和应用程序)!

对我来说,一切都需要在一个文件中,所以,我这样做:

webpack.conf.js 中,使用外部(可能有其他方式没有外部,但对我来说,这已经足够了):

externals: {
    jQuery: 'jQuery',
    foundation: 'Foundation'
},

在源文件夹中创建一个文件(任何名称,如 /libs/foundation.js ):

// jQuery
var $ = require('jquery');
global.jQuery = $;

// if you want all features of foundation
require('./node_modules_folder/foundation-sites/dist/foundation.js');

// if you want only some features
// require('./node_modules/what-input/what-input');
// require('./node_modules/foundation-sites/js/foundation.core');
// require('./node_modules/foundation-sites/js/....');

export default Foundation;

现在,您可以使用以下语法在任何js中使用Foundation:

import Foundation from './libs/foundation';

答案 1 :(得分:7)

我能够通过基本上在将其作为模块加载的最终运行来完成webpack。

这基本上是一个黑客,但基金会确实需要将其JS更新为可加载的commonJS模块。

问题源于基金会的JS从源代码中的嵌套IFFE中以不稳定的方式引用依赖关系。有时jQuery是本地jQuery参数,有时它是$,有时它是window.jQuery。它真的是一个混合包。所有不同机制的结合意味着除了非模块化地加载物品外,没有单一的匀场解决方案。

老实说,那里几乎是业余时间,但在撰写本文时,他们上周刚刚发布了该内容,所以希望它很快就能解决。

Anyhoo ......到了黑客:

我制作一个单独的供应商捆绑并加载所有业余时间的第三方npm库,因为我厌倦了与包装运输不良的开源npm包代码所需的所有各种填充机制的斗争。

我的供应商包是我在webpack中注册的单独入口点,它包含所有不能作为模块运行的库。

require('!!script!jquery/dist/jquery.min.js');

require('!!script!uglify!foundation-sites/js/foundation.core.js');
require('!!script!uglify!foundation-sites/js/foundation.accordion.js');
require('!!script!uglify!foundation-sites/js/foundation.util.keyboard.js');
require('!!script!uglify!foundation-sites/js/foundation.util.motion.js');
// etc.

确保安装了脚本加载器

npm install script-loader -D

!!意味着"忽略我在配置中定义的所有其他规则"。使用脚本加载器告诉webpack在窗口范围内加载和执行文件,就像在页面上包含脚本标记一样。 (但事实并非如此。)

你可以变得更好,并编写自己的解决规则,以便它只检查基础库中的内容,但我没有打扰,因为我希望像基金会一样普及的图书馆在不久的将来一起行动所以我可以删除这个黑客​​。

另外......在你的主webpack配置中,你需要引用jQuery和以这种方式加载的任何其他全局窗口变量作为外部。

var webpackConfig = {
    entry: { // blah },
    output: { // blah },
    loaders: [ // blah ],
    externals: {
        jquery: "jQuery"
    }
};

答案 2 :(得分:7)

我会根据Mason Houtz发布我的完整解决方法,以及药店帮助某人的好答案,因为我在这方面努力学习Webpack。

在我的情况下,我有一个额外的复杂性,因为其他jQuery插件只是在他们自己的模块内部工作,而在他们的属性之外是<a href="{{ route('category-with-subcategory', ['category' => $cat_id, 'subcategory' => $row->sub_id]) }}"> 。显然他们使用的是本地重复的jQuery对象。

无论如何,这是你需要做的事情:

  1. 安装scripts-loader:undefined

  2. 在Webpack的配置中:

    • 添加新条目,我们将其称为npm install --save-dev script-loader。每当Webpack运行时,这将编译一个新的vendor

      vendor.js
    • entry: { ..., "vendor": [ "!!script!jquery/dist/jquery.min.js", "!!script!foundation-sites/dist/foundation.min.js" ] }, 添加到外部。这样可以确保主JS中对jquery的任何引用都将替换为对全局jquery变量的引用,该变量由上面的jQuery提供。

      vendor.js
  3. 确保使用jQuery的每个模块都导入它:

    entry : {
        // ...
    },
    externals: {
        jquery: "jQuery"
    }
    
  4. 上面的var $ = require('jquery'); 配置会将其替换为对全局externals变量的引用,而不是重新导入重复的jQuery&#34;正确&#34;。 您可以选择使用ProvidePlugin,它会在模块中遇到jQuery时自动执行上述操作,从而为您节省一些按键。如果您需要,请将以下内容放在Webpack的配置中:

    jQuery
    1. 将新的plugins: [ // ..., new webpack.ProvidePlugin({ '$': 'jquery', jQuery: 'jquery' }) ] 包含在您的网页中,显然是在主JS之前。
    2. 很有可能这样做更容易或更优雅,但我只想要一个快速,有效的解决方案,直到基金会希望尽快解决问题。

答案 3 :(得分:5)

只需使用脚本加载程序(npm i script-loader)并使用script!为您的导入添加前缀。 然后它将在全球范围内进行评估。

要从基础加载所有js文件,请使用此

import 'script!jquery'
import 'script!what-input'
import 'script!foundation-sites'

就像我在entry point

中一样

您可以查看我的样板项目进行试用:https://github.com/timaschew/r3-foundation-boilerplate

答案 4 :(得分:4)

虽然@ roberto的答案看起来很棒,但我想提供一个更简单的解决方案(其中不需要任何额外的供应商/基础文件)。

在你的webpack配置中使用:

// 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'
  })
]

在你的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();
  …
});

注意#1 (谢谢@mtyson)
您需要使用导出加载器:$ npm install --save exports-loader$ npm install --save-dev exports-loader

注意#2
由于jQuery在单个模块中不是全局的(或者出于我理解的其他原因),因此可能存在依赖于Foundation JS组件的data-属性的问题。如果是这种情况,您可以始终使用基础文档中记录的纯JavaScript方式。

答案 5 :(得分:2)

以下是我使用黑客的方式。我将foundation和jquery放在一个名为vendor的单独入口点中,并使用脚本加载器加载它们。唯一相关的位在供应商入口点。

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]' }
    ]
  }
};

答案 6 :(得分:1)

如果您可以告诉它忽略define测试下面的麻烦代码,它适用于webpack:

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

最好的方法是使用imports-loader并将define设置为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');

答案 7 :(得分:1)

如果您仔细查看基础网站6.2.0 模块,您将在路径中找到以下更改

  1. 基础站点/ DIST / CSS / foundation.min.css
  2. 基础站点/ DIST / JS / foundation.min.js
  3. 所以基本上你必须更改webpack confing files条目,如下所示

    module.exports =  {
             entry: ['script!jquery/dist/jquery.min.js',
            'script!foundation-sites/dist/js/foundation.min.js',
             './app/app.jsx'
           ]
    }
    

    并且样式的条目应该是这样的

    require('style!css!foundation-sites/dist/css/foundation.min.css');

答案 8 :(得分:1)

我自己使用了以下解决方案:

我使用的是Laravel框架,因此首先我将.webpackConfig (...)方法添加到了webpack.mix.js文件中:

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()
                }
            ]
        }]
    }
});

注意: 要安装Foundation,我使用了软件包https://github.com/laravel-frontend-presets/zurb-foundation。并添加了将Foundation加载到/resources/assets/js/bootstrap.js文件中的代码:

/**
 * 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) {}

其次,我创建了文件/resources/assets/js/plugins/entries/foundation.js(该文件包含在// The app plugins for the Foundation.上方的代码中)。在其中包括我的模块(示例):

import { CropText } from '../cropText';
Foundation.plugin(CropText, 'CropText');

第三,我创建了两个文件来包含Foundation插件:

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};

在第四个中,我使用Foundation插件模板为我的插件创建了一个文件,其中包括上述文件中的两个:

/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};

全部。接下来,我只需要在页面的HTML代码中包含标准JavaScript文件并初始化Foundation(示例)即可:

/resources/views/layouts/app.blade.php

<script src=" {{ mix('/js/app.js') }} "></script>

<script>
    $(document).foundation();
</script>

P.S。抱歉,我的英文;-),我使用了Google翻译。

答案 9 :(得分:1)

这是从Web搜索中获取与问题中提到的技术相关的初学者的常见地方。

这是我的 Zurb Foundation with SCSS and Webpack Example Project

随时克隆它。它是由Unlicense授权的。

背景

尽管,模块兼容性问题已由Zurb Foundation的最新版本(> 6.4)解决,但对于初学者而言,基本设置似乎仍然是不可思议的事情。我认为在某处肯定还有其他示例,可能还有更好的示例,但我只是找不到它们。我在这里添加学习之旅的成果,希望这将使某人的骑行过程不再那么坎bump。