我该如何告诉grunt-usemin忽略Django的静态模板标签?

8
我正在构建一个Django应用程序,用于提供单页面Angular应用程序。
Django提供Angular的index.html文件,其中包含以下usemin脚本块:
<!-- build:js scripts/scripts.js -->
<script src="{% static "scripts/app.js" %}"></script>
<script src="{% static "scripts/controllers/main.js" %}"></script>
<script src="{% static "scripts/controllers/stats.js" %}"></script>
<script src="{% static "scripts/directives/highchart.js" %}"></script>
<!-- endbuild -->

Usemin试图在文件系统中查找"{% static "scripts/app.js" %}",当然失败了,因为它真正应该尝试查找的是"scripts/app.js"。

有人知道解决这个问题的方法吗?


你是用 grunt build 构建网站的吗?在向客户端提供代码时,不应该包含 usemin 块,这只与 grunt 有关,与后端无关(据我所知)。 - Patrick
我正在尝试利用Django的反向URL查找静态URL,因此我从Django路由中提供Angular的index.html,这使我可以在index.html中使用Django模板标签。但我已经放弃了这种方法,现在将从静态URL访问index.html,而不是从一个正确的Django路由。我会直接承担风险,如果我的静态文件URL发生变化,我将手动更新index.html。 - forte
@davemckenna01 自从你最初询问以来,你有没有发现任何新的进展?我目前正在使用grunt/yeoman与Angular,并将工作流程与django集成在一起,这使我的工作速度变慢了很多。 - kevins
@kvseelbach 我也遇到了同样的问题。你找到了解决方法吗? - lakenen
2
@lakenen 我想继续使用Grunt和生成器,所以我编辑了配置并安装了grunt-text-replace,并设置了一些搜索/替换。replace: { example: { src: ['<%= yeoman.dist %>/*.html'], overwrite: true, replacements: [{ from: '<script src="scripts', to: '<script src="/static/mdb/scripts' }] } } - kevins
2个回答

9

好的,我认为我有一个解决方法。假设您希望生成的文件也指向内置资产的静态网址。

这将需要您在视图上下文中定义 STATIC_URL(而不是使用 src="{% static 'foo/bar.js'%}" 您将使用 src="{{STATIC_URL}}foo/bar.js")。 我无法在未修改 grunt-usemin 源代码的情况下使 {% static %} 正常工作。

因此,使用您的示例,这样做:

<!-- build:js {{STATIC_URL}}scripts/scripts.js -->
<script src="{{STATIC_URL}}scripts/app.js"></script>
<script src="{{STATIC_URL}}scripts/controllers/main.js"></script>
<script src="{{STATIC_URL}}scripts/controllers/stats.js"></script>
<script src="{{STATIC_URL}}scripts/directives/highchart.js"></script>
<!-- endbuild -->

编译后的结果如下:

<script src="{{STATIC_URL}}scripts/scripts.js"></script>

为了实现这一点,我需要在Gruntfile.js中添加以下grunt配置:
// custom createConfig script for replacing Django {{STATIC_URL}} references
// when building config for concat and cssmin
var path = require('path');
function createDjangoStaticConcatConfig(context, block) {
  var cfg = {files: []};
  var staticPattern = /\{\{\s*STATIC_URL\s*\}\}/;

  block.dest = block.dest.replace(staticPattern, '');
  var outfile = path.join(context.outDir, block.dest);

  // Depending whether or not we're the last of the step we're not going to output the same thing
  var files = {
    dest: outfile,
    src: []
  };
  context.inFiles.forEach(function(f) {
    files.src.push(path.join(context.inDir, f.replace(staticPattern, '')));
  });
  cfg.files.push(files);
  context.outFiles = [block.dest];
  return cfg;
}


grunt.initConfig({
    /*...*/

    // add a preprocessor to modify the concat config to parse out {{STATIC_URL}} using the above method
    useminPrepare: {
      html: 'app/index.html',
      options: {
        dest: 'dist',
        flow: {
          steps: {
            js: [
              {
                name: 'concat',
                createConfig: createDjangoStaticConcatConfig
              },
              'uglifyjs'
            ],
            // also apply it to css files
            css: [
              {
                name: 'cssmin',
                createConfig: createDjangoStaticConcatConfig
              }
            ]
          },
          // this property is necessary
          post: {}
        }
      }
    },

    // add a pattern to parse out the actual filename and remove the {{STATIC_URL}} bit
    usemin: {
      html: ['dist/{,*/}*.html'],
      css: ['dist/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['dist'],
        patterns: {
          html: [[/\{\{\s*STATIC_URL\s*\}\}([^'"]*)["']/mg, 'django static']]
        }
      }
    },


    // if you are using bower, also include the jsPattern to automatically 
    // insert {{STATIC_URL}} when inserting js files
    'bower-install': {
      app: {
        html: 'app/index.html',
        jsPattern: '<script type="text/javascript" src="{{STATIC_URL}}{{filePath}}"></script>'
      }
    }
});

工作很棒,但输出没有生成{{STATIC_URL}}前缀。 - Yousuf Jawwad
1
嘿,谢谢,这解决了我的 PHP 问题。对于那些遇到这个问题的人来说,“post: {}”属性是必需的。 - stalin
@stalin 是的,没错。我会在那里做个注释,这样更明显。谢谢! - lakenen
1
@mouse,我遇到了与{{STATIC_URL}}无关的同样问题-我不得不添加一个blockReplacements部分,返回类似于return '<script src="{{STATIC_URL}}path/'+block.dest+'"></script>'; - Victor Roetman

3

我在Google搜索解决方案时一直找到这个问题,所以我在这里分享我发现的解决方案,以便像我这样的其他人可以找到它。

我刚刚发现了一个名为grunt-bridge的grunt插件,它可以使用static标签将静态文件包装在html模板中。文档不是很好,但我弄清楚了如何使其适用于我的项目。

如果您有以下脚本:

<!-- build:js({.tmp,app}) /scripts/scripts.js -->
    <script src="scripts/app.js"></script>
    <script src="scripts/util/util.js"></script>
    ...

最终输出应该是像这样的内容:
<script src="{% static 'adjangoappname/scripts/94223d51.scripts.js' %}"></script>

使用npm install grunt-bridge --save-dev安装Gruntbridge,并在Gruntfile.js的grunt.initConfig中添加以下配置:

bridge: {
  distBaseHtml: {
      options: {
          pattern: '{% static \'adjangoappname{path}\' %}',
          html: '<%= yeoman.minifiedDir %>/index.html', dest: '<%= yeoman.templateDir %>/index.html'
      }
  },
  distIndexHtml: {
      options: {
          pattern: '{% static \'adjangoappname{path}\' %}',
          html: '<%= yeoman.minifiedDir %>/index.html', dest: '<%= yeoman.templateDir %>/index.html'
      }
  },
  // ... etc for each html file you want to modify
},

其中<%= yeoman.minifiedDir %>是最终压缩的HTML文件的输出目录,而<%= yeoman.minifiedDir %>则是目标模板目录。将adjangoappname替换为您的Django应用程序名称或任何要使用的目录前缀。

然后将grunt-bridge添加到registerTask列表的末尾,如下所示:

grunt.registerTask('build', [
    //...
    'htmlmin',
    'bridge'
]);

我认为可以让配置更加紧凑,但这是我发现的第一种可行的方法。


grunt-bridge插件非常好用。我使用yeoman-webapp测试了它。由于grunt-bridge不喜欢缺少引号的'htmlmin',我需要从“build”任务中删除'htmlmin'。 - tsand

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