Django/Webpack - 如何使用 webpack 开发服务器提供生成的 webpack 包
Posted
技术标签:
【中文标题】Django/Webpack - 如何使用 webpack 开发服务器提供生成的 webpack 包【英文标题】:Django/Webpack - How to serve generated webpack bundles with webpack dev server 【发布时间】: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 为我的应用程序的其他静态文件提供服务,其他应用程序的静态文件将不会被提供
【问题讨论】:
【参考方案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 页面模板。请参阅 here 和 here ,这是我认为比使用 django-webpack-loader 更好的解决方案。 @myke以上是关于Django/Webpack - 如何使用 webpack 开发服务器提供生成的 webpack 包的主要内容,如果未能解决你的问题,请参考以下文章
Vue.js img src 使用绝对路径(django+webpack)
在 vue + django webpack 应用程序中处理页面
使用 Django、webpack、reactjs、react-router 解耦前端和后端
manage.py runserver 可以执行 npm 脚本吗?