使用Webpack提供公共静态文件服务

15

我很难按照自己的想法配置webpack。

我在localhost:8080上运行开发服务器,并希望通过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配置文件

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>

谢谢大家 :)

3个回答

14

问题

问题的根源在于WebpackDevServer只能从一个文件夹中提供服务。你应该提供包含index.html的文件夹,这正是你正在正确地做的。

到目前为止,你仅提供了./dist/templates/admin的内容,因此当你查找其他目录中的文件时,会得到404错误。唯一的例外是你的bundle,因为你设置了一个publicPath,使任何对路由/static/js的请求都被重定向到存储在内存中的输出。

你需要让WebpackDevServer能够从其他文件夹中提供服务。在你的特定情况下,当你请求路径/static/css时,你还需要从./dist/static/css中提供服务。


解决方案

您需要在WebpackDevServer中设置一些中间件。您可以按照devServer.setup的文档中所述进行操作。为此,我建议您使用express.static,因为您可能已经在使用Express。

您需要引入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会在所需的路由上提供你需要的静态文件。
编辑
我刚刚发现上述代码会破坏热模块替换。原因是setup中的中间件处理了/static/js/,因此bundle从文件系统而非内存中提供。
为了从内存中继续获取bundle,请在output属性中定义publicPath,并不要在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.
}

我尝试了几个版本,但似乎无法让它正常工作。如果您能查看我的问题并提供帮助,那就太好了,谢谢。https://stackoverflow.com/questions/47054824/webpack-middleware-with-jekyll-setup-for-context-path - Rhys

2

您正在8080端口上提供应用程序。在您的webpack配置中,我看到您设置了内容基础dist/template/Admin,但我没有看到那个文件夹。当您设置内容基础时,它将从该文件夹中提供Admin.html,并且如果您在该文件中声明了依赖项,则会从中加载。您可以查看这个种子来了解更多信息。


你是对的,我忘记包含这个目录了。admin/index.html在localhost:8080/上正常服务,static/js/bundle.js也正常服务,但static/css/style.css返回404错误。我会尝试查看你附加的资源。我已经编辑了问题。 - Dima Gimburg
哦,抱歉,我添加了一个HTML文件,通过常规的链接标签导入CSS,只是一个相对路径的静态文件。 - Dima Gimburg
你能否看到文件在浏览器中被加载了吗? - Jorawar Singh
我会尝试将contentbase更改为只有dist,然后使用导航到template/admin.html。使用contentbase将从当前目录中提供静态文件。 - Jorawar Singh
谢谢,问题是我想在我的目录结构中保持顺序,并将所有HTML模板存储在一个目录中,但在本地主机的根目录中提供admin/index.html。我会尝试一下contentbase。再次感谢。 - Dima Gimburg
让我们在聊天中继续这个讨论 - Jorawar Singh

1
显然,webpack-dev-server并不适合用作后端加载静态文件(如CSS或其他静态JS)的服务器,尤其是在您同时运行另一个服务器时。当您将contentBase键设置为特定目录时,文档说明您必须在该目录下创建一个index.html文件,并且可以基于此目录提供文件。
如果您想从其他目录提供静态文件,并且您有另一个服务器与webpack-dev-server并行运行,请注意文档中的这一部分
我所做的是在localhost:8080上运行webpack-dev-server,而在localhost:3000上运行我的后端服务器,并从其根路由服务于admin/index.html,在localhost:3000/上。在HTML文件本身中,我将bundle.js的导入更改为绝对路径<script src="http://localhost:8080/static/js/bundle.js"></script>

现在热重载已经正常工作了,我也可以从我的webpack配置文件中删除contentBase参数。

重要提示:

  1. 为了使webpack按我们想要的方式运行并使热重载真正起作用,只需在运行时添加--inline,例如:webpack-dev-server --progress --colors --hot --config ./webpack.config.js --inline
  2. 你也可以使用iframe模式,但我没有深入研究它。
  3. 仍然存在一个问题,就是构建项目时必须手动删除绝对路径,这很烦人。现在正在寻找自动解决它的方法。

查看我的解决方案。在开发或生产中,您不需要更改路径。 - Daniel Reina

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接