跳转到主要内容

透明地使用webpack与django

项目描述

django-webpack-loader

Build Status Coverage Status pyversions djversions

使用简单的模板标签将Webpack包集成到Django模板中

{% load render_bundle from webpack_loader %}

<html>
  <head>
    {% render_bundle 'main' 'css' %}
  </head>
</html>

幕后,Django Webpack Loader消耗由webpack-bundle-tracker生成的stats文件,并允许您在Django中使用生成的包。

提供变更日志

兼容性

通常,Python、Django和Node LTS版本将支持到EOL。有关详细信息,请检查tests/tox.ini
不在tests/tox.ini中列出的版本可能仍然可以使用,但维护者不会测试它们,也不会解决与它们相关的问题。
以下示例在Webpack 5中。

安装

npm install --save-dev webpack-bundle-tracker

pip install django-webpack-loader

配置

要启动一个带有有见地的开发和生产设置的完整示例项目,您可以查看django-react-boilerplate。对于更灵活的配置,请继续阅读。

配置webpack-bundle-tracker

在配置 django-webpack-loader 之前,我们先配置 webpack-bundle-tracker 所需的内容。更新你的 Webpack 配置文件(它通常位于项目根目录下的 webpack.config.js)。确保你的文件看起来像这样(根据需要调整):

const path = require("path");
const webpack = require("webpack");
const BundleTracker = require("webpack-bundle-tracker");

module.exports = {
  context: __dirname,
  entry: "./assets/js/index",
  output: {
    path: path.resolve(__dirname, "assets/webpack_bundles/"),
    publicPath: "auto", // necessary for CDNs/S3/blob storages
    filename: "[name]-[contenthash].js",
  },
  plugins: [
    new BundleTracker({ path: __dirname, filename: "webpack-stats.json" }),
  ],
};

上面的配置期望 index.js(应用程序入口文件)位于 /assets/js/ 目录内(本指南后续将假定所有前端相关文件都放置在 /assets/ 目录下,不同类型的文件按其子目录排列)。

生成的编译文件将放在 /assets/webpack_bundles/ 目录下,有关包和资源的 统计文件webpack-stats.json)将存储在项目根目录。你可以将 webpack-stats.json 添加到 .gitignore 中。

配置 Django 设置文件

首先,将 webpack_loader 添加到 INSTALLED_APPS 中。

INSTALLED_APPS = (
    ...
    'webpack_loader',
    ...
)

以下是使用 django-webpack-loader 时 Django 设置文件的推荐设置。

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

WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'webpack_bundles/',
        'CACHE': not DEBUG,
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
        'POLL_INTERVAL': 0.1,
        'IGNORE': [r'.+\.hot-update.js', r'.+\.map'],
    }
}

请注意,你必须设置你的静态资源和 Webpack 包所在的路径到 STATICFILES_DIRS

对于这种设置,我们使用 Django 提供的 DEBUG 变量。由于在生产环境中(DEBUG = False),资产文件不会不断更改,我们可以安全地缓存结果(CACHE=True)并优化流程,因为 django-webpack-loader 只会读取一次统计文件并将资产路径存储在内存中。如果 CACHE=False,我们将始终读取统计文件以获取资产路径。

STATS_FILE 参数表示由 webpack-bundle-tracker 生成的输出文件。由于在 Webpack 配置文件中我们将其命名为 webpack-stats.json 并存储在项目根目录,我们必须在后端复制这个设置。

在开发过程中,统计文件会经常更改,因此我们希望始终检查其更新版本(每 0.1 秒检查一次,如 POLL_INTERVAL 所定义)。

⚠️ 在生产环境(DEBUG=False)中,我们只获取一次统计文件,因此 POLL_INTERVAL 被忽略。

IGNORE 是一个正则表达式列表。如果由 Webpack 生成的文件与其中一个表达式匹配,则该文件不会被包含在模板中。

编译前端资产

使用 Webpack,在使用 django-webpack-loader 在 Django 模板中之前,你必须使用 webpack-bundle-tracker 生成前端包和统计文件。请注意,你可能会在开发和生产中使用不同的配置。流程应如下所示

flowchart TD
    A("Run webpack")
    A --> |CSS, JS, imgs, fonts| B(Collect compiled assets)
    A --> |webpack-stats.json| C(Read on Django templates)

在开发中,我们可以简单地这样做

# in one shell
npx webpack --mode=development --watch

# in another shell
python manage.py runserver

查看开发中的完整示例

此外,通过特定的配置,还提供了热重载。查看本节

