Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

import and export components (v4.2.0) #40

Merged
merged 30 commits into from
Oct 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7e93872
build component and test
JRJurman Oct 5, 2023
35b8c1e
working import-component output
JRJurman Oct 7, 2023
74b2899
remove jsdom
JRJurman Oct 7, 2023
668ccfb
4.2.0
JRJurman Oct 7, 2023
79223a3
hybrid test, enclose component import, non-module and non-install build
JRJurman Oct 7, 2023
8ae56c4
simplify build tooling
JRJurman Oct 7, 2023
6a2a19d
enclose
JRJurman Oct 7, 2023
0d8e747
export-script logic
JRJurman Oct 7, 2023
77e550b
move test files to relevant locations
JRJurman Oct 7, 2023
13e7843
fix build scripts, fix safari issue, start documentation
JRJurman Oct 7, 2023
d78c514
final documentation
JRJurman Oct 7, 2023
9b4ddab
include the export command as a binary
JRJurman Oct 7, 2023
1636823
4.2.0-beta.0
JRJurman Oct 7, 2023
023a5eb
fix export script
JRJurman Oct 7, 2023
76bd25d
4.2.0-beta.1
JRJurman Oct 7, 2023
a24696b
fix export
JRJurman Oct 8, 2023
e161e56
4.2.0-beta.2
JRJurman Oct 8, 2023
a72da44
use relative paths for export
JRJurman Oct 8, 2023
f6918ee
4.2.0-beta.3
JRJurman Oct 8, 2023
79e1499
use real relative paths
JRJurman Oct 8, 2023
fd506dd
4.2.0-beta.4
JRJurman Oct 8, 2023
b38bb47
more comments for build.js
JRJurman Oct 8, 2023
3b5ccd9
fix hyperlink
JRJurman Oct 8, 2023
9fd79ff
remove generated components
JRJurman Oct 8, 2023
03daa12
documentation for new shadowRoot parameter
JRJurman Oct 8, 2023
ec47fd9
add comments pointing to documentation
JRJurman Oct 8, 2023
b7de92b
4.2.0
JRJurman Oct 8, 2023
015bcfa
support and tests for multi-component definitions
JRJurman Oct 8, 2023
a2141fa
update documentation
JRJurman Oct 8, 2023
961b8b0
remove todolist component
JRJurman Oct 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Comment on lines +1 to +5
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this new build.js replaces the set of scripts that were in the package.json. This is a more organized way to bundle and expose all the different scripts that we need, allows us to write comments, and have more consistent behavior across all the generated scripts.

Candidly, this is slightly more error prone, compared to the CLI interface (which is better documented), but all in all, worth the migration.

//
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>
Comment on lines +47 to +53
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding a nice gradient to the background of the main website - including this here so that we always have this (even if the external stylesheet doesn't load).

The gradient itself was created with cssgradient.io

image

<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>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New documentation for the functionality added in this PR! 📝
I would advocate reviewing this locally, over reading the source code 😅

<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
Comment on lines +1 to +2
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, this is just a shell script, but we should migrate this with a JS API (separate issue #41)

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">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a copy-paste of the inline colorpicker example. Some thinking should happen around making this more consistent (see #42)

<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