/
index.html
90 lines (81 loc) · 108 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta http-equiv="x-ua-compatible" content="ie=edge"/><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/><style data-href="/styles.f4dbc894744c3c869f21.css" id="gatsby-global-css">@import url(https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap);.post--2021--binary-floating-point--bit-button:hover{box-shadow:0 0 5px 1px rgba(0,0,0,.2);transition:box-shadow .2s ease-in-out}input:checked~.toggle__dot{transform:translateX(100%)}input:checked~.toggle__line{background-color:#48bb78}.post--2021--water-line--gyro-cube .gyro-cube-container{height:400px;display:flex;justify-content:center;align-items:center;perspective:800px;perspective-origin:50%}.post--2021--water-line--gyro-cube .gyro-cube{position:relative;width:200px;height:200px;transform-style:preserve-3d}.post--2021--water-line--gyro-cube .gyro-cube-side{position:absolute;width:100%;height:100%;opacity:.8;border:2px solid #fff;display:flex;justify-content:center;align-items:center;color:#fff;font-weight:700;font-size:100px}.post--2021--water-line--gyro-cube .gyro-cube-front{background-color:#d50000;transform:translateZ(100px)}.post--2021--water-line--gyro-cube .gyro-cube-back{background-color:#a0f;transform:translateZ(-100px)}.post--2021--water-line--gyro-cube .gyro-cube-left{background-color:#304ffe;transform:translateX(100px) rotateY(90deg)}.post--2021--water-line--gyro-cube .gyro-cube-right{background-color:#0091ea;transform:translateX(-100px) rotateY(90deg)}.post--2021--water-line--gyro-cube .gyro-cube-top{background-color:#00bfa5;transform:translateY(-100px) rotateX(90deg)}.post--2021--water-line--gyro-cube .gyro-cube-bottom{background-color:#64dd17;transform:translateY(100px) rotateX(90deg)}.custom-fade-in-opacity{opacity:1;-webkit-animation-name:customFadeInOpacity;animation-name:customFadeInOpacity;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out;-webkit-animation-duration:.8s;animation-duration:.8s}@-webkit-keyframes customFadeInOpacity{0%{opacity:0}to{opacity:1}}@keyframes customFadeInOpacity{0%{opacity:0}to{opacity:1}}.prose blockquote p:first-of-type:before,.prose blockquote p:last-of-type:after,.prose code:after,.prose code:before{content:""!important}.prose blockquote{font-weight:400!important}.prose li code.language-text,.prose p code.language-text,.prose td code.language-text,.prose th code.language-text,.prose tr code.language-text{padding:2px 5px 1px;font-weight:400}.prose p>img{margin:auto}.prose h1>a.gatsby-remark-autolink-header-anchor,.prose h2>a.gatsby-remark-autolink-header-anchor,.prose h3>a.gatsby-remark-autolink-header-anchor,.prose h4>a.gatsby-remark-autolink-header-anchor,.prose h5>a.gatsby-remark-autolink-header-anchor{visibility:hidden;display:inline-block;margin-left:10px}.prose h1:hover>a.gatsby-remark-autolink-header-anchor,.prose h2:hover>a.gatsby-remark-autolink-header-anchor,.prose h3:hover>a.gatsby-remark-autolink-header-anchor,.prose h4:hover>a.gatsby-remark-autolink-header-anchor,.prose h5:hover>a.gatsby-remark-autolink-header-anchor{visibility:visible}
/* ! tailwindcss v2.1.2 | MIT License | https://tailwindcss.com */
/*! modern-normalize v1.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji}hr{height:0;color:inherit}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}button{background-color:transparent;background-image:none}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}fieldset,ol,ul{margin:0;padding:0}ol,ul{list-style:none}html{font-family:Roboto,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{font-family:inherit;line-height:inherit}*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input:-ms-input-placeholder,textarea:-ms-input-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:#374151;max-width:65ch}.prose [class~=lead]{color:#4b5563;font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose a{color:#dc2626;text-decoration:underline;font-weight:500}.prose a:hover{color:#ef4444}.prose strong{color:#111827;font-weight:600}.prose ol[type=A]{--list-counter-style:upper-alpha}.prose ol[type=a]{--list-counter-style:lower-alpha}.prose ol[type=I]{--list-counter-style:upper-roman}.prose ol[type=i]{--list-counter-style:lower-roman}.prose ol[type="1"]{--list-counter-style:decimal}.prose ol>li{position:relative;padding-left:1.75em}.prose ol>li:before{content:counter(list-item,var(--list-counter-style,decimal)) ".";position:absolute;font-weight:400;color:#6b7280;left:0}.prose ul>li{position:relative;padding-left:1.75em}.prose ul>li:before{content:"";position:absolute;background-color:#d1d5db;border-radius:50%;width:.375em;height:.375em;top:.6875em;left:.25em}.prose hr{border-color:#e5e7eb;border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose blockquote{font-weight:500;font-style:italic;color:#111827;border-left-width:.25rem;border-left-color:#e5e7eb;quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-left:1em}.prose blockquote p:first-of-type:before{content:open-quote}.prose blockquote p:last-of-type:after{content:close-quote}.prose h1{color:#111827;font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose h2{color:#111827;font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose h3{font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose h3,.prose h4{color:#111827;font-weight:600}.prose h4{margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose figure figcaption{color:#6b7280;font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose code{color:#111827;font-weight:600;font-size:.875em}.prose code:after,.prose code:before{content:"`"}.prose a code{color:#111827}.prose pre{color:#e5e7eb;background-color:#1f2937;overflow-x:auto;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding:.8571429em 1.1428571em}.prose pre code{background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:400;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose pre code:after,.prose pre code:before{content:none}.prose table{width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose thead{color:#111827;font-weight:600;border-bottom-width:1px;border-bottom-color:#d1d5db}.prose thead th{vertical-align:bottom;padding-right:.5714286em;padding-bottom:.5714286em;padding-left:.5714286em}.prose tbody tr{border-bottom-width:1px;border-bottom-color:#e5e7eb}.prose tbody tr:last-child{border-bottom-width:0}.prose tbody td{vertical-align:top;padding:.5714286em}.prose{font-size:1rem;line-height:1.75}.prose p{margin-top:1.25em;margin-bottom:1.25em}.prose figure,.prose img,.prose video{margin-top:2em;margin-bottom:2em}.prose figure>*{margin-top:0;margin-bottom:0}.prose h2 code{font-size:.875em}.prose h3 code{font-size:.9em}.prose ol,.prose ul{margin-top:1.25em;margin-bottom:1.25em}.prose li{margin-top:.5em;margin-bottom:.5em}.prose>ul>li p{margin-top:.75em;margin-bottom:.75em}.prose>ul>li>:first-child{margin-top:1.25em}.prose>ul>li>:last-child{margin-bottom:1.25em}.prose>ol>li>:first-child{margin-top:1.25em}.prose>ol>li>:last-child{margin-bottom:1.25em}.prose ol ol,.prose ol ul,.prose ul ol,.prose ul ul{margin-top:.75em;margin-bottom:.75em}.prose h2+*,.prose h3+*,.prose h4+*,.prose hr+*{margin-top:0}.prose thead th:first-child{padding-left:0}.prose thead th:last-child{padding-right:0}.prose tbody td:first-child{padding-left:0}.prose tbody td:last-child{padding-right:0}.prose>:first-child{margin-top:0}.prose>:last-child{margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm p{margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm [class~=lead]{font-size:1.2857143em;line-height:1.5555556;margin-top:.8888889em;margin-bottom:.8888889em}.prose-sm blockquote{margin-top:1.3333333em;margin-bottom:1.3333333em;padding-left:1.1111111em}.prose-sm h1{font-size:2.1428571em;margin-top:0;margin-bottom:.8em;line-height:1.2}.prose-sm h2{font-size:1.4285714em;margin-top:1.6em;margin-bottom:.8em;line-height:1.4}.prose-sm h3{font-size:1.2857143em;margin-top:1.5555556em;margin-bottom:.4444444em;line-height:1.5555556}.prose-sm h4{margin-top:1.4285714em;margin-bottom:.5714286em;line-height:1.4285714}.prose-sm figure,.prose-sm img,.prose-sm video{margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm figure>*{margin-top:0;margin-bottom:0}.prose-sm figure figcaption{font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm code{font-size:.8571429em}.prose-sm h2 code{font-size:.9em}.prose-sm h3 code{font-size:.8888889em}.prose-sm pre{font-size:.8571429em;line-height:1.6666667;margin-top:1.6666667em;margin-bottom:1.6666667em;border-radius:.25rem;padding:.6666667em 1em}.prose-sm ol,.prose-sm ul{margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm li{margin-top:.2857143em;margin-bottom:.2857143em}.prose-sm ol>li{padding-left:1.5714286em}.prose-sm ol>li:before{left:0}.prose-sm ul>li{padding-left:1.5714286em}.prose-sm ul>li:before{height:.3571429em;width:.3571429em;top:.67857em;left:.2142857em}.prose-sm>ul>li p{margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm>ul>li>:first-child{margin-top:1.1428571em}.prose-sm>ul>li>:last-child{margin-bottom:1.1428571em}.prose-sm>ol>li>:first-child{margin-top:1.1428571em}.prose-sm>ol>li>:last-child{margin-bottom:1.1428571em}.prose-sm ol ol,.prose-sm ol ul,.prose-sm ul ol,.prose-sm ul ul{margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm hr{margin-top:2.8571429em;margin-bottom:2.8571429em}.prose-sm h2+*,.prose-sm h3+*,.prose-sm h4+*,.prose-sm hr+*{margin-top:0}.prose-sm table{font-size:.8571429em;line-height:1.5}.prose-sm thead th{padding-right:1em;padding-bottom:.6666667em;padding-left:1em}.prose-sm thead th:first-child{padding-left:0}.prose-sm thead th:last-child{padding-right:0}.prose-sm tbody td{padding:.6666667em 1em}.prose-sm tbody td:first-child{padding-left:0}.prose-sm tbody td:last-child{padding-right:0}.prose-sm>:first-child{margin-top:0}.prose-sm>:last-child{margin-bottom:0}.prose-red a,.prose-red a code{color:#dc2626}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.bg-black{--tw-bg-opacity:1;background-color:rgba(0,0,0,var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgba(156,163,175,var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgba(254,226,226,var(--tw-bg-opacity))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.hover\:bg-black:hover{--tw-bg-opacity:1;background-color:rgba(0,0,0,var(--tw-bg-opacity))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.hover\:bg-gray-800:hover{--tw-bg-opacity:1;background-color:rgba(31,41,55,var(--tw-bg-opacity))}.hover\:bg-red-500:hover{--tw-bg-opacity:1;background-color:rgba(239,68,68,var(--tw-bg-opacity))}.bg-cover{background-size:cover}.border-black{--tw-border-opacity:1;border-color:rgba(0,0,0,var(--tw-border-opacity))}.border-white{--tw-border-opacity:1;border-color:rgba(255,255,255,var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgba(209,213,219,var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgba(156,163,175,var(--tw-border-opacity))}.border-red-500{--tw-border-opacity:1;border-color:rgba(239,68,68,var(--tw-border-opacity))}.hover\:border-white:hover{--tw-border-opacity:1;border-color:rgba(255,255,255,var(--tw-border-opacity))}.hover\:border-gray-400:hover{--tw-border-opacity:1;border-color:rgba(156,163,175,var(--tw-border-opacity))}.rounded-sm{border-radius:.125rem}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-full{border-radius:9999px}.border-solid{border-style:solid}.border-dashed{border-style:dashed}.border{border-width:1px}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.items-stretch{align-items:stretch}.self-start{align-self:flex-start}.self-stretch{align-self:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-self-end{justify-self:end}.flex-1{flex:1 1 0%}.font-light{font-weight:300}.font-normal{font-weight:400}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.h-0{height:0}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-48{height:12rem}.h-64{height:16rem}.h-96{height:24rem}.h-0\.5{height:.125rem}.h-full{height:100%}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.m-auto{margin:auto}.mr-0{margin-right:0}.mb-0{margin-bottom:0}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.ml-1{margin-left:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mt-3{margin-top:.75rem}.mr-3{margin-right:.75rem}.mb-3{margin-bottom:.75rem}.ml-3{margin-left:.75rem}.mr-4{margin-right:1rem}.mb-4{margin-bottom:1rem}.ml-4{margin-left:1rem}.mr-5{margin-right:1.25rem}.ml-5{margin-left:1.25rem}.mt-6{margin-top:1.5rem}.mr-6{margin-right:1.5rem}.mb-6{margin-bottom:1.5rem}.mb-12{margin-bottom:3rem}.mt-16{margin-top:4rem}.max-w-md{max-width:28rem}.max-w-screen-xl{max-width:1280px}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.p-6{padding:1.5rem}.p-8{padding:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.pb-6{padding-bottom:1.5rem}.static{position:static}.absolute{position:absolute}.relative{position:relative}.inset-y-0{top:0;bottom:0}.left-0{left:0}.resize{resize:both}*{--tw-shadow:0 0 transparent}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,0.05)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px 0 rgba(0,0,0,0.06)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,0.1),0 2px 4px -1px rgba(0,0,0,0.06)}.shadow-inner,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}.shadow-inner{--tw-shadow:inset 0 2px 4px 0 rgba(0,0,0,0.06)}.shadow-card{--tw-shadow:0 2px 1px -1px rgba(0,0,0,0.2),0 1px 1px 0 rgba(0,0,0,0.14),0 1px 3px 0 rgba(0,0,0,0.12);box-shadow:var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),var(--tw-shadow)}*{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,0.5);--tw-ring-offset-shadow:0 0 transparent;--tw-ring-shadow:0 0 transparent}.text-center{text-align:center}.text-black{--tw-text-opacity:1;color:rgba(0,0,0,var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgba(156,163,175,var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgba(107,114,128,var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgba(55,65,81,var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgba(239,68,68,var(--tw-text-opacity))}.text-red-600{--tw-text-opacity:1;color:rgba(220,38,38,var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity:1;color:rgba(37,99,235,var(--tw-text-opacity))}.hover\:text-black:hover{--tw-text-opacity:1;color:rgba(0,0,0,var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgba(107,114,128,var(--tw-text-opacity))}.hover\:text-red-600:hover{--tw-text-opacity:1;color:rgba(220,38,38,var(--tw-text-opacity))}.uppercase{text-transform:uppercase}.underline{text-decoration:underline}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.whitespace-nowrap{white-space:nowrap}.w-1{width:.25rem}.w-2{width:.5rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-10{width:2.5rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-36{width:9rem}.w-64{width:16rem}.w-full{width:100%}.gap-12{gap:3rem}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.transform{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;transform:translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:-translate-y-1:hover{--tw-translate-y:-0.25rem}.transition{transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-200{transition-duration:.2s}.duration-500{transition-duration:.5s}@-webkit-keyframes spin{to{transform:rotate(1turn)}}@keyframes spin{to{transform:rotate(1turn)}}@-webkit-keyframes ping{75%,to{transform:scale(2);opacity:0}}@keyframes ping{75%,to{transform:scale(2);opacity:0}}@-webkit-keyframes pulse{50%{opacity:.5}}@keyframes pulse{50%{opacity:.5}}@-webkit-keyframes bounce{0%,to{transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}@keyframes bounce{0%,to{transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}.filter{--tw-blur:var(--tw-empty,/*!*/ /*!*/);--tw-brightness:var(--tw-empty,/*!*/ /*!*/);--tw-contrast:var(--tw-empty,/*!*/ /*!*/);--tw-grayscale:var(--tw-empty,/*!*/ /*!*/);--tw-hue-rotate:var(--tw-empty,/*!*/ /*!*/);--tw-invert:var(--tw-empty,/*!*/ /*!*/);--tw-saturate:var(--tw-empty,/*!*/ /*!*/);--tw-sepia:var(--tw-empty,/*!*/ /*!*/);--tw-drop-shadow:var(--tw-empty,/*!*/ /*!*/);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.grayscale{--tw-grayscale:grayscale(100%)}@media (min-width:640px){.sm\:prose{color:#374151;max-width:65ch}.sm\:prose [class~=lead]{color:#4b5563;font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.sm\:prose a{color:#dc2626;text-decoration:underline;font-weight:500}.sm\:prose a:hover{color:#ef4444}.sm\:prose strong{color:#111827;font-weight:600}.sm\:prose ol[type=A]{--list-counter-style:upper-alpha}.sm\:prose ol[type=a]{--list-counter-style:lower-alpha}.sm\:prose ol[type=I]{--list-counter-style:upper-roman}.sm\:prose ol[type=i]{--list-counter-style:lower-roman}.sm\:prose ol[type="1"]{--list-counter-style:decimal}.sm\:prose ol>li{position:relative;padding-left:1.75em}.sm\:prose ol>li:before{content:counter(list-item,var(--list-counter-style,decimal)) ".";position:absolute;font-weight:400;color:#6b7280;left:0}.sm\:prose ul>li{position:relative;padding-left:1.75em}.sm\:prose ul>li:before{content:"";position:absolute;background-color:#d1d5db;border-radius:50%;width:.375em;height:.375em;top:.6875em;left:.25em}.sm\:prose hr{border-color:#e5e7eb;border-top-width:1px;margin-top:3em;margin-bottom:3em}.sm\:prose blockquote{font-weight:500;font-style:italic;color:#111827;border-left-width:.25rem;border-left-color:#e5e7eb;quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-left:1em}.sm\:prose blockquote p:first-of-type:before{content:open-quote}.sm\:prose blockquote p:last-of-type:after{content:close-quote}.sm\:prose h1{color:#111827;font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.sm\:prose h2{color:#111827;font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.sm\:prose h3{font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.sm\:prose h3,.sm\:prose h4{color:#111827;font-weight:600}.sm\:prose h4{margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.sm\:prose figure figcaption{color:#6b7280;font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.sm\:prose code{color:#111827;font-weight:600;font-size:.875em}.sm\:prose code:after,.sm\:prose code:before{content:"`"}.sm\:prose a code{color:#111827}.sm\:prose pre{color:#e5e7eb;background-color:#1f2937;overflow-x:auto;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding:.8571429em 1.1428571em}.sm\:prose pre code{background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:400;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.sm\:prose pre code:after,.sm\:prose pre code:before{content:none}.sm\:prose table{width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.sm\:prose thead{color:#111827;font-weight:600;border-bottom-width:1px;border-bottom-color:#d1d5db}.sm\:prose thead th{vertical-align:bottom;padding-right:.5714286em;padding-bottom:.5714286em;padding-left:.5714286em}.sm\:prose tbody tr{border-bottom-width:1px;border-bottom-color:#e5e7eb}.sm\:prose tbody tr:last-child{border-bottom-width:0}.sm\:prose tbody td{vertical-align:top;padding:.5714286em}.sm\:prose{font-size:1rem;line-height:1.75}.sm\:prose p{margin-top:1.25em;margin-bottom:1.25em}.sm\:prose figure,.sm\:prose img,.sm\:prose video{margin-top:2em;margin-bottom:2em}.sm\:prose figure>*{margin-top:0;margin-bottom:0}.sm\:prose h2 code{font-size:.875em}.sm\:prose h3 code{font-size:.9em}.sm\:prose ol,.sm\:prose ul{margin-top:1.25em;margin-bottom:1.25em}.sm\:prose li{margin-top:.5em;margin-bottom:.5em}.sm\:prose>ul>li p{margin-top:.75em;margin-bottom:.75em}.sm\:prose>ul>li>:first-child{margin-top:1.25em}.sm\:prose>ul>li>:last-child{margin-bottom:1.25em}.sm\:prose>ol>li>:first-child{margin-top:1.25em}.sm\:prose>ol>li>:last-child{margin-bottom:1.25em}.sm\:prose ol ol,.sm\:prose ol ul,.sm\:prose ul ol,.sm\:prose ul ul{margin-top:.75em;margin-bottom:.75em}.sm\:prose h2+*,.sm\:prose h3+*,.sm\:prose h4+*,.sm\:prose hr+*{margin-top:0}.sm\:prose thead th:first-child{padding-left:0}.sm\:prose thead th:last-child{padding-right:0}.sm\:prose tbody td:first-child{padding-left:0}.sm\:prose tbody td:last-child{padding-right:0}.sm\:prose>:first-child{margin-top:0}.sm\:prose>:last-child{margin-bottom:0}.sm\:flex{display:flex}.sm\:flex-row{flex-direction:row}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:flex-1{flex:1 1 0%}.sm\:h-auto{height:auto}.sm\:mb-0{margin-bottom:0}.sm\:mr-6{margin-right:1.5rem}.sm\:px-12{padding-left:3rem;padding-right:3rem}.sm\:text-left{text-align:left}.sm\:w-2\/5{width:40%}.sm\:w-3\/5{width:60%}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:w-1\/4{width:25%}.lg\:w-3\/4{width:75%}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:none;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}</style><meta name="generator" content="Gatsby 3.4.0"/><title data-react-helmet="true">How to create AOT/JIT compatible Angular 4 library with external SCSS/HTML templates | Trekhleb</title><meta data-react-helmet="true" name="description" content="Example of how to create a re-usable npm library for Angular projects"/><meta data-react-helmet="true" name="image" content="https://trekhleb.dev/static/84e514bd76b8318fa3c404718860281c/9aebb/01-cover.jpg"/><meta data-react-helmet="true" property="og:title" content="How to create AOT/JIT compatible Angular 4 library with external SCSS/HTML templates | Trekhleb"/><meta data-react-helmet="true" property="og:description" content="Example of how to create a re-usable npm library for Angular projects"/><meta data-react-helmet="true" property="og:url" content="https://trekhleb.dev/blog/2017/how-to-create-aot-jit-compatible-angular-4-library/"/><meta data-react-helmet="true" property="og:image" content="https://trekhleb.dev/static/84e514bd76b8318fa3c404718860281c/9aebb/01-cover.jpg"/><meta data-react-helmet="true" property="og:type" content="article"/><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"/><meta data-react-helmet="true" name="twitter:creator" content="@Trekhleb"/><meta data-react-helmet="true" name="twitter:title" content="How to create AOT/JIT compatible Angular 4 library with external SCSS/HTML templates | Trekhleb"/><meta data-react-helmet="true" name="twitter:description" content="Example of how to create a re-usable npm library for Angular projects"/><meta data-react-helmet="true" name="twitter:image" content="https://trekhleb.dev/static/84e514bd76b8318fa3c404718860281c/9aebb/01-cover.jpg"/><meta data-react-helmet="true" name="twitter:url" content="https://trekhleb.dev/blog/2017/how-to-create-aot-jit-compatible-angular-4-library/"/><link rel="preconnect dns-prefetch" href="https://www.google-analytics.com"/><link rel="alternate" type="application/rss+xml" title="Trekhleb.dev RSS Feed" href="/rss.xml"/><link as="script" rel="preload" href="/webpack-runtime-a06de1b72798900395ba.js"/><link as="script" rel="preload" href="/framework-d63adeb7e1b44b7b8aa5.js"/><link as="script" rel="preload" href="/app-2e0826ec06cafce3bdee.js"/><link as="script" rel="preload" href="/commons-213c962999d4e181c8a0.js"/><link as="script" rel="preload" href="/component---src-templates-post-tsx-c4045391b1a7c095d609.js"/><link as="fetch" rel="preload" href="/page-data/blog/2017/how-to-create-aot-jit-compatible-angular-4-library/page-data.json" crossorigin="anonymous"/><link as="fetch" rel="preload" href="/page-data/app-data.json" crossorigin="anonymous"/></head><body><div id="___gatsby"><div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper"><main class="flex flex-col items-center"><div class="max-w-screen-xl self-stretch m-auto w-full"><header class="flex flex-row items-center px-6 sm:px-12 py-6"><div class="mr-6"><div><a class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 font-extrabold text-sm tracking-widest uppercase" href="/">Trekhleb</a></div></div><nav><ul class="flex flex-row"><li class="ml-5"><a class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 uppercase text-xs" href="/">About</a></li><li class="ml-5"><a class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 uppercase text-xs" href="/projects/">Projects</a></li><li class="ml-5"><a class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 uppercase text-xs" href="/blog/">Blog</a></li></ul></nav></header><article class="px-6 sm:px-12 py-6"><div class="flex flex-col items-center"><article class="w-full prose prose-sm sm:prose overflow-hidden prose-red" style="max-width:860px"><h1 class="text-3xl mb-6 uppercase font-extrabold ">How to create AOT/JIT compatible Angular 4 library with external SCSS/HTML templates</h1><div class="flex flex-row items-center "><div class="flex flex-row items-center mr-6"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="mr-1" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>07 June, 2017</div><div class="flex flex-row items-center "><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="mr-1" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>13<!-- --> min to read</div></div><p><span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px">
<span class="gatsby-resp-image-background-image" style="padding-bottom:56.400000000000006%;position:relative;bottom:0;left:0;background-image:url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDAf/EABcBAAMBAAAAAAAAAAAAAAAAAAABAwT/2gAMAwEAAhADEAAAAVnqCcgS0f/EABgQAAMBAQAAAAAAAAAAAAAAAAABAhEh/9oACAEBAAEFAqGVmx0fVp//xAAYEQADAQEAAAAAAAAAAAAAAAAAARICEf/aAAgBAwEBPwGl2RaP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQASEf/aAAgBAgEBPwHKnLJf/8QAGhAAAgIDAAAAAAAAAAAAAAAAAAEQISIxgf/aAAgBAQAGPwJ6FZiqOFx//8QAGhABAAMBAQEAAAAAAAAAAAAAAQARITFBUf/aAAgBAQABPyFFDXyAGxCrWtI3xU9nAZarpgq7P//aAAwDAQACAAMAAAAQ7D//xAAaEQACAgMAAAAAAAAAAAAAAAABEQAhMbHh/9oACAEDAQE/EAN2DUCgtdn/xAAaEQACAgMAAAAAAAAAAAAAAAAAEQEhMbHh/9oACAECAQE/EKAsOSWXvh//xAAbEAEBAAMBAQEAAAAAAAAAAAABEQAxYSFR4f/aAAgBAQABPxCNAjBbFbT7+5qOK1x+3uCNEIfbiuFK8k1rGSfQq9w44z//2Q==');background-size:cover;display:block"></span>
<img class="gatsby-resp-image-image" alt="AOT/JIT" title="AOT/JIT" src="/static/84e514bd76b8318fa3c404718860281c/a2510/01-cover.jpg" srcSet="/static/84e514bd76b8318fa3c404718860281c/0479a/01-cover.jpg 250w,/static/84e514bd76b8318fa3c404718860281c/41099/01-cover.jpg 500w,/static/84e514bd76b8318fa3c404718860281c/a2510/01-cover.jpg 1000w,/static/84e514bd76b8318fa3c404718860281c/c58a3/01-cover.jpg 1500w,/static/84e514bd76b8318fa3c404718860281c/3acf0/01-cover.jpg 2000w,/static/84e514bd76b8318fa3c404718860281c/93719/01-cover.jpg 4000w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0" loading="lazy"/>
</span></p><h2 id="tldr-or-library-requirements" style="position:relative">TL;DR or Library Requirements<a href="#tldr-or-library-requirements" aria-label="tldr or library requirements permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2><p>I’ve created <a href="https://github.com/trekhleb/angular-library-seed">angular-library-seed</a> project that may be interesting for you in case if:</p><ul><li>You want to create component library for <strong>Angular 4</strong> and publish it on NPM.</li><li>You want your library to be ready for further <strong>AOT</strong> and <strong>JIT</strong> compilation.</li><li>You want your library to be ready for further usage <strong>directly in browsers</strong> (let’s say <strong>UMD</strong> bundle loaded by SystemJS).</li><li>You want to write component styles in <strong>external SCSS</strong> files.</li><li>You want to write component templates in <strong>external HTML</strong> files.</li><li>You want to have <strong>watch-mode</strong> for library builds (including <strong>AOT</strong> build).</li></ul><p>This project contains TickTock library example. The library itself is small, and the only thing it does is <a href="http://embed.plnkr.co/VbO1hldrCfF6ITG6VvGG/">displaying current time</a>. But what most important is that the project contains reusable environment for Angular libraries that allows to build, test, lint, document, explore and publish them.</p><h2 id="the-frustration-of-back-end-developer" style="position:relative">The Frustration of Back-End Developer<a href="#the-frustration-of-back-end-developer" aria-label="the frustration of back end developer permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2><p>I’m a backend developer that for last several years was working on developing RESTful APIs and thus was not involved too much in front-end part of the projects. So those several years of front-end news have passed me by.</p><p>Once I decided to develop my own pet-project it was interesting for me to dive into front-end world (as I used to do before when jQuery ruled that world :)</p><p>And I was frustrated...</p><p><em>React, AngularJS, Angular 2, Angular 4, Vue, Ember, Webapck, Rollup, Babel, Prepack, Node.js, NPM, Yarn, Gulp, Grunt, Karma, Jasmine, Protractor, Istanbul, Mocha, Chai, Sinon, TypeScript, ECMAScript, ES5, ES2015, TSlint, Codelyzer, AMD, UMD, CommonJS, Compodoc, SystemJS, Ahead-of-Time compilation, Just-in-Time compilation, Redux, Flux, RxJS, Promises, Observables, SCSS, Flex… Came on! Stop! That is too much for one who thought that if you know jQuery you’re front-end ninja :D What to choose? How to use them together? Thats a lot of possible combinations, man!</em></p><p><span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px">
<span class="gatsby-resp-image-background-image" style="padding-bottom:63.6%;position:relative;bottom:0;left:0;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB8klEQVQoz22Rv0orQRTGJ0geQKys8xAhRbAUbMUHSGOVN7CxsQ0I1lbbWYlYBSRdGiEW2dKAK+sss7Pj/FlnZ2dm59xLRi56ya87nPnmfOc7CH4TQnDOAUCapkmSLJdLAFBKvb29tW3732P0s+i6Ls/zzWZze3t7cHCAEOr1eicnJw8PDx8fH4SQ3eIQAgCUZVlV1WKx2N/fRwjt7e31+32E0NnZWQiBUto0ze7JbdvmeV6W5cXFxWg0Ojo66m1BCA2Hw/V6ba1ljO0WV1WltfbeX15ezmaz1Wp1dXV1fHx8eno6GAwmkwkASCl/DkfRcNu2QggAuLm5OTw8rOv6/v5+Pp+/vr7e3d1dX1+fn58DgPeec951XdwUxZyUUjHk6XQ6Ho8BgHNeFIWU0hjz9PT0+PgIAMYY51xd19+ThRBFUQCAtbZt2yzLnp+fYw9v0VrHIKNt55z3nhBSVRXCGEex1joaS5JEShnFaZo2TYMxttbGLmNMKUUIwRgj771SKp7BbXl5eYlzjDF5ngsh2JbPz0/OOcY4+nLOfQdGKeWcU0qFEFJKrTWlNJrMsoxSyhjrus4YwxiLLr4Di8vEX6J/IQTGmFJKCHl/fyeElGUJAF9fX3bLrzs758KWWFprOefW2hCCUqrrupiIMeaf8q/4D4wmo7WQ8OhZAAAAAElFTkSuQmCC');background-size:cover;display:block"></span>
<img class="gatsby-resp-image-image" alt="whaaat" title="whaaat" src="/static/e022d30a81a574aa37eb53f9b7854e90/00d43/02-what.png" srcSet="/static/e022d30a81a574aa37eb53f9b7854e90/63868/02-what.png 250w,/static/e022d30a81a574aa37eb53f9b7854e90/0b533/02-what.png 500w,/static/e022d30a81a574aa37eb53f9b7854e90/00d43/02-what.png 1000w,/static/e022d30a81a574aa37eb53f9b7854e90/2cefc/02-what.png 1400w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0" loading="lazy"/>
</span></p><p>Of course, I’m not going to cover all that topics here. I’m not going to say that I’ve fully covered them for myself yet.</p><p>What I’m going to do is to share a little bit of my experience (frustrations and answers I’ve found for myself) in one specific area — <strong>developing component library for Angular 4</strong>.</p><p>The answers and solutions I’m going to suggest below of course are not perfect and not “the only ones”. This is just something that answered my questions and worked for me in my project. So I hope you might find them useful for you as well. And also I hope you forgive me if you find any incorrectness below and take into account my fresh start in front-end world.</p><h2 id="the-questions" style="position:relative">The Questions<a href="#the-questions" aria-label="the questions permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2><p><span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px">
<span class="gatsby-resp-image-background-image" style="padding-bottom:14.399999999999999%;position:relative;bottom:0;left:0;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAeUlEQVQI1x2NSRKEMAwD+f9DWYYk3mSDzWUq6aOkam3HflRVRDicWZj5/t2AwxAeAFrrDndA1cwAQ76Zbz7Ps81iEtd5OdwWNGh0gkFFhUXV3KO3PjqZweHtbqPTBsN5XlU1tUssLJWFNQKQWSpKRF99Klr1rXz+/QH3dqrLapcarAAAAABJRU5ErkJggg==');background-size:cover;display:block"></span>
<img class="gatsby-resp-image-image" alt="questions" title="questions" src="/static/deb73386fe34ee300067c6c8e069ecd3/00d43/03-questions.png" srcSet="/static/deb73386fe34ee300067c6c8e069ecd3/63868/03-questions.png 250w,/static/deb73386fe34ee300067c6c8e069ecd3/0b533/03-questions.png 500w,/static/deb73386fe34ee300067c6c8e069ecd3/00d43/03-questions.png 1000w,/static/deb73386fe34ee300067c6c8e069ecd3/2cefc/03-questions.png 1400w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0" loading="lazy"/>
</span></p><p>When I decided to move one of my internal Angular 4 module to a separate npm library to make it re-usable in many future project I’ve faced the following questions that were not that trivial for me.</p><h3 id="1-what-to-export-and-in-what-format" style="position:relative">1. What to export and in what format?<a href="#1-what-to-export-and-in-what-format" aria-label="1 what to export and in what format permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><p>If I want my library be <a href="https://blog.craftlab.hu/multiple-solutions-for-angular-ahead-of-time-aot-compilation-c474d9a0d508">AOT/JIT compatible</a> and to be usable in browser builds via <a href="https://github.com/systemjs/systemjs">SystemJS</a> in what formats and structure should I export it?</p><ul><li>Should it be just one JS bundle file or should it be many not-bundled JS-files with folder structure being preserved? Or should be be both?</li><li>Do I need to export <em>.js.map, </em>.d.ts files? What the heck is <em>.metadata.json and </em>.ngfactory.ts files and should I export them as well?</li><li>Should I include Angular core in JS bundles or should I skip it? If I need to skip it then how should I do it?</li><li>What JS standard should I use: ES5 or ES2015?</li></ul><h3 id="2-how-to-export" style="position:relative">2. How to export?<a href="#2-how-to-export" aria-label="2 how to export permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><p>Let’s pretend we have all answers on first question. How should I build it then? Looks like there are plenty of options:</p><ul><li><a href="https://webpack.js.org/">Webpack</a> or <a href="https://rollupjs.org/">Rollup</a>?</li><li>TypeScript compiler (tsc) or Angular compiler (ngc)?</li><li>“ngc + Webpack” or “ngc + Rollup”?</li><li><a href="https://www.npmjs.com/package/@ngtools/webpack">ngtools/webpack Webpack</a> plugin without ngc?</li><li><a href="https://www.npmjs.com/package/rollup-plugin-angular-aot">rollup-plugin-angular-aot</a> Rollup plugin without ngc?</li></ul><h3 id="3-how-to-utilize-external-scss-styles-and-html-templates" style="position:relative">3. How to utilize external SCSS styles and HTML templates?<a href="#3-how-to-utilize-external-scss-styles-and-html-templates" aria-label="3 how to utilize external scss styles and html templates permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><p>There are several <a href="https://github.com/mgechev/angular-lib-seed">good examples</a> of Angular library starters (my favorite one is <a href="https://github.com/mattlewis92/generator-angular-library#readme">Yo generator for Angular libraries</a>), but they don’t support external SCSS styles or HTML templates or watch-mode for AOT builds. But I wanted to have my templates, styles and component-related logic separately.</p><p>The issue is that Webpack allows you to have external SCSS and HTML templates with watch-mode but it is a bundler by its nature and thus it produces bundles that are not AOT-compatible. Angular Compiler in turn provides AOT-friendly output (all files separately with *.metadata.jsons), but it <a href="https://github.com/angular/angular/issues/12867">doesn’t support watch-mode yet</a> and also it doesn’t support external SCSS templates.</p><h3 id="4-development-flow" style="position:relative">4. Development flow<a href="#4-development-flow" aria-label="4 development flow permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><p>As a developer I want to have more or less automated developing workflow. So I should have been able to change the library sources and test them in a browser instantly without doing transpiation, linking, copying and all of that stuff manually.</p><h4 id="how-to-provide-watch-mode-for-aot-build" style="position:relative">How to provide watch-mode for AOT-build?<a href="#how-to-provide-watch-mode-for-aot-build" aria-label="how to provide watch mode for aot build permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>As it was mentioned in previous question Angular Compiler <a href="https://github.com/angular/angular/issues/12867">doesn’t support watch-mode yet</a>. I needed a workaround here.</p><h4 id="how-to-link-locally-developed-library-to-the-local-project" style="position:relative">How to link locally developed library to the local project?<a href="#how-to-link-locally-developed-library-to-the-local-project" aria-label="how to link locally developed library to the local project permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>Of course there is npm-link for that but there is a <a href="https://github.com/npm/npm/issues/10343">bug</a> that causes npm to steal library’s dependancies from it and move them to the project’s node_modules folder. As a result all builders scripts inside library package become not functional.</p><h2 id="the-answers" style="position:relative">The Answers<a href="#the-answers" aria-label="the answers permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2><p><span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px">
<span class="gatsby-resp-image-background-image" style="padding-bottom:13.999999999999998%;position:relative;bottom:0;left:0;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAa0lEQVQI1yWNOQ7EMAwD8/+/2hIPSd5u4YQgpiKGz/TMDEFJJM/52VVVomKHZdsReQeUZYJfbT+xAkBGIoGEqL227ZJFVfVeQSojpZeU6O4m+HS37bwBwM9im2TXZOS9diExPS5LmjlIlOsP+9Gqk74fdd4AAAAASUVORK5CYII=');background-size:cover;display:block"></span>
<img class="gatsby-resp-image-image" alt="answers" title="answers" src="/static/a5e8b2b841d78a3f2b59aa96eeb53732/00d43/04-anwsers.png" srcSet="/static/a5e8b2b841d78a3f2b59aa96eeb53732/63868/04-anwsers.png 250w,/static/a5e8b2b841d78a3f2b59aa96eeb53732/0b533/04-anwsers.png 500w,/static/a5e8b2b841d78a3f2b59aa96eeb53732/00d43/04-anwsers.png 1000w,/static/a5e8b2b841d78a3f2b59aa96eeb53732/2cefc/04-anwsers.png 1400w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0" loading="lazy"/>
</span></p><p>You may browse <a href="https://github.com/trekhleb/angular-library-seed">angular-library-seed</a> project on <a href="https://github.com/trekhleb/angular-library-seed">GitHub</a> to see full working example and source-files. I’ve also provided descriptive README there so it should be easy to grasp whole idea.</p><p>But for now let’s focus on the questions listed above.</p><h3 id="1-what-to-export-and-in-what-format-1" style="position:relative">1. What to export and in what format?<a href="#1-what-to-export-and-in-what-format-1" aria-label="1 what to export and in what format 1 permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><h4 id="11-files-to-be-consumed-by-browsers-directly" style="position:relative">1.1 Files to be consumed by browsers directly<a href="#11-files-to-be-consumed-by-browsers-directly" aria-label="11 files to be consumed by browsers directly permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>Since I wanted my library to be ready for consuming from browser by <a href="https://github.com/systemjs/systemjs">SystemJS</a> I definitely needed to export it as one JS file (bundle).</p><p>SystemJS <a href="https://github.com/systemjs/systemjs/blob/master/docs/module-formats.md">understands</a> different module formats such as ESM (ECMAScript Module), AMD (Asynchronous Module Definition), CJS (CommonJS) etc. So basically I might pick any of those.</p><p>But there also another one format that is called <a href="http://davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/">UMD</a> (Universal Module Definition). This format seems to fit pretty well for delivering library as a bundle since it ultimately implements both <a href="http://davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/">AMD</a> and <a href="http://davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/">CommonJS</a> formats. In a result our bundle may be consumed even on the back-end by Node.</p><p>So we’re getting our first file that need to be exported:</p><blockquote><ul><li>index.umd.js</li></ul></blockquote><p>For consumers convenience the library should also provide minified version of the bundle to decrease download time for the user:</p><blockquote><ul><li>index.umd.min.js</li></ul></blockquote><p>Ok, we took care about end-users let’s also take care of developers who might want to debug the bundle. Thankfully we have JavaScript <a href="https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/">SourceMaps</a>. Basically it’s a way to map a combined/compiled/minified file back to an unbuilt state.</p><p>So there is two more files to export:</p><blockquote><ul><li>index.umd.js.map</li><li>index.umd.min.js.map</li></ul></blockquote><p>Once the library is published to <a href="http://npmjs.com/">npm</a> the dist folder with your library builds become also available on <a href="https://unpkg.com/">UNPKG</a> server. You may find real-world examples of files mentioned above <a href="https://unpkg.com/angular-library-seed/dist/">there</a>:</p><p>Since we have our bundle available on the web you might <a href="http://embed.plnkr.co/VbO1hldrCfF6ITG6VvGG/">play with it on Plunker</a> <em>(this approach is not a real-world example and it should be used only for testing or demo purposes since it utilizes TypeScript compilation and project build on browser side which is quite slow and traffic consuming)</em>.</p><h4 id="111-exclude-angular-core-from-the-bundle" style="position:relative">1.1.1 Exclude Angular core from the bundle<a href="#111-exclude-angular-core-from-the-bundle" aria-label="111 exclude angular core from the bundle permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>It might be pretty obvious, but we must keep in mind that we’re writing library for Angular project. Since project itself must have Angular core as a dependency the library should not include Angular sources in the bundles it produces. To do so, we need to set a <a href="https://docs.npmjs.com/files/package.json#peerdependencies">peer dependencies</a> in our package.json file.</p><div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token property">"peerDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"@angular/common"</span><span class="token operator">:</span> <span class="token string">"^4.0.0"</span><span class="token punctuation">,</span>
<span class="token property">"@angular/core"</span><span class="token operator">:</span> <span class="token string">"^4.0.0"</span>
<span class="token punctuation">}</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span></code></pre></div><p><a href="https://github.com/trekhleb/angular-library-seed/blob/master/package.json">Full version of package.json</a> in <a href="https://github.com/trekhleb/angular-library-seed">angular-library-seed</a> repository.</p><p>And then exclude peer packages from the bundle by asking Webpack bundler to do so in webpack-umd.config.ts.</p><div class="gatsby-highlight" data-language="typescript"><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> angularExternals <span class="token keyword">from</span> <span class="token string">'webpack-angular-externals'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> rxjsExternals <span class="token keyword">from</span> <span class="token string">'webpack-rxjs-externals'</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
externals<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">angularExternals</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span></code></pre></div><p><a href="https://github.com/trekhleb/angular-library-seed/blob/master/webpack-umd.config.ts">Full version of webpack-umd.config.ts</a> in <a href="https://github.com/trekhleb/angular-library-seed">angular-library-seed</a> repository.</p><h4 id="12-files-to-be-consumed-by-angular-projects-on-the-back-end" style="position:relative">1.2 Files to be consumed by Angular projects on the back-end<a href="#12-files-to-be-consumed-by-angular-projects-on-the-back-end" aria-label="12 files to be consumed by angular projects on the back end permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>One of the requirement your library must fulfill is to be <strong>AOT-compatible</strong>. It is because you, as library developer, will never know what kind of projects will try to consume your library: with <a href="https://angular.io/docs/ts/latest/cookbook/aot-compiler.html">JIT</a> or <a href="https://angular.io/docs/ts/latest/cookbook/aot-compiler.html">AOT</a> types of compilation or even with both. And you probably don’t want to shrink your consumer audience.</p><p>Also according to <a href="https://angular.io/docs/ts/latest/cookbook/aot-compiler.html">official Angular documentation</a> it is preferable to use JIT in development and AOT in production.</p><p>These are not the only reasons to support AOT compilation. AOT itself is a great option for minimising overall library weight, speed up rendering process and catch template-related exception during compilation and not during execution in browsers. More about AOT over JIT advantages you may read in the <a href="https://angular.io/docs/ts/latest/cookbook/aot-compiler.html">official documentation</a> and, for example, in Minko Gechev’s <a href="http://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/">article</a>.</p><p>Ok, I guess we’re clear now that we need this Ahead-of-Time compilation support. So how would we gain it?</p><p>We need <a href="https://www.npmjs.com/package/@angular/compiler">Angular Compiler</a> (or ngc) to do that for us. NGC is kind of wrapper over TSC (<a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html">TypeScriptCompiler</a>), but it takes Angular’s specifics into account while compiling *.ts files (see additional files it produces below).</p><p>Let’s forget about NGC for a moment and think about why we need that transpilation from TypeScript to JavaScript at all. Since project-consumers of the library might be written on <a href="https://www.typescriptlang.org/">TypeScript</a> as well as on JavaScript we need to make our builds to be TypeScript-agnostic. In other words we need to transpile the sources from <em>.ts to </em>.js format utilizing one of the current standards: ES5 or ES2015 (aka ES6). This way not only TypeScript projects will be able to consume your library but JavaScript ones as well. You may read more about ES5 and ES2015 (aka ES6) in John Papa’s <a href="https://johnpapa.net/es5-es2015-typescript/">article</a>. In our case we will produce ES5 version of JavaScript files along with ES2015 <a href="https://en.wikipedia.org/wiki/Polyfill">polyfills</a> to provide greater support for “not that modern” browsers.</p><p><img src="/posts-assets/19eedcb53528dc5cc5752cd5f4a22730/05-aot-jit.gif" alt="es5"/></p><center><i>Image source: <a href="https://johnpapa.net/es5-es2015-typescript/">johnpapa.net</a></i></center><p>Ok, let’s get back to Angular Compiler. Unfortunately it is not documented enough (comparing to, let’s say, <a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html">TSC</a>) at the moment. And thus the following piece of information may be hard to grasp and confusing.</p><p>NGC takes component’s and service’s TypeScript files as an input and produces the following files as an output:</p><ul><li><code class="language-text">*.js</code> — produced by tsc, remember that ngc is a wrapper, compiled JavaScript representation of the component/service *.ts file from the input.</li><li><code class="language-text">*.d.ts</code> — produced by tsc, remember that ngc is a wrapper declaration files. Since <em>.ts files with types are being transpiled to </em>.js files that don’t support typings the TypeScript Compiler needs to put all types information to separate <em>.d.ts files in order to be able to use those </em>.js files in TypeScript projects later. By the way, there is a <a href="https://github.com/DefinitelyTyped/DefinitelyTyped">DefinitelyTyped</a> project with a lot of type definitions that have been already contributed for a plenty of JS non-TypeScript libraries.</li><li><code class="language-text">*.ngfactory.ts</code> — component factory. In other words an instance of the component at runtime — the combination of original class file and a JavaScript representation of the component’s HTML template. The original component class is still referenced internally by the generated factory.</li><li><code class="language-text">*.css.shim.ts</code> — compiled version of component’s CSS styles.</li><li><code class="language-text">*.metadata.json</code> — metadata associated with the current component (or NgModule). It is kind of JSON representation of the objects we pass to the @Component, @NgModule decorators. This file contains the information that project’s (not library’s) NGC will need that was in the original library <em>.ts files but was not included in the </em>.d.ts files.</li></ul><p>As Chuck Jazdzewski <a href="https://github.com/angular/angular/issues/11262#issuecomment-244472000">mentioned</a>: “All libraries must include the <em>.metadata.json file along side any </em>.d.ts files they produce otherwise they will not work correctly with ngc. If we don’t have that information we cannot generate the factories for the library”.</p><p>Also Minko Gechev writes in his <a href="http://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/">article</a>: “Angular Compiler needs metadata for the components in order to compile their templates. Lets suppose that in our application we use a third-party component library. How does the Angular AoT compiler knows the metadata of the components defined there if they are distributed as plain JavaScript? It doesn’t. In order to be able to compile ahead-of-time an application, referencing an external Angular library, the library needs to be distributed with the *.metadata.json produced by the compiler.”</p><p>Also, we don’t need to deliver our library’s <em>.ngfactory.ts files since it is something that will be compiled and produced by NGC on project’s (not library’s) side based on </em>.metadata.json files that must be provided by library. As explained <a href="http://kylecordes.com/2017/angular-component-library-aot">here</a>: “The actual implementation of AOT expects AOT to be performed always at a project level and never at a library level (although the letter is not exactly true; you may use the AOT tool in the library to produce “metadata” files). With this design, you can consume a library written (for example) with Angular 2.3.3, even if your project is using Angular 2.4.5 (somewhat different AOT output) or Angular 4.x (very different AOT output).</p><p>Ok, let’s sum up. In order our library to be consumable by Angular projects with AOT/JIT types of compilation we need to produce the following four files out of each *.ts file:</p><ul><li><code class="language-text">**/*.js</code> — transpiled version of *.ts file in ES5 standard.</li><li><code class="language-text">**/*.js.map</code> — JavaScript map for pleasant debugging.</li><li><code class="language-text">**/*.d.ts</code> — declaration files for saving types information.</li><li><code class="language-text">**/*.metadata.json</code> — metadata required for further AOT compilation.</li></ul><h4 id="121-angular-compiler-configuration" style="position:relative">1.2.1 Angular Compiler Configuration<a href="#121-angular-compiler-configuration" aria-label="121 angular compiler configuration permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>So how do we run ngc? It is done via <a href="https://docs.npmjs.com/misc/scripts">npm scripts</a>. Take a look at the piece of package.json file:</p><div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
<span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token property">"ngcompile"</span><span class="token operator">:</span> <span class="token string">"node_modules/.bin/ngc -p tsconfig-aot.json"</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token property">"@angular/compiler"</span><span class="token operator">:</span> <span class="token string">"^4.0.0"</span><span class="token punctuation">,</span>
<span class="token property">"@angular/compiler-cli"</span><span class="token operator">:</span> <span class="token string">"^4.0.0"</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre></div><p><a href="https://github.com/trekhleb/angular-library-seed/blob/master/package.json">Full version of package.json</a> in <a href="https://github.com/trekhleb/angular-library-seed">angular-library-seed</a> repository.</p><p>As you might noticed Angular Compiler takes configuration file tsconfig-aot.json as a parameter. Here is where all ngc configuration happens. Here we ask the compiler to produce JS files in ES5 standard, to skip ngfactory generation, to produce source maps and declaration files and so on:</p><div class="gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
<span class="token property">"compilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"target"</span><span class="token operator">:</span> <span class="token string">"es5"</span><span class="token punctuation">,</span> <span class="token comment">// Specifying ES standard</span>
<span class="token property">"module"</span><span class="token operator">:</span> <span class="token string">"es2015"</span><span class="token punctuation">,</span>
<span class="token property">"sourceMap"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// Ask tsc to generate *.map.js files</span>
<span class="token property">"declaration"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// Ask tsc to generate *.d.ts files</span>
<span class="token property">"outDir"</span><span class="token operator">:</span> <span class="token string">"dist"</span><span class="token punctuation">,</span> <span class="token comment">// Specify output folder for the files</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token comment">// Specify input file for tsc/ngc</span>
<span class="token string">"./tmp/src-inlined/index.ts"</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token property">"angularCompilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// Angular compiler specific config</span>
<span class="token property">"genDir"</span><span class="token operator">:</span> <span class="token string">"dist"</span><span class="token punctuation">,</span>
<span class="token property">"skipTemplateCodegen"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// Don't produce *.ngfactory.ts</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre></div><p><a href="https://github.com/trekhleb/angular-library-seed/blob/master/tsconfig-aot.json">Full version of tsconfig-aot.json</a> in angular-library-seed repository.</p><h3 id="2-how-to-export-1" style="position:relative">2. How to export?<a href="#2-how-to-export-1" aria-label="2 how to export 1 permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><p>I’ve found the following building scheme working for me.</p><p><span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px">
<span class="gatsby-resp-image-background-image" style="padding-bottom:68.39999999999999%;position:relative;bottom:0;left:0;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAAsTAAALEwEAmpwYAAACCUlEQVQoz3VTS28TMRDOX+fCCapKCHFGvcABDlFVJKqoUt9NQlKyeWzSZJvSTbMve/1Ye19jGyVpllTAd7BH9nye+WbGNbMG55wxFscEI0wpk0IyyhKeUEIBYOOjtzBb1Dabv/S9J8/3/GDhoWXAGccYyzSlhOZ5seIpVdEqo2Z2UYAJqUHcgDagk0VQZnnlLfNsMps9eV51Uqss99G9/tm1H+f3/lIQylH8rdHojW17ZLvdoevMf4wGrU53NJ3+Cvw/kTdZBEFw2m3HQXQ16B3sf7j4XD/vtFtWr14/nHw/v71qju5nLIo5YUscYU6fySrNFWIkJm/29g4bx2/fvyuCOHkKcgUk4ZXCwb1zY1mDycS6uxs/PqzIGzVk6Bx//NQ+uywB9l+9Hp7dGDcCka6eXsNozWTWX/iWu7x9cJGQz5FFTOzhqPX1KLYdY4xz0T4/+DK77pgMVAlVNbXRWKQLymVZ5uv+rcgkYSfNy1a/BwBqnSTC+Oj0xJqOQ4Sqiu40eKfPIROW60WU7F70bfuseU1lssp8q1tvRqUia61pmnk04VmBRRolEotUZLkXU4+wMJGyKM1/UMtK8BlfxMwJ4zkiToiRkAUAkekckWmIg0SyLMci5euBeUHWxoBSoPRKrtbrxRCZLWkyi/CC8DkiPhciL2ia/UPz31BKFaBygBzgxVd4Sf4NDm8Vxg0MYt8AAAAASUVORK5CYII=');background-size:cover;display:block"></span>
<img class="gatsby-resp-image-image" alt="export" title="export" src="/static/95220732a6e8c4dceacdc624f9e91d14/00d43/06-export.png" srcSet="/static/95220732a6e8c4dceacdc624f9e91d14/63868/06-export.png 250w,/static/95220732a6e8c4dceacdc624f9e91d14/0b533/06-export.png 500w,/static/95220732a6e8c4dceacdc624f9e91d14/00d43/06-export.png 1000w,/static/95220732a6e8c4dceacdc624f9e91d14/aa440/06-export.png 1500w,/static/95220732a6e8c4dceacdc624f9e91d14/e8950/06-export.png 2000w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0" loading="lazy"/>
</span></p><p>You may take a look at “Angular-Library-Seed Build Evolution” section at the end of this article for other possible solutions that for some reason couldn’t fit to all my requirements.</p><h4 id="21-utilizing-gulp" style="position:relative">2.1 Utilizing Gulp<a href="#21-utilizing-gulp" aria-label="21 utilizing gulp permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>The distinguishing characteristic of this approach is <strong>inlining</strong> of all external HTML templates with theirs SCSS styles (compiled to CSS) into related <code class="language-text">*.component.ts</code> files via <a href="http://gulpjs.com/">Gulp</a>. By doing this at the end you’ll receive temporary folder with pure <code class="language-text">**/*.ts</code> files that may be easily compiled by Angular compiler. Gulp will also help us to simulate watch-mode for Angular compiler (more on that later).</p><h4 id="22-parallel-builds" style="position:relative">2.2 Parallel Builds<a href="#22-parallel-builds" aria-label="22 parallel builds permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>Another advantage of this approach is that ESM, UMD and Test <strong>builds are completely independent</strong> and may be done in <strong>parallel</strong> or separately one by one:</p><div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token comment"># Run all builds at once.</span>
<span class="token function">yarn</span> build
<span class="token comment"># Run ESM build only.</span>
<span class="token function">yarn</span> build:esm
<span class="token comment"># Run UMD build only.</span>
<span class="token function">yarn</span> build:umd</code></pre></div><p>Read more about build process in angular-library-seed’s <a href="https://github.com/trekhleb/angular-library-seed#build-the-library">README</a>.</p><h4 id="23-rollup-or-webpack" style="position:relative">2.3. Rollup or Webpack<a href="#23-rollup-or-webpack" aria-label="23 rollup or webpack permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p><a href="https://rollupjs.org/">Rollup</a> and <a href="https://webpack.js.org/">Webpack</a> are two great bundlers I was looking at.</p><p>As you may see from the “Angular-Library-Seed Build Evolution” schemes below I decided to use Rollup first. It attracted me by configuration simplicity and native <a href="https://rollupjs.org/">TreeShaking</a> support.</p><p>Both Webpack and Rollup has TypeScript/Angular related plugins (<a href="https://github.com/rollup/rollup-plugin-typescript">rollup-plugin-typescript</a>, <a href="https://github.com/cebor/rollup-plugin-angular">rollup-plugin-angular</a>, <a href="https://www.npmjs.com/package/@ngtools/webpack">ngtools/webpack</a>, <a href="https://github.com/s-panferov/awesome-typescript-loader">awesome-typescript-loader</a> etc).</p><p>But personally I decided to use Webpack so far since it looks for me more mature, well documented and with greater community support.</p><p>Once again, this is my personal choice. If you would prefer using Rollup as your library bundler then <a href="http://www.techumber.com/rollup-bundler-for-angular2-projects/">two</a> <a href="https://www.codementor.io/stevebelovarich/use-rollup-to-build-angular-2-web-apps-du1089cq5">good</a> articles may be useful for you.</p><p>Once thing I may suggest you: don’t use both at the same time :) Keep you technology stack as thin as possible. Once I’ve ended up with Rollup making UMD bundle and Webpack doing similar bundle but for Karma tests — it was a red flag for me, so I’ve switched to Webpack for both cases.</p><h3 id="3-how-to-utilize-external-scss-styles-and-html-templates-1" style="position:relative">3. How to utilize external SCSS styles and HTML templates?<a href="#3-how-to-utilize-external-scss-styles-and-html-templates-1" aria-label="3 how to utilize external scss styles and html templates 1 permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><p>Having Gulp in the library’s arsenal makes it possible to perform <a href="http://sass-lang.com/">SCSS</a> compilation in prior to templates inlining. Template inlining are done using <a href="https://github.com/ludohenin/gulp-inline-ng2-template">gulp-inline-ng2-template</a> library which in turn allows you to provide template processor function.</p><p>Take a look at <a href="https://github.com/trekhleb/angular-library-seed/blob/master/gulpfile.js">gulpfile.js</a> example in angular-library-seed repository for more details.</p><h3 id="4-development-flow-1" style="position:relative">4. Development flow<a href="#4-development-flow-1" aria-label="4 development flow 1 permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h3><p>In order to debug your library in browser you need to have Angular project that will consume your library, build the application and display it. For your convenience all of that should happen automatically in background so once you change library source code you should instantly see the changes in browser.</p><p>There are several ways to go here:</p><ul><li>Use your real library-consumer project and link your library to it via <code class="language-text">yarn link</code> command (see below).</li><li>Use <a href="https://github.com/trekhleb/angular-library-seed/tree/master/demo">demo applications</a> that are provided for your convenience as a part of angular-library-seed repository.</li><li>Use <a href="https://cli.angular.io/">Angular-CLI</a> to generate library-consumer project for you and then use <code class="language-text">yarn link</code> to link your library to it.</li></ul><h4 id="providing-watch-mode-for-aot-compiler-for-better-developing-experience" style="position:relative">Providing watch-mode for AOT compiler for better developing experience<a href="#providing-watch-mode-for-aot-compiler-for-better-developing-experience" aria-label="providing watch mode for aot compiler for better developing experience permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>Ok, so we now that Angular Compiler <a href="https://github.com/angular/angular/issues/12867">doesn’t support watch-mode</a> yet. But Using <a href="http://gulpjs.com/">Gulp</a> in angular-library-seed gives us a possibility to simulate watch-mode. Take a look at gulpfile.js (file with Gulp scripts) example:</p><p>It watches for any file changes in src folder and once any file change detected it forces AOT compiler to re-compile the library.</p><p>Of course, it looks like a workaround, but it may save you hours of development by launching compilation process automatically for you.</p><p><a href="https://github.com/trekhleb/angular-library-seed/blob/master/gulpfile.js">The full version of gulpfile.js</a> may be found in angular-library-seed repository.</p><h4 id="using-demo-applications" style="position:relative">Using demo applications<a href="#using-demo-applications" aria-label="using demo applications permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>You may take advantage of watch-modes for both library build and <a href="https://github.com/trekhleb/angular-library-seed/tree/master/demo">demo-projects</a> builds in order to see changes to your library’s source code immediately in your browser.</p><p>To do so, you need to:</p><ol><li>Open two console instances.</li><li>Launch library build in watch mode in first console instance by running <code class="language-text">yarn build:watch</code> (assuming that you're in <code class="language-text">angular-library-seed</code> root folder).</li><li>Launch demo project build (JIT version) in watch-mode by running <code class="language-text">yarn start</code> in second console instance (assuming that you're in <code class="language-text">angular-library-seed/demo</code> folder).</li></ol><p>As a result once you change library source code it will be automatically re-compiled and in turn your JIT demo-project will be automatically re-built and you will be able to see that changes in your browser instantly.</p><p>For more details about demo projects, their folder structure and npm commands please take a look at angular-library-seed <a href="https://github.com/trekhleb/angular-library-seed/tree/master/demo">demo projects README</a>.</p><h4 id="using-yarn-link" style="position:relative">Using yarn link<a href="#using-yarn-link" aria-label="using yarn link permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h4><p>Since angular-library-seed uses <a href="https://yarnpkg.com/lang/en/">Yarn</a> as a default package manager then we don’t have to deal with npm-link <a href="https://github.com/npm/npm/issues/10343">bug</a> that causes npm to steal library’s dependancies from it and move them to the project’s node_modules folder. (as a result all builders scripts inside library package become not functional).</p><p>So you might simply run <a href="https://yarnpkg.com/lang/en/docs/cli/link/">yarn link</a> to link your library to the project:</p><div class="gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token comment"># Run this inside of your library folder</span>
<span class="token function">yarn</span> <span class="token function">link</span>
<span class="token comment"># Run this inside of your project folder (replace library name)</span>
<span class="token function">yarn</span> <span class="token function">link</span> angular-library-seed</code></pre></div><p>But in case if you run your project on <a href="https://cli.angular.io/">Angular CLI</a> then you might experience <a href="https://github.com/angular/angular-cli/issues/4647#issuecomment-306170986">another bug</a> that will not allow you to have node_modules folder inside your linked library folder, and your AOT (prod) builds will fail with error: <em>“ERROR in Error encountered resolving symbol values statically. Calling function ɵmakeDecorator”</em>.</p><p><a href="https://github.com/angular/angular-cli/issues/4647#issuecomment-305967234">Here</a> is a workaround suggested. So you might simply add the following line to your AngularCLI’s tsconfig.json file:</p><div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"paths": { "@angular/*": ["../node_modules/@angular/*"] }</code></pre></div><p><a href="https://github.com/trekhleb/angular-library-seed#library-development-workflow">Read more</a> about library developing workflow and demo projects that angular-library-seed provides in <a href="https://github.com/trekhleb/angular-library-seed#library-development-workflow">related README section</a>.</p><h2 id="additional-project-features" style="position:relative">Additional Project Features<a href="#additional-project-features" aria-label="additional project features permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2><p>Additionally, to main library building functionality the <a href="https://github.com/trekhleb/angular-library-seed">angular-library-seed</a> project contains the following features:</p><ul><li><strong>Testing</strong> with <a href="https://karma-runner.github.io/1.0/index.html">Karma</a> and <a href="https://jasmine.github.io/">Jasmine</a>.</li><li><strong>Test coverage</strong> report via <a href="https://github.com/gotwarlost/istanbul">Istanbul</a>.</li><li><strong>Linting</strong> with <a href="https://palantir.github.io/tslint/">TSLint</a> and <a href="https://github.com/mgechev/codelyzer">Codelyzer</a> for static code analysis.</li><li><strong>Exploring your build</strong> via <a href="https://www.npmjs.com/package/source-map-explorer">Sourcemap Explorer</a> that shows you a treemap visualization to help you debug where all the code is coming from.</li><li><strong>Documentation generation</strong> via <a href="https://github.com/compodoc/compodoc">Compodoc</a>. Take a look at <a href="https://trekhleb.dev/angular-library-seed/">documentation example</a>.</li><li><strong>Documentation hosting</strong> via <a href="https://pages.github.com/">GitHub Pages</a>.</li><li><strong>Continuous integration</strong> with <a href="https://travis-ci.org/">Travis CI</a>.</li><li><strong>Code coverage</strong> badge via <a href="https://codecov.io/">Codecov</a> as a reminder to cover code with tests.</li></ul><h2 id="ps-angular-library-seed-build-evolution" style="position:relative">P.S. Angular-Library-Seed Build Evolution<a href="#ps-angular-library-seed-build-evolution" aria-label="ps angular library seed build evolution permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2><p>These are just several examples of how the Angular library could be build depending on requirements. I’ve found the requirement of having external SCSS and HTML files the most problem one since it brought different kind of workarounds with it like copying templates into dist folder or using Gulp for inlining templates into *.component.ts files etc.</p><p><span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px">
<span class="gatsby-resp-image-background-image" style="padding-bottom:141.6%;position:relative;bottom:0;left:0;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAIAAADuuAg3AAAACXBIWXMAAAsTAAALEwEAmpwYAAAEIUlEQVQ4y5VU227bRhDVl/cr+lCgTwHaviQpiqSpXbdJHcuKbFmWYl1IS6RIUSJFUryJlyV3lruzBWXJtZsARQdYcLHgzDkze/a05D4YQBxGUkrMq8xymRBJnNxNFT8ISlIKLlhRlvdLKSUFsFZrwYWUslUUBAV6QdDt32rOeqnMrM4gMNfX41F3OFQWur5eWZ6rXN0u3rX1zuCy1ztpX3SGt4jYujr76K6c5dbTF+ZEUX969Wr8oTN4eXJvLAzX0SxzbC4+fOoo3Vvjou/NzJJBTPIoT1HKVuD6AFBROjX0e9MAJ8Tllvs7yXjTjxCSUOnEch3W2gbjQniJLKjMKhSiJb+IklE99BTPLmsmKaumJqy3leaUVypoNg9T5kXMjaQQLURs5tQsfNhzIVZJqEdeDrRBZrzqKzCzeJIzYwMzm45NUC2E+gkyHr4151YcWEmo+nZBq2bCyoIHsSC09pPai+t1gFBLlC0U4hFcABP7PfAaeF2jwMeSX4snyGEmDE9GOQcmhUiyTFutSNUgF1WZVSSj1a4kbhoTSg/JS80I/UBKaahzN9h2Xr1t//jz5PeL8/bl7WjcUyeUsaBIF5GX04rWrGCUCX5Ivj7vzEeKn+2uxqP+6O712zdxEAd+JCSWQHNaHpjjkb9AJBRZ3SQ/nEVZagfb6Xz+y+npqNOfdj/PFU1fmv2Z4kRbCTXVbFhsqGbTuV27kSB03zPiQ1XBOTO9RXcwODs3e3eDk3P9fq4YWpgkklCwfGb5VX8O9ytRVFjBcWCIPMpFXiJlMiWISEmZxGnJeAX1A1WY6LUTCFKJvBS7Akt6SK79uLqdV0OdWVtBWcNk34wRxH+qurfLpJTBN99W1+OHQk+uCiUPd8zyqWLRkQFTqwp3uWwA05IOVq6+jRtyUDdqw/3k8Pk98yhj+qYa6HBnkMnSOrvyN17BAcVBuOIo3mciwceBZQRMD6YWdyLhxEVnugp8JXACkhEGXpYQoHiMfytMSIl7f3ioBeqKJ0UIZB5uUlpOvVV91MY/yNE25JwDwOGgoLXliyjbv2WRFHnJoLK3+b1FDEddm3eWTuAoz377eqyqN8PPjufZM0MbjNvvP/718eLy5buby+5v152zQe/0ptv/9f3N65N27/qzPnPSmO/ZtShjpu9qy+X3L168/+6HSadnBb7urDemtdMsT104czNa2vnCJm74lVdVMYhIpkyU4Zs/hq9PJ4rSnynLrSc5YlpKAjIl3I1lmFVcFBQIqwuoBeIzG0Ih6ozEUaybpuf5ElEIwQnlcQZ+vPAj1Qt7y83lYj1y/IodnQT3/+GjAErAMK/tsHkDKRF7JVvRbh2nI9uf+5GfE+C89VWLQIlfOghwnlEIc6K6gZ/mz53kvwKlrEUjBNXd9k37/yU/lngk9TcLASWWYlDl3gAAAABJRU5ErkJggg==');background-size:cover;display:block"></span>
<img class="gatsby-resp-image-image" alt="evolution" title="evolution" src="/static/13309da39c5882fb0203b2cd25483175/00d43/07-evolution.png" srcSet="/static/13309da39c5882fb0203b2cd25483175/63868/07-evolution.png 250w,/static/13309da39c5882fb0203b2cd25483175/0b533/07-evolution.png 500w,/static/13309da39c5882fb0203b2cd25483175/00d43/07-evolution.png 1000w,/static/13309da39c5882fb0203b2cd25483175/2cefc/07-evolution.png 1400w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0" loading="lazy"/>
</span></p><p><span class="gatsby-resp-image-wrapper" style="position:relative;display:block;margin-left:auto;margin-right:auto;max-width:1000px">
<span class="gatsby-resp-image-background-image" style="padding-bottom:68.39999999999999%;position:relative;bottom:0;left:0;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAAsTAAALEwEAmpwYAAACDElEQVQoz2WSzW/aQBDF+ed76KXHSj20UiOlAqk9VIlSBSWIDzVtCAQioFAINjYONjb22rv2ru3dna2AkprmnUYj/XbevJ2S2kkKSSlljBFMCIlpQvMsp5TSZNtUBQHAc11Su5oxps91e2UbC3NlPXmuhzFxXQ+FUeCjPfSPV3CAC72tCFPrSGGqcqFSzhEujqUpW1oWS9MjeG9mPtfG2qO2sqKYKFDmwqxeX1veem0+YctxPPfnQ/+m05kujZjR48lc9IaDzmSEUFi5OKu+Pbk6//ZjNLio185PypPL1k27PdM03/ZwhBeuLSX8hTlOFKi7bvfjp9PTL5+vajU01kM/8HEUErJdWAKKyf2v0WAymWr63XiECD7AdmB3h5V3H3Rdbzabb169hg0WTrDPQu6WEkI8Ol5bM3uLZX9hZVxsYUhz7KOH+vdu+UzgOCVJ4335tvI1MRyVSygEJgFMhN2YJhkXUpb2UU0N/bLVWFlPCrYTFMB9r9fqd43lknNe/I2iSjs/0vDDvr5AMX5OHuGo2qjfDvpCyqMjKbxS2puxQ+LgBAAY5zTjKecRTY31xsdJQJmEl1MPMKLMDKKZ649tb7hyx7YX0jTj3CHJzAsMP2I5z4SI04wfu9jZBpAAQkohYSsFXMoNSVYhGTsbK8S/175LEpckNOfqP9svBaByIXIhMy5E8aqP/f8ByGcVmgtqT5cAAAAASUVORK5CYII=');background-size:cover;display:block"></span>
<img class="gatsby-resp-image-image" alt="evolution" title="evolution" src="/static/95b52e02d0423e03146cd7d6b8af85f1/00d43/07-evolution-2.png" srcSet="/static/95b52e02d0423e03146cd7d6b8af85f1/63868/07-evolution-2.png 250w,/static/95b52e02d0423e03146cd7d6b8af85f1/0b533/07-evolution-2.png 500w,/static/95b52e02d0423e03146cd7d6b8af85f1/00d43/07-evolution-2.png 1000w,/static/95b52e02d0423e03146cd7d6b8af85f1/2cefc/07-evolution-2.png 1400w" sizes="(max-width: 1000px) 100vw, 1000px" style="width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0" loading="lazy"/>
</span></p><p>But in a result, I believe the build flow became more or less straight-forward, with a possibility of doing any build (for tests, for UMD, for ESM) in parallel.</p><h2 id="ps-ps" style="position:relative">P.S. P.S.<a href="#ps-ps" aria-label="ps ps permalink" class="gatsby-remark-autolink-header-anchor after"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a></h2><p>I hope you’ve found something useful for you in this article. Of course it doesn’t cover the subject completely but, you might find additional information by exploring <a href="https://github.com/trekhleb/angular-library-seed">READMEs</a> and browsing <a href="https://github.com/trekhleb/angular-library-seed">the sources</a> themselves. All this has been written for one purpose — to help developers to spend more time on <strong>developing the library</strong> itself than on focusing on its build environment. Good luck!</p></article></div><div class="flex flex-row justify-center items-center mt-16"><div class="max-w-md"><div class="bg-white rounded-md shadow-md p-8"><h1 class="text-grey-darkest uppercase font-bold text-xl mb-3">Subscribe to the Newsletter</h1><p class="text-sm mb-3">Get my latest posts and project updates by email</p><form action="https://dev.us1.list-manage.com/subscribe/post?u=7714f14ff32085c685da2cfaa&amp;id=53ffa81463" method="post" class="flex flex-col"><input type="text" placeholder="First Name" name="FNAME" class="border py-2 px-3 mb-3 rounded border-gray-300 border-solid appearance-none" required=""/><input type="email" placeholder="Email" name="EMAIL" class="border py-2 px-3 mb-3 rounded border-gray-300 border-solid appearance-none" required=""/><div class="hidden" aria-hidden="true"><input type="text" name="b_7714f14ff32085c685da2cfaa_53ffa81463" tabindex="-1"/></div><input type="submit" value="Subscribe" class="transition duration-200 ease-in-out bg-black text-white py-2 px-3 rounded shadow-sm cursor-pointer hover:bg-gray-800"/></form></div></div></div></article><footer class="px-6 sm:px-12 py-12"><div class="flex flex-col sm:flex-row items-center "><div style="flex:1" class="flex flex-row items-center mb-6 sm:mb-0"><a class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 text-xs mr-5" href="/subscribe"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024" height="20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0 0 68.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg><span class="w-2"></span>Subscribe</a><a href="https://github.com/trekhleb/trekhleb.github.io/discussions" class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 text-xs mr-5"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg><span class="w-2"></span>Feedback</a><a class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 text-xs" href="/rss.xml"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle></svg><span class="w-2"></span>RSS</a></div><div style="flex:1" class="flex flex-row items-center justify-center"><ul class="flex flex-row flex-wrap "><li class="flex flex-row items-center last:mr-0 mr-2 ml-2"><a href="https://www.linkedin.com/in/trekhleb/" class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 " title="Oleksii Trekhleb on LinkedIn"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" class="w-5 h-5" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"></path></svg></a></li><li class="flex flex-row items-center last:mr-0 mr-2 ml-2"><a href="https://github.com/trekhleb" class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 " title="Oleksii Trekhleb on GitHub"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 496 512" class="w-5 h-5" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg></a></li><li class="flex flex-row items-center last:mr-0 mr-2 ml-2"><a href="https://twitter.com/Trekhleb" class="transition duration-200 ease-in-out flex flex-row items-center hover:text-red-600 " title="Oleksii Trekhleb on Twitter"><svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" class="w-5 h-5" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg></a></li></ul></div><div style="flex:1" class="hidden sm:flex"> </div></div></footer></div></main></div><div id="gatsby-announcer" style="position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0" aria-live="assertive" aria-atomic="true"></div></div><script async="" src="https://www.googletagmanager.com/gtag/js?id=G-YJ73BX984Z"></script><script>
if(true) {
window.dataLayer = window.dataLayer || [];
function gtag(){window.dataLayer && window.dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-YJ73BX984Z', {"send_page_view":false});
}
</script><script id="gatsby-script-loader">/*<![CDATA[*/window.pagePath="/blog/2017/how-to-create-aot-jit-compatible-angular-4-library/";/*]]>*/</script><script id="gatsby-chunk-mapping">/*<![CDATA[*/window.___chunkMapping={"polyfill":["/polyfill-b7afeec9af34d175ba4b.js"],"app":["/app-2e0826ec06cafce3bdee.js"],"component---src-pages-404-tsx":["/component---src-pages-404-tsx-63f1eb2c9d9eccd00add.js"],"component---src-pages-blog-tsx":["/component---src-pages-blog-tsx-09e5ed745cd76684f8ac.js"],"component---src-pages-index-tsx":["/component---src-pages-index-tsx-700f213869b8e0037911.js"],"component---src-pages-projects-tsx":["/component---src-pages-projects-tsx-781dc12fd2babbe9fac0.js"],"component---src-pages-subscribe-confirm-index-tsx":["/component---src-pages-subscribe-confirm-index-tsx-7d43f1b2228f03a924f8.js"],"component---src-pages-subscribe-index-tsx":["/component---src-pages-subscribe-index-tsx-c02ecb9201e3fc4b2ce6.js"],"component---src-pages-subscribe-thanks-index-tsx":["/component---src-pages-subscribe-thanks-index-tsx-cec855950644a6361532.js"],"component---src-templates-post-tsx":["/component---src-templates-post-tsx-c4045391b1a7c095d609.js"],"component---src-templates-project-tsx":["/component---src-templates-project-tsx-d7e84ca35145045f8249.js"]};/*]]>*/</script><script src="/polyfill-b7afeec9af34d175ba4b.js" nomodule=""></script><script src="/component---src-templates-post-tsx-c4045391b1a7c095d609.js" async=""></script><script src="/commons-213c962999d4e181c8a0.js" async=""></script><script src="/app-2e0826ec06cafce3bdee.js" async=""></script><script src="/framework-d63adeb7e1b44b7b8aa5.js" async=""></script><script src="/webpack-runtime-a06de1b72798900395ba.js" async=""></script></body></html>