⚠️ 对于在生产环境中编译和提供前端资产,请参阅本节

用法

为了将前端代码渲染到 Django 模板中,我们使用 render_bundle 模板标签。

它的行为是接受一个字符串,包含统计文件中入口点的名称(在我们的例子中,我们使用 main,这是 默认),然后它会继续包含该入口点下的所有文件。你可以在这里了解更多关于入口点概念的信息这里

⚠️ 你也可以在这里查看如何使用多个 entry 值的示例这里

以下是模板中 render_bundle 的基本用法

{% load render_bundle from webpack_loader %}

<html>
  <head>
    {% render_bundle 'main' 'css' %}
  </head>
</html>

这将渲染模板中所需的正确 <script><link> 标签。

在测试中使用

为了运行出现在 render_bundle 中的测试,由于在那个点我们没有 webpack-bundle-tracker 来生成统计文件,渲染包的调用将会失败。解决方案是在您的测试设置中使用 FakeWebpackLoader

WEBPACK_LOADER['DEFAULT']['LOADER_CLASS'] = 'webpack_loader.loaders.FakeWebpackLoader'

在生产环境中使用

建议的方法是在 部署阶段 生成前端包和统计文件的生产管道。我们建议将生成的包和统计文件放在版本控制之外。换句话说,将 webpack-stats.jsonassets/webpack_bundles/ 添加到您的 .gitignore

假设静态文件已通过 Django 内置或类似 django-storages 正确配置,简单的生产部署可以使用 Django 的 collectstatic。请记住,Django 设置的 STATICFILES_DIRSBUNDLE_DIR_NAMESTATS_FILE 和 Webpack 的 output.path 必须兼容

// webpack.config.js
module.exports = {
  // ...
  context: __dirname,
  output: {
    // Emit bundle files at "assets/webpack_bundles/":
    path: path.resolve(__dirname, "assets/webpack_bundles/"),
    publicPath: "auto", // necessary for CDNs/S3/blob storages
    filename: "[name]-[contenthash].js",
  },
  plugins: [
    // Emit 'webpack-stats.json' in project root for Django to find it:
    new BundleTracker({ path: __dirname, filename: "webpack-stats.json" }),
  ],
};
# app/settings.py

BASE_DIR =  ... # set to project root

STATICFILES_DIRS = (
   # make Django collect all "assets/" and "assets/webpack_bundles"
   # to be served at "my-static-url.com/asset-name.png"
   # and "my-static-url.com/webpack_bundles/main.js"
   os.path.join(BASE_DIR, 'assets'),
)

WEBPACK_LOADER = {
    'DEFAULT': {
        # Bundle directory, like in "my-static-url.com/webpack_bundles/main.js":
        'BUNDLE_DIR_NAME': 'webpack_bundles/',
        # Absolute path to where 'webpack-stats.json' is in Django project root:
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
        # ...
    }
}

在您的部署脚本中,必须在调用 collectstatic 之前先以生产模式运行您的 Webpack 构建

NODE_ENV=production webpack --progress --bail --mode=production
python manage.py collectstatic --noinput

这意味着我们正在构建资产,由于我们在 Webpack 构建管道中使用了 webpack-bundle-trackerwebpack-stats.json 统计文件也被填充。如果您遵循默认配置,webpack-stats.json 将位于 Django 项目的根目录(BASE_DIR),并且 render_bundle 模板标签将能够使用它。

然而,此包的生产使用相对灵活,因为整个 Django-Webpack 集成仅依赖于 webpack-stats.json 文件。

⚠️ Heroku 是一个自动为您运行 collectstatic 的平台,因此您需要设置环境变量 DISABLE_COLLECTSTATIC=1,并在运行 Webpack 后手动运行 collectstatic。在 Heroku 上,这通过 post_compile 钩子实现。这里有一个 示例

高级使用

热重载

热重载(热模块替换)对于改善开发工作流程至关重要。如果您想为项目启用它,请查看 此示例,特别是 webpack.config.js 的配置。关键是设置 publicPathdevServer

动态导入

如果您想使用 动态导入,请查看 此示例,特别是 webpack.config.js 的配置。

webpack-bundle-tracker 的额外选项

请查看 webpack-bundle-trackerREADME 了解所有支持选项,例如相对路径、完整性散列、时间戳日志等。

Django 中的额外 WEBPACK_LOADER 设置

按照以下方式设置这些额外设置

