预编译pug模板并保存对htmlWebpackPlugin.options的访问

时间:2019-06-12 09:21:47

标签: webpack pug-loader

在Webpack项目中,我决定从ejs转到pug作为模板引擎。我需要的是预编译的静态输出(无论是在dev还是prod模式下)。另外,我需要通过编译过程将数据传递给模板,并且为此使用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变量。

因此,我发现了2种情况:使用module -> rules -> 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中所述,我尝试从选项中破坏titlenav字段,并得到编译错误: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,但是如果找不到答案,似乎必须这样做。

谢谢。

2 个答案:

答案 0 :(得分:1)

已解决。

答案包括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中的数据,因此必须在通用布局文件中声明此数据的变量 not ,在部分自身中声明 but

// app/views/partials/nav.pug
- var { nav } = htmlWebpackPlugin.options

nav.navbar(... and the other code you've seen above)

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

答案 1 :(得分:1)

我想通知OP他的解决方案,但我不能发表评论。

HtmlWebpackPluginpug-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

它可与所有哈巴狗引擎功能一起使用,并且我们获得了更具可读性的模板。