【问题标题】:Gulp task to replace all Root-Relative URLs with Document-Relative URLsGulp 任务用文档相对 URL 替换所有根相对 URL
【发布时间】:2018-09-13 23:32:25
【问题描述】:

有 4 种不同的 URL 类型;

  1. 绝对 http://www.example.com/images/icons.png
  2. 文档相关 ../images/icons.png
  3. 根相对 /images/icons.png
  4. 协议相关 //www.example.com/images/icons.png

我有一个使用Jigsaw 构建的大型静态文件站点(html、css、js)。该框架采用 PHP 模板并将它们编译成静态 HTML。我也在使用 Gulp 任务来编译资产(sass、js..etc)。

使用 Jigsaw 的构建过程,我可以使用完整的绝对路径/url (http://example.com/path-to/page) 或根相对路径 (/path-to/page) 构建站点。

这很好,但现在客户希望网站使用 Document-Relative,因为他们现在将网站托管在一个子目录中,并且 URL 指向该子目录。

例如http://example.com 将指向 http://xx.server.com/hosted-files/directory

我的问题是 Jigsaw 不允许使用文档相对 URL。是否有一个 gulp/node 脚本可以用来转换所有引用(图像源、链接、css 路径..等)?还是有其他解决方案(例如使用 .htacccess)?

TLDR;

我需要用 Document-Relative 路径和 URL 替换多个 HTML 文件和目录中的任何 AbsoluteRoot-Relative 引用。还是有其他解决方案(例如使用 .htacccess)?

【问题讨论】:

    标签: html .htaccess url-rewriting gulp


    【解决方案1】:

    我已经设法解决了我自己的问题,我觉得这是一个“hacky”修复。

    我基本上创建了一个自定义 gulp 插件,用文档相对路径替换 URLs/paths..etc。

    gulpfile.js - relative-urls 任务在所有其他任务完成后运行。

    const relative = require('./tasks/document-relative');
    gulp.task('relative-urls', function() {
        return gulp.src('build/**/*.html')
            .pipe( relative({
                directory: 'build',
                url: 'http://localhost:8000',
            }) )
            .pipe( gulp.dest('build') );
    });
    

    ./tasks/document-relative.js - 插件

    'use strict';
    
    const fs            = require('fs');
    const PluginError   = require('plugin-error');
    const through       = require('through2');
    
    const PLUGIN_NAME   = 'document-relative';
    
    let count = 0;
    
    module.exports = function(options) {
    
        // Remove slashes from beginning and end of string
        const strip_slashes = (string) => {
            return string ? string.replace(/^\/|\/$/g, '') : null;
        }
    
        // Users options object
        options = options || {};
    
        // Cleanup options
        const base_dir  = strip_slashes(options.directory);
        const url       = strip_slashes(options.url) + '/';
    
        return through({
            objectMode: true,
            writable: true,
            readable: true
        },
        function(file, enc, callback) {
            count++;
    
            // Check for null file
            if (file.isNull()) {
                return callback(null, file);
            }
    
            if (file.isStream()) {
                this.emit('error', new PluginError(PLUGIN_NAME, 'Stream not supported!'));
                return callback(null, file);
            }
    
            if (file.isBuffer()) {
    
                // Get contents of this file
                let html        = file.contents.toString(enc);
    
                // This files full path (/home/usr/project/build/page/example/index.html)
                const path      = file.path;
    
                // Path task was run from (/home/usr/project/)
                const cwd       = file.cwd+( base_dir ? '/'+base_dir : '' );
    
                // Project specific path (/page/example/index.html)
                const relative  = path.replace(cwd, '');
    
                // Get array of directories ['page', 'example', 'index.html']
                let paths       = strip_slashes(relative).split('/');
    
                // Remove last item ['page', 'example']
                paths.pop();
    
                // Add ../ for nth number of paths in array
                let rel_path    = paths.length === 0 ? '' : ('../'.repeat(paths.length));
    
                // Replace dom attributes (e.g. href="/page/example")
                html = html.replace( /(?:(?!="\/\/)="\/)/g, '="'+rel_path );
    
                // Replace inline background (e.g. background: url('/image/something.jpg'))
                html = html.replace( /url\(\'\//g, 'url(\''+rel_path );
                html = html.replace( /url\('\//g, 'url(''+rel_path );
    
                // If user defined URL, match and remove
                if (url && url.length) {
                    html = html.replace( new RegExp(url, 'g'), rel_path );
                }
    
                // Overwrite file
                fs.writeFileSync(file.path, html, {
                    encoding: enc,
                    flag:'w'
                });
    
                return callback();
            }
        });
    };
    

    这基本上会打开我的构建文件夹中的所有.html 文件,计算每个文件的深度路径(/folder1/folder2/index.html),并将urlhttp://localhost:8000)的任何实例替换为@987654327 @ 重复计算的路径数。

    【讨论】:

      【解决方案2】:

      节点有path.relative

      • 阅读 Levi Coles 自己的 answer 以了解 urldirectory 的来源。
      const path = require("path");
      
      // create a regular expression from your url property.
      const domain_expression = new RegExp(url);
      
      // Once you have an offending 'href' you can do this.
      // - Here 'href' is Absolute, but this same code would work
      //   with Root-Relative paths too.
      const href = "http://localhost:8000/images/icons.png";
      const file_index = href.lastIndexOf("/") + 1;
      const file_component = href.substring(file_index);
      const root_relative = href.replace(domain_expression, "");
      const relative_href = path.relative(`${directory}/${root_relative}`, directory);
      const _href = relative_href + file_component;
      // _href = ../../icons.png
      
      

      【讨论】:

      • 这太棒了!我将不得不玩。感谢您让我注意到path.relative :)
      猜你喜欢
      • 2018-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多