web-dev-qa-db-ja.com

Webpackでパブリック静的ファイルを提供する

Webpackを思い通りに構成するのに苦労しています。私は開発サーバーをlocalhost:808で実行し、localhost:8080/static/js/bundle.jsを介してアプリを提供したいと思っています。以下に添付したwebpack.config.jsファイル私が添付したファイル構造では、dist/staticにある他のファイルも静的ファイルとして提供したいので、localhost:8080/static/css/style.cssたとえばこれを提供しますdist/static/css/style.cssファイル。

それはおそらく私が設定ファイルでやった何か間違っている、そして私はあなたが理解できるように私が質問をしているのかどうかわからないのでwebpackに慣れていません。

私のディレクトリツリーは:

client
  -- /dist
    -- /templates
      -- /admin
        -- index.html
    -- /static
      -- /css
        -- style.css
      -- /js
  -- /node_modules
  -- /src
  -- /test
  -- package.json
  -- webpack.config.json

webpack.config.js

var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

var plugins = [
    new webpack.ProvidePlugin({
        'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
    }),
    new ExtractTextPlugin('app.css', {
        allChunks: true
    }),
    new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
    })
];

var cssLoader = {};

if(process.env.NODE_ENV == 'production'){
    plugins.Push(
        new webpack.optimize.UglifyJsPlugin()
    );

    cssLoader = {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
    };

} else {

    cssLoader = {
        test: /\.css$/,
        loaders: [
            'style?sourceMap',
            'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
        ]
    }

}

module.exports = {
    entry: [
        'react-hot-loader/patch',
        'webpack-dev-server/client?http://localhost:8080',
        'webpack/hot/only-dev-server',
        './src/index.js'
    ],
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                exclude: /node_modules/,
                loaders: ['babel']
            },
            cssLoader
        ]
    },
    resolve: {
        extensions: ['', '.js', '.jsx']
    },
    output: {
        path: __dirname + '/dist/static',
        publicPath: '/static/js',
        filename: 'bundle.js'
    },
    devServer: {
        contentBase: './dist/templates/admin',
        hot: true,
        historyApiFallback: true
    },
    plugins: plugins
};

dist/templates/admin/index.html

<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
    <link href="static/css/style.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div id="app"></div>
<script src="static/js/bundle.js"></script>
</body>
</html>

みんなありがとう :)

9
Dima Gimburg

問題

問題の原因は、WebpackDevServerが1つのフォルダーからのみ提供されることです。提供する必要があるフォルダーは、index.htmlを含むフォルダーです。これは、正常に実行していることです。

これまでのところ、提供しているのは./dist/templates/adminのコンテンツのみなので、他のディレクトリでファイルを検索すると、404が返されます。ここでの唯一の例外はバンドルです。ルートへのすべてのリクエストを行うpublicPathを設定しているので、/static/jsはメモリに保存されている出力にリダイレクトされます。

他のフォルダーからサービスを提供できるようにするには、WebpackDevServerが必要です。特定のケースでは、パス./dist/static/cssをリクエストするときに、/static/cssからもサービスを提供する必要があります。


解決

WebpackDevServerにいくつかのミドルウェアを設定する必要があります。 devServer.setupのドキュメント で説明されているように行うことができます。そのためには、おそらくすでにExpressを使用しているので、 express.static を使用することをお勧めします。

Expressが必要です。

const express = require('express')

次に、devServerを次のように変更します。

devServer: {
  contentBase: './dist/templates/admin',
  hot: true,
  historyApiFallback: true,
  setup (app) {
    app.use('/static/css/',
      express.static(path.join(__dirname, 'dist', 'static', 'css')));
    /* Using this commented code will break the HMR, see edit
    app.use('/static/js/',
      express.static(path.join(__dirname, 'dist', 'static', 'js')));
    */

    // in general
    app.use('/public/route/',
      express.static('/your/local/path'));
  }
}

このようにして、開発パスとビルドパスは同じままで、WebpackDevServerは必要なルートで必要な静的ファイルを提供します。

編集する

上記のコードがHot Module Replacementに違反していることを発見しました。その理由は、セットアップのミドルウェアが/static/js/を処理しているため、バンドルがメモリではなくファイルシステムから提供されるためです。

バンドルをメモリからフェッチし続けるには、publicPathプロパティでoutputを定義し、devServer.setup内のカスタムミドルウェアからは処理しないでください。

module.exports = {

  output: {
    path: ...,
    filename: ...,
    publicPath: '/static/js/'
  },

  devServer: {
    contentBase: './dist/templates/admin',
    hot: true,
    historyApiFallback: true,
    setup (app) {
      app.use('/static/css/',
        express.static(path.join(__dirname, 'dist', 'static', 'css')));
    }
  },

  // other properties: entry, module, etc.
}
10
Daniel Reina

あなたはポート8080でアプリを提供しています。あなたのwebpack設定で、コンテンツベースのdist/template/Adminを設定していることがわかりますが、そのフォルダーはどこにも表示されません。コンテンツベースを設定すると、そのフォルダーからAdmin.htmlが提供され、そのファイルで依存関係を宣言している場合は、ユーザーから読み込まれます。 このシードを確認できます 詳細については、.

1
Jorawar Singh

そのため、明らかに、ある意味で、別のサーバーを実行しているときに、webpack-dev-serverをCSSや他の静的JSなどの静的ファイルをロードするためのバックエンドとして使用することは想定されていません。 contentBaseキーを特定のディレクトリに設定すると、ドキュメントにはindex.htmlファイルを作成する必要があり、このディレクトリに基づいてファイルを提供できると記載されています。

他のディレクトリから静的ファイルを提供する必要があり、webpack-dev-serverと並行して実行している別のサーバーがある場合は、 ドキュメントのこのセクション に注意してください。

私がしたことは、webpack-dev-serverをlocalhost:808で実行し、バックエンドサーバーをlocalhost:30で実行し、バックエンドサーバーがadmin/index。 htmlルートルートからlocalhost:3000 /にあり、htmlファイル自体でbundle.jsのインポートを絶対パスに変更<script src="http://localhost:8080/static/js/bundle.js"></script>

ホットリロードが正常に機能するようになりました。Webpack構成ファイルからcontentBase paramを削除することもできます。

重要:

  1. 希望どおりにWebpackを実行し、ホットリロードを実際に機能させるには、実行中に-inlineを追加します。たとえば、webpack-dev-server --progress --colors --hot --config ./webpack.config.js --inline
  2. iframeモードを使用することもできますが、これについては詳しく説明していません。
  3. それでもプロジェクトをビルドするときに手動で絶対パスを削除する必要があるという問題が発生しました。今それを自動的に解決する方法を探しています。
1
Dima Gimburg