Skip to content

Commit

Permalink
import and export components (v4.2.0, #40)
Browse files Browse the repository at this point in the history
  • Loading branch information
JRJurman authored Oct 8, 2023
1 parent 4d805ec commit ae0348d
Show file tree
Hide file tree
Showing 31 changed files with 1,120 additions and 305 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ output

# Dependency directory
node_modules

# components that are generated as part of build-test-components.sh
examples/components/ex-colorpicker.js
examples/components/ex-todolist.js
examples/components/example-components.js
109 changes: 109 additions & 0 deletions build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// This script contains all the steps for generating the output results.
// This can be triggered by running `npm run build`
//
// A majority of this file uses the UglifyJS API
// https://www.npmjs.com/package/uglify-js
//
const fs = require('fs');
const path = require('path');
const UglifyJS = require('uglify-js');
const { version } = require('./package.json');

// before we start anything, make sure the output directory exists and is empty
if (!fs.existsSync('output')) {
// if it doesn't exist make it
fs.mkdirSync('output');
} else {
// if it does, remove all files in the directory
const files = fs.readdirSync('output');
for (const file of files) {
const filePath = path.join('output', file);
fs.unlinkSync(filePath);
}
}

// load all source class files (these will be included in all builds)
const classFiles = ['src/TramLite.js', ...fs.readdirSync('src/processors').map((file) => `src/processors/${file}`)];
const loadedClassFiles = Object.fromEntries(
classFiles.map((filePath) => {
console.log('loading', filePath);
return [filePath, fs.readFileSync(filePath).toString()];
}),
);

// load all import/export scripts separately (these are only included in some builds)
console.log('loading', 'src/import-components.js');
const importComponentClass = {
'src/ImportComponent.js': fs.readFileSync('src/ImportComponent.js').toString(),
};
console.log('loading', 'src/import-script.js');
const importScript = {
'src/scripts/import-script.js': fs.readFileSync('src/scripts/import-script.js').toString(),
};

// uglify parameters to change the result of each bundle.
// `MODULE` and `INSTALL` are variables that can be found in the class files and
// determine if we should attach listeners for a window or export the class for a JS API.
// `enclose` determines if the code should be wrapped in an IIFE (which prevents
// prevents class definitions from colliding).
const buildConfigs = [
{
outputFile: 'output/api.js',
files: loadedClassFiles,
defines: { MODULE: true, INSTALL: false },
},
{
outputFile: 'output/tram-lite.js',
files: loadedClassFiles,
defines: { MODULE: false, INSTALL: true },
},
{
outputFile: 'output/import-components.js',
files: { ...loadedClassFiles, ...importComponentClass, ...importScript },
defines: { MODULE: false, INSTALL: false },
enclose: true,
},
{
outputFile: 'output/export-dependencies.js',
files: { ...loadedClassFiles, ...importComponentClass },
defines: { MODULE: false, INSTALL: false },
},
];

buildConfigs.forEach((config) => {
console.log('building', config.outputFile);
const options = {
compress: {
global_defs: {
APP_VERSION: version,
...config.defines,
},
},
enclose: config.enclose,
output: {
comments: 'all',
beautify: true,
},
};
const result = UglifyJS.minify(config.files, options);
fs.writeFileSync(config.outputFile, result.code);
});

// for each of these, create a minified version
const minifyConfigs = [
{ inputFile: 'output/api.js', outputFile: 'output/api.min.js' },
{ inputFile: 'output/tram-lite.js', outputFile: 'output/tram-lite.min.js' },
{ inputFile: 'output/import-components.js', outputFile: 'output/import-components.min.js' },
{ inputFile: 'output/export-dependencies.js', outputFile: 'output/export-dependencies.min.js' },
];

minifyConfigs.forEach((config) => {
console.log('minifying', config.outputFile);
const result = UglifyJS.minify(fs.readFileSync(config.inputFile, 'utf8'));
fs.writeFileSync(config.outputFile, result.code);
});

// do a simple copy for the export-script (needs no minification)
fs.copyFileSync('src/scripts/export-script.js', 'output/export-components.js');

console.log('Tram-Lite build complete!');
65 changes: 0 additions & 65 deletions cypress/spec.cy.js

This file was deleted.

9 changes: 9 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image:src" content="https://tram-one.io/tram-lite/preview.png" />

<!-- styles -->
<style>
:root {
background: rgb(31, 44, 57);
background: linear-gradient(140deg, rgba(31, 44, 57, 1) 0%, rgba(49, 49, 26, 1) 100%);
}
</style>
<link rel="stylesheet" type="text/css" href="./styles.css" />

<!-- highlight.js -->
Expand Down Expand Up @@ -78,6 +85,7 @@
<side-nav-section>
<a href="#install">Install</a>
<a href="#building-components">Building Components</a>
<a href="#importing-and-exporting">Importing & Exporting</a>
</side-nav-section>
<a>HTML API</a>
<side-nav-section>
Expand Down Expand Up @@ -110,6 +118,7 @@
></page>
<page id="guiding-principles"><html-import src="./pages/guiding-principles.html"></html-import></page>
<page id="building-components"><html-import src="./pages/guide-building-components.html"></html-import></page>
<page id="importing-and-exporting"><html-import src="./pages/importing-and-exporting.html"></html-import></page>
<page id="projects-and-posts"><html-import src="./pages/projects-and-posts.html"></html-import></page>
<!-- <page id="cheat-sheet"><html-import src="./pages/cheat-sheet.html"></html-import></page> -->
</main>
Expand Down
120 changes: 120 additions & 0 deletions docs/pages/importing-and-exporting.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<h2>Importing And Exporting Components</h2>
<p>
If you are building a library, there are a few different options when it comes to sharing your components with other
developers. On this page, we document a few different options, and the reasons why you may choose one.
</p>
<p>
Regardless of how you choose to share your components, doing so is a great way to make components easily consumable
among other developers, without requiring Tram-Lite as a core dependency. All methods also allow you to have different
versions of Tram-Lite components in the same project.
</p>

<h3>Using import-components script</h3>
<p>
The <code>import-components</code> script is a great way to share raw HTML templates without requiring a build step as
part of your project. It also allows developers to selectively choose which elements they would like to import.

<code-template-html>
<template>
<script src="https://unpkg.com/tram-lite@4/output/import-components.js" tl-components="..."></script>
</template>
</code-template-html>

The script depends on an attribute <code>tl-components</code>, which is a space separated list of paths to the
components you'd like to import.
</p>
<h4>Parameters</h4>
<p>
The only parameter for <code>import-components.js</code> is the <code>tl-components</code> attribute. It is a space
delimited list of component definition paths. The components should be HTML, and just the definition of the
components, the same as the content inside of a <a href="#tl-definition">tl-definition template tag</a>.
</p>
<h4>Example Importing an HTML Template</h4>
<p>
For example, we might have the following <code>x-button.html</code>.
<code-template-html>
<template>
<x-button>
<button>Hello World</button>
</x-button>
</template>
</code-template-html>

We could then import and immediately use this component in our HTML page using the
<code>import-components.js</code> script.

<code-template-html>
<template>
<script src="https://unpkg.com/tram-lite@4/output/import-components.js" tl-components="./x-button.html"></script>
<x-button></x-button>
</template>
</code-template-html>
</p>
<p>This script is also available as a minified script - simply point to <code>import-components.min.js</code>.</p>

<h3>Using export-components command</h3>
<p>
The <code>export-components</code> CLI tool is a great way to build native javascript if consumers of the library are
using tools to bundle their code, or if you (or your consumers) have a build step. It's also great because it works
with the native script import on the consumer's side.

<code-template-js>
<template>
<script>
npx tram-lite@4 export-components ...
</script>
</template>
</code-template-js>

You can pass in any html files you'd like to be bundled, and it will create a javascript file that people can natively
import with a script tag.
</p>
<h4>Parameters</h4>
<p>
<code-template-js>
<template>
<script>
npx tram-lite@4 export-components <components> [--output output-file.js] [--minified]
</script>
</template>
</code-template-js>
Aside from the required components, the command has two optional flags, <code>--output</code> and
<code>--minified</code>.
</p>
<p>
<code>--output</code> (or <code>-o</code>) can be used to set the file name and directory of the resulting javascript.
If this flag is missing, the command will place the file in the current directory, named based on the component files
passed in.
</p>
<p>
<code>--minified</code> (or <code>-m</code>) can be used to import the minified Tram-Lite code as part of your export.
This should reduce the total size of the exported components.
</p>
<h4>Example Exporting an HTML Template to Javascript</h4>
<p>
Similar to the example above, we start with a component definition in an <code>x-button.html</code>.
<code-template-html>
<template>
<x-button>
<button>Hello World</button>
</x-button>
</template>
</code-template-html>

Then we can run the command to export this component to javascript.
<code-template-js>
<template>
<script>
npx tram-lite@4 export-components x-button.html
</script>
</template>
</code-template-js>

This will create an <code>x-button.js</code> file locally. We can then import that file using a normal script tag.
<code-template-html>
<template>
<script src="x-button.js"></script>
<x-button></x-button>
</template>
</code-template-html>
</p>
7 changes: 7 additions & 0 deletions docs/pages/install.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ <h2>script tag</h2>
</code-template-html>
</p>

<h2>Importing & Exporting Components</h2>
<p>
If you want to import components from an external source, or would like to break up your component definitions into
separate files, check out the documentation on
<a href="#importing-and-exporting">Importing & Exporting Components</a>.
</p>

<h2>Javascript API</h2>
<p>
If you only want access to the Javascript API, or are using tram-lite in a non-browser environment, you can pull just
Expand Down
10 changes: 9 additions & 1 deletion docs/pages/js-appendShadowRootProcessor.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ <h2>Syntax</h2>
<code-template-js>
<template>
<script>
TramLite.appendShadowRootProcessor(cssSelector, behaviorClass);
// prettier-ignore
TramLite.appendShadowRootProcessor(cssSelector, behaviorClass, shadowRoot = ShadowRoot.prototype);
</script>
</template>
</code-template-js>
Expand All @@ -61,6 +62,13 @@ <h3>Parameters</h3>
<dd>
<p>class with a <code>static connect</code> function, which are associated with newly attached nodes.</p>
</dd>
<dt><code>shadowRoot</code><optional-badge>optional</optional-badge></dt>
<dd>
<p>
a specific shadowRoot instance to update the behavior for - by default this is the shadowRoot prototype for all
components, but by passing a specific shadowRoot, you only update the behavior of that component's shadowRoot.
</p>
</dd>
</dl>
<h3>Return Value</h3>
<p>None</p>
Expand Down
3 changes: 3 additions & 0 deletions examples/components/build-test-components.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node output/export-components.js examples/components/ex-progressbar.html examples/components/ex-temperature.html examples/components/ex-container.html examples/components/ex-colorpicker.html -o examples/components/example-components.js
node output/export-components.js examples/components/ex-colorpicker.html -o examples/components/ex-colorpicker.js
node output/export-components.js examples/components/ex-todolist.html -o examples/components/ex-todolist.js -m
15 changes: 15 additions & 0 deletions examples/components/ex-colorpicker.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<ex-colorpicker width="100px">
<style>
svg {
display: block;
}
rect {
fill: oklch(70% 0.1 ${'hue'});
}
</style>
<input id="hue-range-input" type="range" tl-controlled tl-hostattr="hue" tl-trigger="input" min="0" max="360" />
<input id="hue-text-input" type="text" placeholder="hue value" tl-controlled tl-hostattr="hue" />
<svg viewbox="0 0 100 100" width="${'width'}">
<rect width="100" height="100" />
</svg>
</ex-colorpicker>
Loading

0 comments on commit ae0348d

Please sign in to comment.