2015-12-15 43 views
19

我正在使用带有WebPack和NPM的Zurb Foundation,没有 Bower。NPM + Zurb Foundation + WebPack:无法解析模块'foundation'

我遇到的问题是一样的,因为这下面:

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。

+0

timaschew的回答很简单,我http://stackoverflow.com/a/35373347/1783439 –

回答

7

我已经能够通过webpack做到这一点,本质上是把它作为一个模块进行加载。

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

该问题源于Foundation的JS以源代码中的嵌套IFFE中的不规则方式引用依赖关系。有时jQuery是本地的jQuery参数,有时它是$,有时候是window.jQuery。这真是一个混合包。所有不同机制的组合意味着没有单一的匀场解决方案,而只是非模块化地加载物体。

老实说,这里非常有业余时间,但截至撰写本文时,他们上周刚刚发布了这个东西,所以希望它很快就会解决。

安美居...到弓:

我做一个单独的供应商捆绑并加载所有的业余小时的第三方故宫图书馆那里,因为我只是厌倦了所有必要的包裹的各种匀场机制的战斗运行良好的开源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" 
    } 
}; 
+1

使用你如何提供了jQuery的基础脚本,需要匀场? – Mihail

+1

啊,对不起,我只发布了我的供应商包的一个片段。在我的供应商捆绑中,我采用基本相同的方式进行升级。将更新答案。 –

+2

可悲的是我得到一个'Uncaught TypeError:$(...)。基础是不是一个函数'在浏览器:(。应该是一个很好的完整的例子... – slothy

2

这是我如何使用黑客。我把基础和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]' } 
    ] 
    } 
}; 
7

我会根据梅森Houtz并且如果药(pharmakon)的伟大的答案后我的完整的解决方法也可以帮助别人,因为我与它挣扎了一下,在这个过程中学习的WebPack。

在我的情况下,我有一个额外的复杂,因为其他jQuery插件只能在自己的模块内工作,而在他们的属性之外是undefined。显然他们使用的是本地重复的jQuery对象。

无论如何,这里就是你需要做什么:

  1. 安装脚本装载机:npm install --save-dev script-loader

  2. 在的WebPack的配置:

    • 添加新条目,让我们称之为vendor 。每当Webpack运行时,这将编译一个新的vendor.js

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

      entry : { 
          // ... 
      }, 
      externals: { 
          jquery: "jQuery" 
      } 
      
  3. 确保使用jQuery的每一个模块导入它:

    var $ = require('jquery'); 
    

以上externals配置将与全球jQuery变量的引用取代,而不是重新它,正确导入重复的jQuery。 (可选)您可以使用ProvidePlugin,它会在模块中遇到jQuery时自动执行上述操作,为您节省几个按键。如果你想要的是,摆在的WebPack的配置如下:

plugins: [ 
    // ..., 
    new webpack.ProvidePlugin({ 
     '$': 'jquery', 
     jQuery: 'jquery' 
    }) 
] 
  • 包括新vendor.js到您的网页,主要JS之前明显。
  • 这很可能有一个更简单或更优雅的方式来做到这一点,但我只是想要一个快速的工作解决方案,直到基金会希望尽快解决问题。

    14

    我有同样的问题,但我不想有两个.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:

    import Foundation from './libs/foundation'; 
    
    +1

    这个解决方案很好用;) – Mik378

    +0

    是的,它确实如此。我试图将它与反应样板整合,这似乎已经完成了。现在到网站:) – ariestav

    4

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

    在你的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-属性的问题。如果是这种情况,您可以始终使用Foundation文档中记录的纯JavaScript方式。

    +1

    我不得不包括在我的package.json中:“exports-loader”:“^ 0.6.3”, – mtyson

    +0

    此外,要使样式工作,必须看基础 - 所有内容都包含在内:http://stackoverflow.com/a/35373347/467240 – mtyson

    +0

    当我试图将这与'foundation.dropdown'一起使用时,我得到一个错误'Can not read property'register'of undefined'。有任何想法吗? – jkinz

    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

    +0

    谢谢,不得不看你的模板一段时间,以获得样式工作 – mtyson

    +3

    简单,它的工作 – vumaasha

    +0

    这工作粘滞导航和vue.js一旦我添加了'外部:{foundation:'基金会'},到webpack.conf根据Roberto Correia解决方案 –

    1

    它的工作原理罚款为webpack如果你可以告诉它忽略define测试的麻烦代码如下:

    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'); 
    
    1

    如果您仔细查看基金会网站6.2。0模块,你会发现在路径中的变化如下

    1. 基础的网站/距离/ CSS/foundation.min.css
    2. 基础的网站/距离/ JS/foundation.min。 JS

    所以基本上你必须在的WebPack confing文件条目修改如下

    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');