32

Been using es6 more and more for most work these days. One caveat is template strings.

I like to limit my line character count to 80. So if I need to concatenate a long string, it works fine because concatenation can be multiple lines like this:

const insert = 'dog';
const str = 'a really long ' + insert + ' can be a great asset for ' +
  insert + ' when it is a ' + dog;

However, trying to do that with template literals would just give you a multi-line string with ${insert} placing dog in the resulting string. Not ideal when you want to use template literals for things like url assembly, etc.

I haven't yet found a good way to maintain my line character limit and still use long template literals. Anyone have some ideas?

The other question that is marked as an accepted is only a partial answer. Below is another problem with template literals that I forgot to include before.

The problem with using new line characters is that it doesn't allow for indentation without inserting spaces into the final string. i.e.

const insert = 'dog';
const str = `a really long ${insert} can be a great asset for\
  ${insert} when it is a ${insert}`;

The resulting string looks like this:

a really long dog can be a great asset for  dog when it is a dog

Overall this is a minor issue but would be interesting if there was a fix to allow multiline indenting.

Geuis
  • 41,122
  • 56
  • 157
  • 219
  • @CodingIntrigue Please remove the duplicate question marking for this. I've determined that there is a way to do this that addresses my indenting issues and want to leave an answer for it. Basically if you use ${1} at the end of each line, you can have newlines before the closing } and the template literal is rendered without the newlines. – Geuis Nov 21 '16 at 02:15
  • Done. Perhaps you can add your answer to the other question too if it applies? Interested to see the solution. – CodingIntrigue Nov 21 '16 at 08:29
  • 1
    @Geuis I share your pain: initially filled with hope at the prospect of tagged template literals, I'm dismayed to discover that these somewhat obvious issues have no built-in solution. However, template literals invite tags, and these can be used to that effect — see [common-tags](https://www.npmjs.com/package/common-tags) - [oneLine](https://www.npmjs.com/package/common-tags#oneline) seems appropriate? Sadly, this involves run time function execution to address source code authoring convenience. Not ideal :/ – Barney Nov 21 '16 at 08:34
  • 1
    Yep, this is the same issue I had a long time ago when I started working with templateStrings. For the time being and simplicity of it, i just break templateStrings with normal ` + ` signs at the end of the line. – SzybkiSasza Nov 21 '16 at 12:52
  • 1
    @SzybkiSasza that is such a simple and obvious answer. Damn, never even occurred to me. Thanks for the tip. – Geuis Nov 22 '16 at 02:56

2 Answers2

34

Two answers for this problem, but only one may be considered optimal.

Inside template literals, javascript can be used inside of expressions like ${}. Its therefore possible to have indented multiline template literals such as the following. The caveat is some valid js character or value must be present in the expression, such as an empty string or variable.

const templateLiteral = `abcdefgh${''
  }ijklmnopqrst${''
  }uvwxyz`;

// "abcdefghijklmnopqrstuvwxyz"

This method makes your code look like crap. Not recommended.

The second method was recommended by @SzybkiSasza and seems to be the best option available. For some reason concatenating template literals didn't occur to me as possible. I'm derp.

const templateLiteral = `abcdefgh` +
  `ijklmnopqrst` +
  `uvwxyz`;

// "abcdefghijklmnopqrstuvwxyz"
Geuis
  • 41,122
  • 56
  • 157
  • 219
  • 2
    One gotcha about the last approach is that by concatenating using +, a new string is created, so it's not as performant as the first approach. Just to take that into account. – dalvallana Aug 03 '18 at 11:06
7

Why not use a tagged template literal function?

function noWhiteSpace(strings, ...placeholders) {
  let withSpace = strings.reduce((result, string, i) => (result + placeholders[i - 1] + string));
  let withoutSpace = withSpace.replace(/$\n^\s*/gm, ' ');
  return withoutSpace;
}

Then you can just tag any template literal you want to have line breaks in:

let myString = noWhiteSpace`This is a really long string, that needs to wrap over
    several lines. With a normal template literal you can't do that, but you can 
    use a template literal tag to allow line breaks and indents.`;

The provided function will strip all line breaks and line-leading tabs & spaces, yielding the following:

> This is a really long string, that needs to wrap over several lines. With a normal template literal you can't do that, but you can use a template literal tag to allow line breaks and indents.

I published this as the compress-tag library.

Ian
  • 5,704
  • 6
  • 40
  • 72
  • Its not a bad suggestion if its part of a larger framework like Emotion.js. Actually had filed a bug a while back related to this. https://github.com/emotion-js/emotion/issues/647 – Geuis Aug 15 '18 at 22:39
  • This works successfully, however it strips multiple consecutive spaces which may exist in the interior of each line. Replacing your current regex with `.replace(/$\n^ */gm, ' ')` will preserve those. Also it will allow each line to either be indented or not, and allow any no. of spaces to be used for the line indentation. You could also avoid using a function completely and do this instead: `let myString = \`This is a really long etc etc\`.replace(/$\n^ */gm, ' ');` – RobC Nov 11 '18 at 12:58
  • That's a good point; I'll edit my answer to fix that. Note that the regex should probably be `/$\n^\s*/gm` to account for line-leading tab characters as well. As for avoiding the function, I prefer it even though it's more code; if you plan to do this dozens of times, it's clearer and cleaner to use the tag. – Ian Nov 12 '18 at 13:39
  • I also considered `/$\n^(\t| )*/gm`, but then you end up adding multiple spaces if there's a blank line. `/\s*$\n^\s*/gm` is useful if you want to remove trailing spaces at the end of a line as well. – Ian Nov 12 '18 at 14:02
  • 1
    Good point re. leading tab characters too, and yes I agree tagged templates are cleaner. You may find [common-tags](https://github.com/declandewet/common-tags) useful to help address the many edge cases which may arise. – RobC Nov 14 '18 at 13:45
  • That library looks awesome! I've been writing a bunch of these myself already. Thanks for the recommendation. – Ian Nov 14 '18 at 14:53
  • @RobC That link now appears to be deleted, is https://github.com/zspecza/common-tags the successor? Never mind, there's an open issue: https://github.com/zspecza/common-tags/issues/214 – Edric Aug 14 '23 at 10:30