【问题标题】:Django/Webpack - How to serve generated webpack bundles with webpack dev serverDjango/Webpack - 如何使用 webpack 开发服务器提供生成的 webpack 包
【发布时间】:2019-12-15 01:54:59
【问题描述】:

Django 的“静态”标签使用 STATIC_URL 生成 url,其结果类似于“/static/myapp/js/bundle.js” 同时,webpack-dev-server 正在从 url 'localhost:3000' 提供捆绑包

我的问题是如何让 Django 'static' 模板标签为 js 包生成不同的 url(指向 webpack 开发服务器)。当然,我可以在模板中对其进行硬编码,但这不是一个好的解决方案。

下面是我的项目配置

webpack.config.js

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const BundleTracker = require('webpack-bundle-tracker')


module.exports = {
    mode: 'development',
    context: path.dirname(path.resolve(__dirname)),
    entry: {
        index: './typescript_src/index.ts',
    },
    output: {
        path: path.resolve('./myproject/assets/myapp/bundles/'),
        filename: "[name]-[hash].js"
    },
    resolve: {
        extensions: ['.ts', '.js' ]
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.ts$/,
                use: 'ts-loader',
                exclude: /node_modules/
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new BundleTracker({filename: './myproject/webpack-stats.json'})
    ],
    devServer: {
        port: 3000,
        publicPath: '/myapp/bundles/',
        // hot: true,
        headers: {
            "Access-Control-Allow-Origin": "http://127.0.0.1:8000", /**Django dev server */
        }
    }
}

settings.py

WEBPACK_LOADER = {
    'DEFAULT': {
        'CACHE': not DEBUG,
        'BUNDLE_DIR_NAME': 'myapp/bundles/', # must end with slash
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
        'POLL_INTERVAL': 0.1,
        'TIMEOUT': None,
        'IGNORE': [r'.+\.hot-update.js', r'.+\.map']
    }
}

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'assets'),
)

最初我决定 webpack 在开发过程中也应该提供其他静态文件

webpack.config.js

