angular/angular-cli

Jade support in webpack releases

ShadowManu opened this issue ยท 43 comments

Sorry for not providing template information but I only have my phone available (and there's no critical info either).

Is there some in-the-works support for jade? The related issues/PR 's were closed but no real solution was provided. What can be done to have support for this?

So you guys closed #996 and #968 in favor of #40, then closed #40 with no specific ending, then closed the efforts in #1433 and #626 because you changed to webpack and here we are with no answers.

Sorry, I'm not trying to be annoying, specially when I see a lot of hate on recent issues with bugs regarding latest TS/Angular/CLI combinations. I can understand error because we are humans, I can understand time because we need to sleep and have to live, but I do hate purposeful indifference, just because its not your problem. I'm open to work myself on the CLI on a new PR, but I do need guidance, and that really starts at least with a single answer in a timelapse of 10 days. Nevertheless, thank you for your efforts.

This is my current "solution":

gulpfile.js:

let path = require('path');
let gulp = require('gulp');
let pug  = require('gulp-pug');

let pugFiles = './src/**/*.pug';

gulp.task('compilePug', () => {
  gulp.src( pugFiles )
    .pipe( pug().on('error', () => console.log('JADE ERROR')) )
    .pipe( gulp.dest('./src') );
});

gulp.task('default', ['compilePug'], () => {
  gulp.watch(pugFiles, ['compilePug']);
});

.vscode/settings.json:

{
  "files.exclude": {
      "src/app/**/*.html": {"when": "$(basename).pug"}
  }
}

This actually works but it's obviously only a temporary solution..

My team is using pug-cli with --watch at the moment for the same results. However, I would prefer jade to be part of the webpack bundling itself. I'll submit a PR if I have time to figure out how to set it up.

Any news on how to add pug to cli?

I opened a thread on Stockoverflow aswell, hoping for some result
http://stackoverflow.com/questions/39518500/how-to-add-pug-to-angular-cli

Opened a PR to see how this goes.

Heya @ShadowManu, we're not trying to be indifferent and I'm sorry that the jade support has fallen to the wayside.

I can't say jade/pug support is a big on our radars right now to be honest. If you can get a PR to work I'm happy to review it, but bear in mind that it needs to have tests and documentation.

See https://github.com/angular/angular-cli#development-hints-for-hacking-on-angular-cli for a way to start working with a local copy of the CLI.

The command that runs the e2e suite is node tests/e2e_runner.js. Have a look at https://github.com/angular/angular-cli/tree/master/tests/e2e/tests/build/styles for sass/less/styl tests.

You should test that the the correct html is generated, and that base jade/pug functionality (like imports) works.

Regarding documentation, something akin to https://github.com/angular/angular-cli#css-preprocessor-integration should be enough.

Ideally we'd also support initializing a project with pug like we do with sass (ng new sassy-project --style=sass), or setting the default template language (ng set defaults.styleExt scss) but to be honest that's further down the road.

Thanks man. I'll be looking at the tests and a proper similar documentation as soon as I have time.

Any updates @ShadowManu ?

@ShadowManu please, you can look too the support to (lost-grid and/or jeet.gs) and rupture in stylus too?

@kingsdevelopment @filipesilva I've worked a little with some time I had on this, but got blocked on how to make the tests pass (specially on the time they take). I'll have a second try tomorrow.

@nvrossett not that I have knowledge of it. And probably should be on a different PR/issue.

I just wanted to throw my support behind @tycho01 's pug-plugin-ng and pug-ng-html-loader. I used them to use pug with the Angular Class seed, and it really cleans up the syntax and makes development with Angular2 and pug very pleasant. I recommend checking it out:

https://github.com/tycho01/pug-plugin-ng
https://github.com/tycho01/pug-ng-html-loader

(pug-ng-html-loader is just a fork of pug-html-loader which allows pug-plugin-ng to work)

@TaylorDennisLee: thanks. note that for Webpack 2 it should work without the additional loader as well now, see the readme.

Edit: note that original pug syntax is not harmed/disabled; the plugin just patches the lexer to ensure this cleaner more natural (perspective: HTML) option is parsed correctly as well.

@tycho01 Okay, so now pug-plugin-ng should work with pug-html-loader, as long as you are using Webpack 2?

Also, do you still have to do

template: require('./myComp.pug')

instead of:

templateUrl: 'myComp.pug'

Thanks,

Taylor

@TaylorDennisLee: yeah; if you're experiencing issues feel free to file them.
It does still need the require like that, though it seems angular-cli appeared to have addressed this for Sass and co., so I imagine they could for template engines like Pug as well.

@tycho01 can you please provide small guide how to add this loader to angular cli. I'm getting:

src/app/app.component.pug Unexpected token (1:3) You may need an appropriate loader to handle this file type.

import { Component } from '@angular/core';
@Component({
selector: 'app-root',
 template: require('./app.component.pug'),
 styleUrls: ['app.component.scss']
})
export class AppComponent {
  title = 'app works!';
}

@mbonski: I may have use for further info (where/how you set it, first line of the pug file, whether it worked without it). Could you post an issue with those here?

@tycho01 I created one. reference

I'd be interested to see how to do this with just temporary script that runs right before "ng serve" or "ng build" and also what in the angular-cli source code a change would naturally go. @tycho01 do you have a link for how they handled the Sass issue?

@TaylorDennisLee you might consider using a Gulp task for Pug compilation then, preferably along with one of the watchy kind. That's what I've been using, failing a better solution thus far. That could look something like this:

let gulp = require('gulp'),
    gulpWatch = require('gulp-watch'),
    runSequence = require('run-sequence'),
    pug = require('gulp-pug'),
    pug_plugin_ng = require('pug-plugin-ng');

let pug_opts = { doctype: 'html', plugins: [pug_plugin_ng], pretty: true };
let toSrc = gulp.dest((file) => file.base);

gulp.task('pug', () =>
  gulp.src('src/**/*.pug')
  .pipe(pug(pug_opts))
  .pipe(toSrc)
);

gulp.task('watch', [], () => {
  runSequence(
    ['pug'],
    () => {
      gulpWatch('src/**/*.pug', () => gulp.start('pug'));
    }
  );
});

As to changes, I linked ShadowManu's and mine in mbonski's issue thread.

On the Sass point, I didn't know yet :), but the magic appears to be located here. If I'm reading that correctly, than it should be automatically adding support for any extension already recognized by webpack. So I may have been wrong there earlier!

@TaylorDennisLee @tycho01 why not simply using pug src --watch & ng serve? Sure, since they're running simultaneously, webpack generally starts doing 2 builds. But hey, config-wise, you just need to install pug and pug-cli with npm.

@ShadowManu: Yeah, under normal circumstances I suppose that would've been the straight-forward way. One complication I faced personally with my plugin was (1) adding configuration, and (2) having to ensure I could add Pug plugins as well (-> functions, therefore can't survive JSON serialization, so couldn't be passed through a CLI). I never really wanted to use a plugin, but that's how it ended up. I'd definitely rather not resort to Gulp either.

I just did manage that with help from @TaylorDennisLee though, so to answer @mbonski's earlier question of a guide on how to get this to work before it's merged:

git clone -b pug https://github.com/zoitravel/angular-cli.git
# alternative with plugin: git clone -b pug-html https://github.com/tycho01/angular-cli.git
cd angular-cli
npm link
cd PATH/TO/MY/PROJECT
npm link angular-cli
# in component: templateUrl: './my_pug_file.pug',
ng serve

(Now as to the real frontier, ditching pug gulp tasks in Ionic...)

Has anyone gotten variable interpolation to work with webpack1 and pug-ng-html-loader? For some reason its not being able to access my variables

Edit: Just figured out I was basically writing the angular templates using pug and rendering it so instead of using pug variables I should be using angular variables like such {{var}}

I found a way to use AngularCLI with Pug using pug-html-loader. After generate new projects using ng new.
Install pug and pug-html-loader packages. npm install --save-dev pug pug-html-loader.
Add pug-html-loader to your project \node_modules@angular\cli\models\webpack-configs\common.js

{ test: /.(pug|jade)$/, loader: 'pug-html-loader' },
under { test: /.html$/, loader: 'raw-loader' },

Use .jade template in component.

@component({
selector: 'app',
templateUrl: './app.template.jade'
})

I'v made a demo template here https://github.com/CrystalzWind/AngularCLI-Pug
*Note: We must add pug loader to common.js manually after install

Equivalent option to @CrystalzWind 's example is to use pug-loader with apply-loader.

npm install pug-loader apply-loader

and piping the output of the pug-loader through the apply loader which simply executes the template function.

{ test: /\.pug$/, loader: "apply-loader!pug-loader?self" }
in

\node_modules@angular\cli\models\webpack-configs\common.js

Which works with ng serve and ng build --aot for me now

Extending on the workaround presented by @CrystalzWind and @donmahallem, looking at
https://github.com/angular/angular-cli/blob/master/packages/%40angular/cli/models/webpack-configs/common.ts#L33
https://github.com/angular/angular-cli/blob/master/packages/%40angular/cli/models/webpack-configs/common.ts#L104-L112
it seems like giving configuration access to the extraRules variable (there seems to be some configuration options through buildOptions and appConfig already) might be enough to solve this issue.

Edit: ScallyGames/angular-cli@f3cfdb8 shows how such a change might look like (it works but I am fully aware that this is not suited for PR yet).
This would allow "loaderRules": [{ "test": "\\.(pug|jade)$", "loader": "apply-loader!pug-loader" }] in .angular-cli.json to fix this issue.

I'm sorry to be the bearer of bad news, but jade/pug support will not make it to 1.0. It's an medium/big feature that we can't spare the time to make sure it work properly.

I know it looks like it would only be a small change in loaders but that's just not been the case with similar features like sass support.

We're looking at it for 2.0 instead, either as base functionality or as one of the main usecases for addons.

Thanks for the update. If we could help out in the testing department, I'd be glad to.

@filipesilva one of the things that would need some consideration for proper pug support would be how to handle the angular syntax with pug since pug has problems with it (would we want to trade equivalence to pug for syntax convenience).

For reference see tycho01/pug-plugin-ng

On that, fixing Pug to play nice with Angular amounted to one small addition if it'd made it into Pug core (-> consider '[' and '(' after whitespace as valid indication a new property has started).
While I feel this makes much sense in the Angular 2+ context, I don't consider it a blocker for initial support, in the sense that it's pretty much backward compatible.
In the Angular context I'd be in favor of doctype: 'html' as well, to allow #myVar / md-raised-button over #myVar='' / md-raised-button=''.

They could, yes. We'd still like to make it a first class citizen one day.

@MarkPieszak this was my current solution to this problem.
Thanks for mentioning.

hope some day can support pug in angular-cli

@mbonski
Your example is really close.
First install pug and pug-loader and use this example code.

import { Component } from '@angular/core';
@Component({
selector: 'app-root',
 template: require('pug-loader!./app.component.pug')(),
 styleUrls: ['app.component.scss']
})
export class AppComponent {
  title = 'app works!';
}

The only difference is
template: require('./app.component.pug')
To =>
template: require('pug-loader!./app.component.pug')()

You may also need to add the following into typings.d.ts

// telling the typescript compiler that there is a global function
// called require. And to not freak out about references to it.
declare var require: any;

This also works for any other loader in the webpack universe

So far I got it working with ng eject BUT this does not work with tests which again does desire an appropiate loader.

@Anthonyzou Your workaround does work for JIT but I don't seem to get it running with AOT.
The error reads as follows:

Error encountered resolving symbol values statically. Calling function 'template', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol abc in a/b/c

Following the advice of the error and some sites regarding aot I tried:
`
export function template() {
return require("pug-loader!./test.component.pug")();
}

@component({
template: template()
})`

But it still errors with basicly the same message. Any ideas?

@donmahallem I actually have no idea, actually. This is adapted from a graphql angular2 example where they manually require a graphql file and it works with AOT. It must also depend on how the loader is built.

Heya all, this isn't a feature that we're looking at adding in the 1.x timeframe, but rather something that would happen as a third party addon using the upcoming addon system for v2+.

Guys, I made a pull request to allow tweaking webpack config with a file in the project root. For now, you can use the cli at https://github.com/cashfarm/angular-advanced-cli (branch 1.2.x)

Install pug, pug-ng-html-loader and add a webpack.config.js with this to root of your project:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(pug|jade)$/,
        use: ['pug-ng-html-loader']
      }
    ]
  }
}