WEBPACK_LOADER = {
    'DEFAULT': {
       # settings go here
    }
  • TIMEOUT 是 webpack_loader 等待 Webpack 完成编译并引发异常之前应等待的秒数。设置为 0None 或省略设置将禁用超时。

  • INTEGRITY 是启用 子资源完整性 的标志,用于渲染 <script><link> 标签。完整性散列从统计文件和 BundleTracker 的一侧配置中获得,其中需要配置选项 integrity: true

  • LOADER_CLASS 是一个字符串形式的完全限定 Python 类名,用于存储自定义 Webpack 加载器。这是自定义如何加载统计文件行为的地方。例如,可以从数据库、缓存、外部 URL 等加载统计文件。为了方便,可以扩展 webpack_loader.loaders.WebpackLoader。很可能会在 load_assets 方法中添加自定义行为。这应该返回一个包含统计文件的对象。

以下是从外部 URL 加载的简单示例

import requests
from webpack_loader.loaders import WebpackLoader

class ExternalWebpackLoader(WebpackLoader):
    def load_assets(self):
        url = self.config['STATS_URL']
        return requests.get(url).json()
  • SKIP_COMMON_CHUNKS(默认:False)是一个标志,防止已生成的块再次包含在同一页中。这通常发生在您在每个 Django 模板中使用多个入口点(多个 render_bundle 调用)时。通过启用此选项,您可以获得与 HtmlWebpackPlugin 相同的默认行为。使用 skip_common_chunksrender_bundle 上的注意事项相同,请参阅下面的该部分以获取更多详细信息。

根据文件扩展名渲染

render_bundle 还可以接受第二个参数,即可以匹配的文件扩展名。当您想单独渲染不同类型的文件时,这非常有用。例如,要渲染 CSS 到 head 和 JS 到底部,我们可以这样做

{% load render_bundle from webpack_loader %}

<html>
  <head>
    {% render_bundle 'main' 'css' %}
  </head>
  <body>
    ....
    {% render_bundle 'main' 'js' %}
  </body>
</head>

使用预加载

render_bundle 模板标签中,可以使用 is_preload=True 选项添加 rel="preload" 链接标签

{% load render_bundle from webpack_loader %}

<html>
  <head>
    {% render_bundle 'main' 'css' is_preload=True %}
    {% render_bundle 'main' 'js' is_preload=True %}

    {% render_bundle 'main' 'css' %}
  </head>

  <body>
    {% render_bundle 'main' 'js' %}
  </body>
</html>

访问其他 Webpack 资产

webpack_static 模板标签提供了在 Django 模板中加载由 Webpack 管理的静态资产的便利。它类似于 Django 内置的 static 标签,但用于 Webpack 资产。

在下面的示例中,logo.png 可以是任何与任何 npm 包一起分发的静态资产

{% load webpack_static from webpack_loader %}

<!-- render full public path of logo.png -->
<img src="{% webpack_static 'logo.png' %}"/>

公共路径基于 webpack.config.jsoutput.publicPath

请注意,此方法将使用原始资产文件,而不是 Webpack 管道中经过处理的文件,如果该文件已经过此流程(例如:在 React 端导入了一个图像并使用它,React 组件中使用的文件可能具有哈希字符串的名称等。此处理文件将与您使用 webpack_static 获取的文件不同)。

render_bundle 上使用 skip_common_chunks

您可以使用参数 skip_common_chunks=Trueskip_common_chunks=False 来覆盖特定捆绑包的全局 SKIP_COMMON_CHUNKS 设置。

为了使此选项生效,django-webpack-loader 需要模板上下文中存在 request 对象。默认情况下,通过 django.template.context_processors.request 上下文处理器传递 request 对象,所以请确保您有它。

如果您由于某些原因(例如使用 Template.render 或直接使用 render_to_string 而没有传递请求)在上下文中没有 request,您将在控制台收到警告,并且公共块将保持重复。

追加文件扩展名

可以使用 suffix 选项在文件 URL 的末尾追加一个字符串。例如,如果您的 Webpack 配置生成压缩的 .gz 文件,则可以这样做。

{% load render_bundle from webpack_loader %}
<html>
  <head>
    <meta charset="UTF-8">
    <title>Example</title>
    {% render_bundle 'main' 'css' %}
  </head>
  <body>
    {% render_bundle 'main' 'js' suffix='.gz' %}
  </body>
</html>

多个 Webpack 配置

django-webpack-loader 还支持多个 Webpack 配置。假设您有不同的 Webpack 配置,每个配置有不同的 output.path,则以下配置在设置中定义了 2 个 Webpack 统计文件,并使用模板标签中的 config 参数来影响从哪个统计文件加载捆绑包

WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'bundles/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
    },
    'DASHBOARD': {
        'BUNDLE_DIR_NAME': 'dashboard_bundles/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats-dashboard.json'),
    }
}
{% load render_bundle from webpack_loader %}

