【问题标题】:Pre-compile pug templates and save access to htmlWebpackPlugin.options预编译 pug 模板并保存对 htmlWebpackPlugin.options 的访问
【发布时间】:2019-10-26 18:19:47
【问题描述】:

我决定在我的 webpack 项目中将 ejs 转换为 pug 作为模板引擎。我需要的是预编译的静态输出(无论是在开发模式下还是在生产模式下)。另外,我需要通过编译过程将数据传递给模板,为此我使用了htmlWebpackPlugin 的自定义选项。项目结构如下:

root
|--package.json
|--webpack.configs // .dev.js, build.js
|--data.json
|--layout.pug
|--app
|--|--index.js
|--|--views
|--|--|--index.pug
|--|--|--includes
|--|--|--|--nav.pug
|--|--|--|--footer.pug
|--assets
|--|--(styles, images...)

我找到并尝试的第一种方法是将数据传递到入口点(在 index.js 编译本地变量并通过 innerHTML = 将它们插入页面)。这种方式绝对不适合我,因为我需要 100% 预编译的静态输出而不需要运行时 HTML 插入。然后乐趣就开始了……

例如,我需要创建导航。我的导航架构如下:

module.exports.nav = [
        {
          text: 'Home',
          href: '/'
        },
        {
          text: 'Offers',
          href: '/offers.html'
        },
        {
          text: 'Subnav Parent Test',
          isSubnavTrigger: true
        },
        {
          text: 'Subnav Item',
          href: '/test.html',
          isSubnavItem: true,
          subnavParent: 'Subnav Parent Test'
        }
      ]

这个app/views/includes/nav.pug的哈巴狗部分:

nav.navbar(role="navigation", ariaLabel="navigation")
  .container
    .navbar-brand
      a.navbar-item(href="/")
        img(src="/assets/images/logo.png", alt=title)
    .navbar-menu(id="navbar-menu")
      .navbar-start
      .navbar-end
        for link, index in nav
          //- TODO: isActive
          if !link.isSubnavTrigger && !link.isSubnavItem
            a(href=link.href, class="navbar-item")= link.text
          else if link.isSubnavTrigger
            .navbar-item.has-dropdown.is-hoverable
              a.navbar-link= link.text
              .navbar-dropdown
                - var parent = link.text
                - var dd = nav.filter(_item => _item.subnavParent === 
parent)
                each dd_link in dd
                  a.navbar-item(href=dd_link.href)= dd_link.text

该部分包含在通用布局中layout.pug:

- var { title, nav } = htmlWebpackPlugin.options;
<!DOCTYPE html>
html(lang="en")
  head
    title= title + 'Pug Webpack Test'
    block metas
  body
    header
      include ./app/views/includes/nav.pug

    main
      block content

    footer  
      include ./app/views/includes/footer.pug

希望app/views/includes/nav.pug 将插入nav 变量。

所以我发现了两种情况:使用module -&gt; rules -&gt; loader 和内联加载器到 HTMLWebpackPlugin。

第一个。 webpack.config.js设置:

module.exports = {
  module: {
    rules: [
      //...
      {
        test: /\.pug$/,
        use: ['file-loader?name=[path][name].html', 'pug-html-loader?pretty&exports=false']
      }
      //...
    ],
  },
  plugins: [
    //...
    new HtmlWebpackPlugin({
      template: './layout.pug',
      filename: 'index.html',
      title: 'siteTitle',
      nav: nav  // required somewhere at the top of the file
    })
  ]
}

在这种情况下,我无法将 htmlWebpackPlugin 中的选项传递到模板中。正如layout.pug 中提到的,我尝试从选项中破坏title 和nav 字段并得到编译错误:Cannot read property 'options' of undefined。

第二种情况。 webpack.config.js:

module.exports = {
  module: {
    rules: [
      //...
      // Removed PUG loaders
      //...
    ],
  },
  plugins: [
    //...
    new HtmlWebpackPlugin({
      template: '!!pug-loader!./layout.pug', // <- inlined loader
      filename: 'index.html',
      title: 'siteTitle',
      nav: nav  // required somewhere at the top of the file
    })
  ]
}
// by the way, in case of EJS I've been using exactly this approach
// and it worked out pretty well with partials

这种方法完美地编译了 layout.pug 与来自 htmlWebpackPlugin 的选项,直到它不包含包含的部分。我需要将我的nav 传递给相应的部分并从那里渲染导航。并且部分开始向编译中抛出错误,好像它不理解 pug 并需要加载器:

  ERROR in ./app/views/includes/nav.pug 13:12
    Module parse failed: Unexpected token (13:12)
    You may need an appropriate loader to handle this file type.
    |       .navbar-start
    |       .navbar-end
    >         for link, index in nav
    |           //- TODO: isActive
    |           if !link.isSubnavTrigger && !link.isSubnavItem
     @ ./app/views/index.pug (c:/_npmg/node_modules/pug-loader!./app/views/index.pug) 4:514-543

我完全一团糟。我不想退缩到ejs,但如果我找不到答案,似乎我将不得不这样做。

谢谢转发。

【问题讨论】:

    标签: webpack pug-loader


    【解决方案1】:

    我想将他的解决方案通知 OP,但我无法发表评论。

    HtmlWebpackPlugin 和 pug-loader 可以很好地协同工作。而不是使用:

    // webpack.config file
    new HtmlWebpackPlugin({
          template: './layout.pug',
          filename: 'index.html',
          myContent: 'loremp ipsum'
        })
    
    // app/views/partials/nav.pug
    - var { myContent } = htmlWebpackPlugin.options
    p= myContent
    

    您可以使用以下语法:

    // webpack.config file
    new HtmlWebpackPlugin({
       template: './layout.pug',
       filename: 'index.html',
       templateParameters: {
           myContent: 'loremp ipsum'   
       }
    })
    
    // app/views/partials/nav.pug
    p= myContent
    

    它适用于所有 pug 引擎功能,并且我们获得了更具可读性的模板。

    【讨论】:

    • 谢谢,会尝试使用这种方法的。
    【解决方案2】:

    已解决。

    答案包含两个结论:

    1. 使用适当的加载器。

      唯一适合我需要的加载器是pug-loader(不是pug-html-loader,也不是多个加载器链)。参考是here,但用2个字:

      pug-loader:返回一个函数

      pug-html-loader:返回一个字符串,所以是静态的,不能传递任何选项

      因此,与此相关的最终webpack.config.js 设置是:

    module.exports = {
      module: {
        rules: [
          //...
          test: /\.pug$/,
          use: [
            {loader: 'pug-loader'}
          ]
          //...
        ],
      },
      plugins: [
        //...
        new HtmlWebpackPlugin({
          template: './layout.pug', // <- NOT inlined loader
          filename: 'index.html',
          title: 'siteTitle',
          nav: nav  // required somewhere at the top of the file
        })
      ]
    }
    
    1. 部分不会从需要部分的布局继承变量。

      所以,由于我想使用来自htmlWebpackPlugin.options 的数据,我必须在通用布局文件中声明此数据的变量不是,但在部分本身中:

    // app/views/partials/nav.pug
    - var { nav } = htmlWebpackPlugin.options
    
    nav.navbar(... and the other code you've seen above)
    

    如果有人遇到这个问题,这是 100% 可行的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多