Then your components can use pug

@Component({
  selector: 'app-root',
  templateUrl: './app.component.pug',
  styleUrls: ['./app.component.styl']
})

But your index has to stay in html.

pexak commented

Any update?

Going along with some of the recommendations above, I created a little script that can be ran to automatically insert the pug rule into the node_modules folder. @pexak

This can be used as a temporary solution until it can be available natively. Note this could need to be updated & changed if the CLI changes the location or formatting of this file. It's naively searching for rules: [ within this specific file.

npm i --D apply-loader pug-loader

pug-rule-insert.js

Now you can just create a simple js file with the code below (put it at your root project level).

const fs = require('fs');

const commonCliConfig = 'node_modules/@angular/cli/models/webpack-configs/common.js';
const pug_rule = `\n{ test: /\.pug$/, loader: "apply-loader!pug-loader?self" },`;

fs.readFile(commonCliConfig, (err, data) => {
  if (err) { throw err; }

  const configText = data.toString();

  if (configText.indexOf(pug_rule) > -1) {
    return;
  }

  console.log('-- Inserting .pug webpack rule -- ');

  const position = configText.indexOf('rules: [') + 8;
  const output = [configText.slice(0, position), pug_rule, configText.slice(position)].join('');

  const file = fs.openSync(commonCliConfig, 'r+');
  fs.writeFile(file, output);
  fs.close(file);
});

Running it

Run it simply with: node pug-rule-insert.js or create a nice postinstall hook to do it for you on new installs.

"postinstall": "node pug-rule-insert.js"

Needed this for a client, hope this helps!

Works with ng serve (even live reloads pug file changes) and AoT ng prod builds, even Universal + CLI projects! ๐ŸŽ

@MarkPieszak thank you. I used pug-html-loader and html-loader instead, it is working fine, including the include ./pug-file

const pug_rule = `\n{ test: /.pug$/, loader: [ 'html-loader', { loader: "pug-html-loader", options: { doctype: 'html', pretty: true } } ], },`;

@MarkPieszak @clovisj @chenzhiguang
[Warning] this trick works fine, as long as you do not name your template files something.TS.pug (which I used to do so they pop below their .ts counterpart in vscode)

If you do so, your AOT builds will fail silently (at least on my machine, as of today)

This one was f***ng hard to find. see #8904

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.