147 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
include ../_util-fns
 | 
						|
 | 
						|
:marked
 | 
						|
  ## Write *Component-Relative* URLs to component templates and style files
 | 
						|
 | 
						|
  Our components often refer to external template and style files.
 | 
						|
  We identify those files with a URL in the `templateUrl` and `styleUrls` properties of the `@Component` metadata
 | 
						|
  as seen here:
 | 
						|
  
 | 
						|
+makeExample('cb-component-relative-paths/ts/app/some.component.ts','absolute-config')(format='.')
 | 
						|
:marked
 | 
						|
  By default, we *must* specify the full path back to the application root.
 | 
						|
  We call this an ***absolute path*** because it is *absolute* with respect to the application root.
 | 
						|
 | 
						|
  There are two problems with an *absolute path*:
 | 
						|
  
 | 
						|
  1. We have to remember the full path back to the application root.
 | 
						|
  
 | 
						|
  1. We have to update the URL when we move the component around in the application files structure.
 | 
						|
  
 | 
						|
  It would be much easier to write and maintain our application components if we could specify template and style locations
 | 
						|
  *relative* to their component class file.
 | 
						|
  
 | 
						|
  *We can!*
 | 
						|
  
 | 
						|
.alert.is-important
 | 
						|
  :marked
 | 
						|
    We can if we build our application as `commonjs` modules and load those modules
 | 
						|
    with a suitable package loader such as `systemjs` or `webpack`.
 | 
						|
    Learn why [below](#why-default).
 | 
						|
    
 | 
						|
    The Angular CLI uses these technologies and defaults to the
 | 
						|
    *component-relative path* approach described here.
 | 
						|
    CLI users can skip this chapter or read on to understand
 | 
						|
    how it works.
 | 
						|
  
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## _Component-Relative_ Paths
 | 
						|
  
 | 
						|
  Our goal is to specify template and style URLs *relative* to their component class files, 
 | 
						|
  hence the term ***component-relative path***.
 | 
						|
  
 | 
						|
  The key to success is following a convention that puts related component files in well-known locations.
 | 
						|
  
 | 
						|
  We recommend keeping component template and component-specific style files as *siblings* of their
 | 
						|
  companion component class files. 
 | 
						|
  Here we see the three files for `SomeComponent` sitting next to each other in the `app` folder. 
 | 
						|
  
 | 
						|
.filetree
 | 
						|
  .file app
 | 
						|
    .children
 | 
						|
      .file some.component.css
 | 
						|
      .file some.component.html
 | 
						|
      .file some.component.ts
 | 
						|
    .file ...
 | 
						|
:marked
 | 
						|
  We'll have more files and folders — and greater folder depth — as our application grows.
 | 
						|
  We'll be fine as long as the component files travel together as the inseparable siblings they are.
 | 
						|
  
 | 
						|
  ### Set the *moduleId*
 | 
						|
  
 | 
						|
  Having adopted this file structure convention, we can specify locations of the template and style files
 | 
						|
  relative to the component class file simply by setting the `moduleId` property of the `@Component` metadata like this
 | 
						|
+makeExample('cb-component-relative-paths/ts/app/some.component.ts','module-id')(format='.')
 | 
						|
:marked
 | 
						|
  We strip the `app/` base path from the `templateUrl` and `styleUrls`. The result looks like this:
 | 
						|
+makeExample('cb-component-relative-paths/ts/app/some.component.ts','relative-config')(format='.')
 | 
						|
 | 
						|
.alert.is-helpful
 | 
						|
  :marked
 | 
						|
    Webpack users may prefer [an alternative approach](#webpack).
 | 
						|
    
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Source
 | 
						|
  
 | 
						|
  **We can see the <live-example name="cb-component-relative-paths"></live-example>**
 | 
						|
  and download the source code from there
 | 
						|
  or simply read the pertinent source here.
 | 
						|
+makeTabs(
 | 
						|
  `cb-component-relative-paths/ts/app/some.component.ts,
 | 
						|
  cb-component-relative-paths/ts/app/some.component.html,
 | 
						|
  cb-component-relative-paths/ts/app/some.component.css,
 | 
						|
  cb-component-relative-paths/ts/app/app.component.ts`,
 | 
						|
  null,
 | 
						|
  `app/some.component.ts, app/some.component.html, app/some.component.css, app/app.component.ts`)
 | 
						|
 | 
						|
a#why-default
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Appendix: why *component-relative* is not the default
 | 
						|
 | 
						|
  A *component-relative* path is obviously superior to an *absolute* path.
 | 
						|
  Why did Angular default to the *absolute* path?
 | 
						|
  Why do *we* have to set the `moduleId`? Why can't Angular set it?
 | 
						|
  
 | 
						|
  First, let's look at what happens if we use a relative path and omit the `moduleId`.
 | 
						|
  
 | 
						|
  `EXCEPTION: Failed to load some.component.html`
 | 
						|
 | 
						|
  Angular can't find the file so it throws an error.
 | 
						|
  
 | 
						|
  Why can't Angular calculate the template and style URLs from the component file's location? 
 | 
						|
 | 
						|
  Because the location of the component can't be determined without the developer's help.
 | 
						|
  Angular apps can be loaded in many ways: from individual files, from SystemJS packages, or
 | 
						|
  from CommonJS packages, to name a few. 
 | 
						|
  We might generate modules in any of several formats. 
 | 
						|
  We might not be writing modular code at all!
 | 
						|
  
 | 
						|
  With this diversity of packaging and module load strategies, 
 | 
						|
  it's not possible for Angular to know with certainty where these files reside at runtime.
 | 
						|
 | 
						|
  The only location Angular can be sure of is the URL of the `index.html` home page, the application root.
 | 
						|
  So by default it resolves template and style paths relative to the URL of `index.html`.
 | 
						|
  That's why we previously wrote our file URLs with an `app/` base path prefix.
 | 
						|
 | 
						|
  But *if* we follow the recommended guidelines and we write modules in `commonjs` format
 | 
						|
  and we use a module loader that *plays nice*,
 | 
						|
  *then* we — the developers of the application —
 | 
						|
  know that the semi-global `module.id` variable is available and contains
 | 
						|
  the absolute URL of the component class module file.
 | 
						|
  
 | 
						|
  That knowledge enables us to tell Angular where the *component* file is
 | 
						|
  by setting the `moduleId`:
 | 
						|
+makeExample('cb-component-relative-paths/ts/app/some.component.ts','module-id')(format='.')
 | 
						|
 | 
						|
a#webpack
 | 
						|
.l-main-section
 | 
						|
:marked
 | 
						|
  ## Webpack: load templates and styles
 | 
						|
  Webpack developers have an alternative to `moduleId`.
 | 
						|
 | 
						|
  They can load templates and styles at runtime by adding `./` at the beginning of the `template` and `styles` / `styleUrls`
 | 
						|
  properties that reference *component-relative URLS.
 | 
						|
  
 | 
						|
+makeExample('webpack/ts/src/app/app.component.ts')(format='.')
 | 
						|
 | 
						|
.l-sub-section
 | 
						|
  :marked
 | 
						|
    Webpack will do a `require` behind the scenes to load the templates and styles. Read more [here](../guide/webpack.html#highlights).
 | 
						|
 | 
						|
 | 
						|
:marked
 | 
						|
  See the [Introduction to Webpack](../guide/webpack.html).
 |