<html>
  <body>
    ....
    {% render_bundle 'main' 'js' 'DEFAULT' %}
    {% render_bundle 'main' 'js' 'DASHBOARD' %}

    <!-- or render all files from a bundle -->
    {% render_bundle 'main' config='DASHBOARD' %}

    <!-- the following tags do the same thing -->
    {% render_bundle 'main' 'css' 'DASHBOARD' %}
    {% render_bundle 'main' extension='css' config='DASHBOARD' %}
    {% render_bundle 'main' config='DASHBOARD' extension='css' %}

    <!-- add some extra attributes to the tag -->
    {% render_bundle 'main' 'js' 'DEFAULT' attrs='async charset="UTF-8"'%}
  </body>
</head>

文件 URL 而不是 HTML 标签

如果您需要资产 URL 而不是 HTML 标签,则可以使用 get_files 模板标签。常见用例是为 JavaScript 插件指定自定义 CSS 文件的 URL。

get_filesrender_bundle 的工作方式完全相同,除了它返回一个匹配的文件列表,并允许您将列表分配给自定义模板变量。

返回列表中的每个对象都有 2 个属性

  1. name,它是统计文件中块的名字;
  2. url,可以是
  3. 如果资源有,则为 publicPath
  4. 如果没有 publicPath,则为静态文件存储中资源的 path

例如

{% load get_files from webpack_loader %}

{% get_files 'editor' 'css' as editor_css_files %}
CKEDITOR.config.contentsCss = '{{ editor_css_files.0.url }}';

<!-- or list down name and url for every file -->
<ul>
{% for css_file in editor_css_files %}
    <li>{{ css_file.name }} : {{ css_file.url }}</li>
{% endfor %}
</ul>

Jinja2 配置

如果您需要在 Jinja 模板中输出资源,我们提供了一个与 django-jinja 兼容的 Jinja2 扩展。

要安装扩展,请将其添加到 TEMPLATES 配置中的 ["OPTIONS"]["extension"] 列表。

from django_jinja.builtins import DEFAULT_EXTENSIONS
TEMPLATES = [
  {
    "BACKEND": "django_jinja.backend.Jinja2",
    "OPTIONS": {
      "extensions": DEFAULT_EXTENSIONS + [
        "webpack_loader.contrib.jinja2ext.WebpackExtension",
      ],
    }
  }
]

然后在您的基 Jinja 模板中,执行

{{ render_bundle('main') }}

注意:Jinja2 中的 get_files 被称为 webpack_get_files

从版本 < 1.0.0 迁移

为了使用 django-webpack-loader>=1.0.0,您必须确保在 JavaScript 端使用了 webpack-bundle-tracker@1.0.0。建议您始终保持两个包的至少小版本兼容性,以实现完全兼容。

贡献

该项目包含一个 Makefile,它提供了用于构建、安装和发布项目的几个有用命令。请随时打开 PR 或创建问题!

可用命令

  • clean:删除生成的文件和目录。
  • build:清理项目并构建分发包。
  • test:运行测试。
  • install:安装项目的构建依赖项。如果不存在,将初始化虚拟环境。
  • publish:构建分发包并将它们发布到指定的仓库。
  • register:在指定的仓库中注册包。

要执行命令,请在项目的根目录中运行 make <command>

虚拟环境设置

  • ENV:虚拟环境名称。(默认:venv
  • REPOSITORY:发布分发包的仓库。(默认:pypi

特别感谢

Django Webpack Loader 最初由 Owais Lone 创建,自推出以来收到了 50 多位开发者的贡献,以及许多在问题、评论、文章、演讲等方面提供帮助的人。感谢所有为 Django Webpack Loader 社区做出贡献的人!

商业支持

alt text

该项目目前由 Vinta Software 维护,并用于 Vinta 客户的产品中。我们一直在寻找令人兴奋的工作,如果您需要任何商业支持,请随时联系我们:contact@vinta.com.br

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分发

django-webpack-loader-3.1.1.tar.gz (18.4 kB 查看哈希值)

上传于 来源

构建分发

django_webpack_loader-3.1.1-py2.py3-none-any.whl (19.0 kB 查看哈希)

上传于 Python 2 Python 3

支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面