web-dev-qa-db-ja.com

NPM + Zurb Foundation + WebPack:モジュール 'foundation'を解決できません

私はZurb FoundationをWebPackとNPMで使用することに取り組んでいますwithoutBower。

私が遭遇している問題は、以下と同じです:

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

代わりにbowerを介してファンデーションを含めることでこれを回避できますが、bowerを削除してNPMのみを使用したいと思います。

19
mtyson

私は同じ問題を抱えていますが、2つの.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';
16
Roberto Correia

メイソン・ハウツとファーマコンの優れた答えに基づいた完全な回避策を投稿します。それが誰かを助ける場合です。

私の場合、他のjQueryプラグインは何らかの形で独自のモジュール内でのみ動作し、プロパティの外側はundefinedであったため、複雑さが増しました。どうやら、ローカルの重複したjQueryオブジェクトを使用していたようです。

とにかく、あなたがする必要があるものは次のとおりです。

  1. インストールスクリプトローダー:npm install --save-dev script-loader

  2. Webpackの設定:

    • 新しいエントリを追加し、vendorと呼びましょう。これにより、新しいvendor.js Webpackが実行されるたび。

      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 configは、重複したjQueryを「適切に」再インポートする代わりに、グローバルjQuery変数への参照に置き換えます。オプションで、ProvidPluginを使用することもできます。これは、モジュール内でjQueryに遭遇するたびに上記を自動的に実行し、いくつかのキーストロークを節約します。必要な場合は、Webpackの構成に次を追加します。

plugins: [
    // ...,
    new webpack.ProvidePlugin({
      '$': 'jquery', 
      jQuery: 'jquery'
    })
]
  1. 新しいvendor.jsあなたのページに、明らかにメインJSの前に。

これを行うためのより簡単でエレガントな方法がある可能性は十分にありますが、Foundationが問題をすぐに修正するまで、迅速で実用的なソリューションが必要でした。

これをwebpackで行うには、基本的にモジュールとしてロードするエンドランを実行しました。

これは基本的にハックですが、Foundationは本当にJSをcommonJSモジュールとしてロード可能に更新する必要があります。

問題は、ソースコード内のネストされたIFFE内から不安定な方法で依存関係を参照するFoundationのJSに起因します。 jQueryはローカルjQueryパラメーターである場合もあれば、$である場合も、window.jQueryである場合もあります。それは本当に混合袋です。すべての異なるメカニズムの組み合わせは、モジュール化されていないものをロードする以外に、単一のシミングソリューションがないことを意味します。

正直なところ、かなりアマチュアの時間ですが、この記事の執筆時点では先週リリースされたばかりなので、すぐに修正されることを願っています。

Anyhoo ...ハックへ:

別々のベンダーバンドルを作成し、アマチュアアワーのサードパーティnpmライブラリをすべてロードします。これは、出荷が不十分なオープンソースnpmパッケージコードをラップするために必要なさまざまなシミングメカニズムとの戦いにうんざりしているためです。

ベンダーバンドルは、webpackに登録する個別のエントリポイントであり、モジュールとしてNiceを再生しないすべてのライブラリが含まれています。

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に指示します。 (しかし、明らかにそうではありません。)

ファンデーションを取得し、独自の解決ルールを作成して、Foundation-libraryの内容だけをチェックすることもできますが、気にする必要はありませんでした。このハック。

また、メインのWebpack構成では、jQueryと、この方法で外部としてロードされた他のグローバルウィンドウ変数を参照する必要があります。

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

スクリプトローダー(npm i script-loader)を使用し、インポートの前にscript!を付けるだけです。その後、グローバルスコープで評価されます。

Foundationからすべてのjsファイルをロードするには、これを使用します

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

エントリポイント で行うように

ボイラープレートプロジェクトをチェックして試してみてください: https://github.com/timaschew/r3-foundation-boilerplate

5
timaschew

@robertoの答えは素晴らしく見えますが、より簡単なソリューション(追加のベンダー/ファウンデーションファイルを必要としない)を提供したかったのです。

あなたのウェブパックの設定でこれを使用します:

// 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は単一モジュール内ではグローバルではないため(または、私の理解を超えた他の何らかの理由で)、data- Foundation JSコンポーネントの属性。その場合は、Foundationのドキュメントに記載されているように、常に純粋なJavaScriptの方法を使用できます。

4
mjsarfatti

ハックの使用方法は次のとおりです。ベンダーと呼ばれる別のエントリポイントにFoundationとjqueryを配置し、スクリプトローダーでロードしました。関連するビットは、ベンダーエントリポイントのみです。

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

foundation-sites 6.2.モジュールを注意深く見ると、次のようなパスの変更が見つかります。

  1. foundation-sites/dist/css/foundation.min.css
  2. foundation-sites/dist/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');

1
Dhaval Shekhada

私自身は、このソリューションを使用しました:

Laravelフレームワークを使用しているので、first.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-foundationFoundation/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');

3番目Foundationプラグインを含めるための2つのファイルを作成しました。

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

4番目のでは、上記の2つのファイルを含む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>

追伸英語で申し訳ありません;-)、Google翻訳を使用しました。

1
Grisha_K

以下の厄介なコードの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');
1
Mike M

これは、質問で言及されている技術に関連した初心者の質問でウェブ検索から着陸する一般的な場所です。

ここに私の SCSSとWebpackのサンプルプロジェクトを使用したZurb Foundation があります。

クローンを作成してください。 Unlicenseでライセンスされています。

バックグラウンド

モジュールの互換性の問題はZurb Foundationの最新(> 6.4)バージョンで解決されていますが、基本的なセットアップは初心者にとっては黒魔術のように見えるかもしれません。私の他の、おそらくもっと良い例がどこかにあるに違いないと思いますが、私はそれらを見つけることができませんでした。学習の旅の成果をここに追加します。これにより、誰かの乗り心地が少しでこぼこしないようになります。

1
Peter Lamberg