devServer: {
        port: 3000,
        publicPath: '/myapp/bundles/',
        contentBase: path.resolve('./myproject/assets')
        // hot: true,
        headers: {
            "Access-Control-Allow-Origin": "http://127.0.0.1:8000", /**Django dev server */
        }

settings.py

# in development mode serve from wepack dev server
if DEBUG:
    STATIC_URL = 'http://localhost:3000/'
else:
    STATIC_URL = '/static/'

但后来我意识到我必须提供其他应用程序(admin、tinymce、...)的静态文件,这是 webpack 开发服务器无法访问的

这里的问题是 django-webpack-loader (/static/myapp/bundles/bundle-name.js) 的 'render_bundle' 标签生成的 url 会导致 Http 404 因为 webpack-dev-server 保留在内存中而不是在磁盘上生成包

如果我设置了

STATIC_URL = localhost:3000

并配置 webpack-dev-server 为我的应用程序的其他静态文件提供服务,其他应用程序的静态文件将不会被提供

【问题讨论】:

    标签: javascript python django webpack webpack-dev-server


    【解决方案1】:

    通常使用 STATICFILES_DIRS 是不合理的, 而是使用 STATIC_ROOT。 如果您有权将静态文件复制到项目文件夹,请使用 STATIC_ROOT。

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案2】:

    基于@Ejez 的回答,我能够配置 webpack-dev-server 以提供所有静态文件(包括媒体文件)

    webpack.config.js

    module.exports = {
        // project root (usually package.json dir)
        context: path.dirname(path.resolve(__dirname)),
        output: {
            path: path.resolve('./path/to/bundles/'), 
            filename: "[name]-[hash].js"
        },
        resolve: {
            extensions: ['.ts', '.js' ]
        },
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.ts$/,
                    use: 'ts-loader',
                    exclude: /node_modules/
                }
            ]
        },
        plugins: [
            new CleanWebpackPlugin(),
            new BundleTracker({filename: '/path/to/webpack-stats.json'})
        ],
        optimization: {
            splitChunks: {
                chunks: 'all',
                name: 'lib'  // bundle all their party libraries in lib.js
            }
        },
        devServer: {
        // if you do not mind webpack serving static files of other apps
        // collect them (with django collectstatic) into /static_root/static/ 
        // this way webpack-dev-server can serve from your own app's /static/
        // directory and also /static_root/static/ directory (which contains
        // static files of other apps
            contentBase: [path.resolve('./project'), path.resolve('./project/static_root')],
    
            // webpack bundles will be served from http://locahost:3000/static/project/bundles/
            publicPath: '/static/project/bundles/',
    
            port: 3000,
    
            // proxy all request except (static and media files) to django dev server
            proxy: [{
                context: ['**', '!/static/**', '!/media/**'],
                target: 'http://localhost:8000',
                changeOrigin: true,
            }]
        }
    }
    

    现在您可以从 webpack-dev-server url localhost:3000 访问您的项目。不要忘记启动两个开发服务器(webpack 和 django)

    【讨论】:

    • 这对于快速开发来说似乎有点低效,因为每次修改非 webpack 静态文件时都需要收集静态文件。为什么不让事情变得简单,让 webpack-dev-server 只提供 webpack 的东西,并将对 django 的请求代理到 django 开发服务器。
    • 是的,如果您每次更改应用程序中的静态文件时都必须收集静态文件,那就是这样。但我的意思是收集它们一次以访问其他应用程序的静态文件,并且每次安装第三方应用程序(偶尔会发生)。
    【解决方案3】:

    我们来分析一下问题:

    我们有 2 台服务器,我们希望根据请求的路径将请求路由到其中一台:

    "/static/webpackbundles/** ==> webpack dev server

    other paths ==> django dev server

    这正是代理服务器的工作,它可以通过第三台服务器(haproxy,nginx ...)来实现,但这似乎有点过头了,特别是如果我们知道webpack dev server 可以用作代理! (https://webpack.js.org/configuration/dev-server/#devserverproxy)

    webpack.config.js

    const path = require('path');
    
    module.exports = {
      mode: 'development',
      entry: './src/index.js',
      output: {
        filename: 'main.js',
        path: '/path/to/django_project/django_project/static/webpackbundles',
        publicPath: '/static/webpackbundles/',
      },
      devServer: {
        contentBase: '/path/to/django_project/django_project/static/webpackbundles',
        hot: true,
        proxy: {
          '!/static/webpackbundles/**': {
            target: 'http://localhost:8000', // points to django dev server
            changeOrigin: true,
          },
        },
      },
    };
    

    在您的 django 模板中:

    <script type="text/javascript" src="{% static 'webpackbundles/main.js' %}"></script>
    

    现在使用webpack dev server 地址访问您的 django 应用程序/站点: 例如:http://localhost:8081

    通过这个简单的配置,您将拥有浏览器自动刷新和热模块更换。 您不需要在 django 中更改任何内容,也不需要 django-webpack-loader

    【讨论】:

    • 您的解决方案很好,而且很有效,谢谢。但是我们仍然需要 django-webpack-loader 来渲染正确的包名,因为生成的包名是 [name]-[hash].js 的形式。当然,如果我们不将 [hash] 部分添加到包名称中,我们可以不使用 django-webpack-loader。
    • 不需要用webpack添加hash,django可以做到(这样会保证非webpack静态文件也有hash),只要把这个添加到你的django设置文件中:STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'(见@ 987654322@)。这将为您省去添加/维护额外 django 包的麻烦。
    • 不知道 ManifestStaticFilesStorage。但是查看文档,它似乎需要 DEBUG=False 和其他要求。这仍然让我觉得如果 webpack 做添加哈希部分会更自然。但仍然很高兴知道 Django 拥有它。它可能会在其他时候派上用场
    • 你也可以使用html-webpack-plugin创建带有自动注入webpack包(js,css ...)的html文件,这些文件可以从django base.html模板扩展,也可以进一步扩展以创建最终的 django 页面模板。请参阅 herehere ,这是我认为比使用 django-webpack-loader 更好的解决方案。 @myke
    猜你喜欢
    • 2019-12-06
    • 1970-01-01
    • 2016-06-26
    • 1970-01-01
    • 2017-11-09
    • 2016-12-23
    • 1970-01-01
    • 2019-08-31
    • 2016-04-24
    相关资源
    最近更新 更多