使用webpack提供公共静态文件

serve public static files with webpack

我很难按照自己的意愿配置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不太熟悉,所以我不知道我是否在问这个问题,以便您可以理解。

我的目录树是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
client
  -- /dist
    -- /templates
      -- /admin
        -- index.html
    -- /static
      -- /css
        -- style.css
      -- /js
  -- /node_modules
  -- /src
  -- /test
  -- package.json
  -- webpack.config.json

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
    My App
    <link href="static/css/style.css" type="text/css" rel="stylesheet" />
</head>
<body>

<script src="static/js/bundle.js">
</body>
</html>

谢谢大家:)


问题

问题的根源是WebpackDevServer仅从一个文件夹提供服务。您应该从中提供服务的文件夹是包含index.html的文件夹,这就是您正在正确执行的操作。

到目前为止,您只提供./dist/templates/admin的内容,因此,当您在其他目录中查找文件时,您会得到404。这里唯一的例外是您的捆绑包,因为要设置的publicPath对路由/static/js的任何请求都将重定向到您的输出,该输出存储在内存中。

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

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

您需要Express:

1
const express = require('express')

然后,只需如下修改devServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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在所需的路由处提供所需的静态文件。

编辑

我刚刚发现上面的代码破坏了热模块更换。原因是安装程序中的中间件正在处理/static/js/,因此该捆绑包是从文件系统而不是内存中提供的。

要继续从内存中获取捆绑软件,请在output属性中定义一个publicPath,并且不要从devServer.setup内部的自定义中间件进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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.
}


您正在端口8080上提供该应用程序。在您的Webpack配置中,我看到您设置了内容库dist / template / Admin,但是在任何地方都没有看到该文件夹??。设置内容库时,它将从该文件夹中提供Admin.html,并且如果您在该文件中声明了依赖项,它将从您那里加载。您可以查看此种子以了解更多信息。


因此,显然,从某种意义上讲,当您在一边运行另一台服务器时,不应将webpack-dev-server用作后端以加载诸如CSS或其他静态JS之类的静态文件。当您将contentBase键设置为特定目录时,文档说您必须在其中创建一个index.html文件,并且可以在此目录下提供文件。

如果要从其他目录提供静态文件,并且有另一台服务器与webpack-dev-server并排运行,请注意文档的这一部分。

我所做的是在localhost:8080上运行webpack-dev-server,在localhost:3000上运行后端服务器,而后端服务器从root:localhost:3000 /上运行admin / index.html,并且在html文件本身中,将bundle.js的导入更改为绝对路径<script src="http://localhost:8080/static/js/bundle.js">

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

重要:

  • 现在可以按照我们想要的方式运行webpack并真正实现热重装,只需在运行时添加--inline即可,例如:webpack-dev-server --progress --colors --hot --config ./webpack.config.js --inline
  • 您还可以使用iframe模式,但我没有深入研究它。
  • 仍然存在一个问题,即在构建项目时我必须手动删除绝对路径,这很烦人。寻找如何立即自动解决。