2015-05-14 11 views
5

Mam aplikację izomorphic React, która działa zarówno w przeglądarce, jak i na serwerze. Zbudowałem ten sam kod dla obu, uruchamiając dwie oddzielne kompilacje Webpacka poprzez dwa różne punkty wejścia i różne konfiguracje.Zewnętrzne elementy zewnętrzne w węźle i przeglądarce

Problem polega na tym, że plik zewnętrzny, który istnieje w oknie przeglądarki za pomocą zewnętrznego znacznika skryptu (Google Maps w tym przypadku) oczywiście nie będzie istnieć podczas pracy w węźle na serwerze. Kod jest identyczny z wyjątkiem pliku punktu wejścia.

index.html:

// index.html 
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=XXX"></script> 

uproszczony config:

// Server Webpack config 
{ 
    entry: 'server.js', 
    target: 'node', 
    externals: { 
     google: google 
    } 
} 

// Client Webpack config 
{ 
    entry: 'client.js', 
    target: 'browser', 
    externals: { 
     google: google 
    } 
} 

Komponent:

// The view which builds and runs fine in 
// the client but doesn't run on the server. 
var React = require('react'), 
    css = require('./style.css'), 
    google = require('google'); // Nope, not on the server obviously! 

var Component = React.createClass({ 

    render: function() { 
     return (
      <div> 
       // Do maps stuff 
      </div> 
     ); 
    } 

}); 
module.exports = Component; 

Moje pytanie brzmi jak mam sobie z tym poradzić?

Error: Cannot find module 'google' 

Obecnie mam rozwiązanie, którego w ogóle nie lubię.

// Server Webpack config 
{ 
    entry: 'server.js', 
    target: 'node', 
    externals: { 
     google: google 
    }, 
    plugins: [ 
     new webpack.DefinePlugin({ 'ENV.browser': false }), 
    ] 
} 

// Client Webpack config 
{ 
    entry: 'client.js', 
    target: 'browser', 
    externals: { 
     google: google 
    }, 
    plugins: [ 
     new webpack.DefinePlugin({ 'ENV.browser': true }), 
    ] 
} 

// The component 
var React = require('react'), 
    css = require('./style.css'); 

if (ENV.browser) { 
    var google = require('google'); 
} 

var Component = React.createClass({ 

    render: function() { 
     return (
      <div> 
       if (ENV.browser) { 
        // Do maps stuff 
       } 
      </div> 
     ); 
    } 

}); 
module.exports = Component; 

Odpowiedz

5

Można użyć NormalModuleReplacementPlugin wymienić moduł z noop, jak na pomysł z Dustan Kasten:

{ 
    plugins: [ 
    new webpack.NormalModuleReplacementPlugin(/^google$/, 'node-noop'), 
    ], 
} 
+0

Dzięki wygląda to wygodne! A co, kiedy faktycznie zacznę uzyskiwać dostęp do właściwości obiektu zewnętrznego? Czy po prostu sprawdzisz, czy istnieje przed rozpoczęciem pracy z nim? –

+1

To by działało. 'NormalModuleReplacementPlugin' pozwala na przeprogramowanie twojego żądania do dowolnego modułu, więc możesz również stworzyć prostą próbę modułu i użyć go na serwerze. Jeśli odwołujesz się tylko do zmiennej 'google' w metodzie cyklu życia" componentDidMount', nie ma to znaczenia, ponieważ nigdy nie zostanie wyrzucone z użycia 'React.renderToString'. –

+0

Zastanawiałem się nad tym, co to jest, ale jest to świetny argument na temat 'componentDidMount'. To jest pewność, której szukałem. Dziękuję Ci! –