├── vendor
├── .gitkeep
└── embed.js
├── tests
├── helpers
│ └── .gitkeep
├── unit
│ └── .gitkeep
├── integration
│ └── .gitkeep
├── dummy
│ ├── app
│ │ ├── helpers
│ │ │ └── .gitkeep
│ │ ├── models
│ │ │ └── .gitkeep
│ │ ├── routes
│ │ │ └── .gitkeep
│ │ ├── components
│ │ │ └── .gitkeep
│ │ ├── controllers
│ │ │ ├── .gitkeep
│ │ │ └── application.js
│ │ ├── styles
│ │ │ └── app.css
│ │ ├── router.js
│ │ ├── templates
│ │ │ └── application.hbs
│ │ ├── app.js
│ │ └── index.html
│ ├── public
│ │ ├── assets
│ │ │ ├── ignore.css
│ │ │ └── ignore.js
│ │ └── robots.txt
│ └── config
│ │ ├── optional-features.json
│ │ ├── ember-cli-update.json
│ │ ├── targets.js
│ │ └── environment.js
├── test-helper.js
├── index.html
└── acceptance
│ └── embed-test.js
├── .watchmanconfig
├── .prettierrc.js
├── app
└── services
│ └── embedded.js
├── .template-lintrc.js
├── renovate.json
├── config
├── environment.js
└── ember-try.js
├── .ember-cli
├── .prettierignore
├── .eslintignore
├── .dependabot
└── config.yml
├── .editorconfig
├── .gitignore
├── .npmignore
├── addon
└── services
│ └── embedded.js
├── testem.js
├── CONTRIBUTING.md
├── ember-cli-build.js
├── LICENSE.md
├── .eslintrc.js
├── index.js
├── .github
└── workflows
│ └── ci.yml
├── RELEASE.md
├── package.json
├── README.md
├── lib
└── process-html.js
└── CHANGELOG.md
/vendor/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/helpers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/integration/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/dummy/app/helpers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/dummy/app/components/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/dummy/app/controllers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/dummy/public/assets/ignore.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/dummy/public/assets/ignore.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {
2 | "ignore_dirs": ["tmp", "dist"]
3 | }
4 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | singleQuote: true,
5 | };
6 |
--------------------------------------------------------------------------------
/tests/dummy/public/robots.txt:
--------------------------------------------------------------------------------
1 | # http://www.robotstxt.org
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/app/services/embedded.js:
--------------------------------------------------------------------------------
1 | export { default } from 'ember-embedded-snippet/services/embedded';
2 |
--------------------------------------------------------------------------------
/.template-lintrc.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | extends: 'recommended',
5 | };
6 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "local>kaliber5/renovate-config:ember-addon"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/config/environment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (environment /*, appConfig*/) {
4 | return {
5 | locationType: environment === 'test' ? 'none' : 'hash',
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/tests/dummy/config/optional-features.json:
--------------------------------------------------------------------------------
1 | {
2 | "application-template-wrapper": false,
3 | "default-async-observers": true,
4 | "jquery-integration": false,
5 | "template-only-glimmer-components": true
6 | }
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/styles/app.css:
--------------------------------------------------------------------------------
1 | body, :host {
2 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
3 | }
4 |
5 | .title {
6 | color: #00f;
7 | }
8 |
9 | .something {
10 | color: #00f !important;
11 | }
12 |
--------------------------------------------------------------------------------
/tests/dummy/app/router.js:
--------------------------------------------------------------------------------
1 | import EmberRouter from '@ember/routing/router';
2 | import config from 'dummy/config/environment';
3 |
4 | export default class Router extends EmberRouter {
5 | location = config.locationType;
6 | rootURL = config.rootURL;
7 | }
8 |
9 | Router.map(function () {});
10 |
--------------------------------------------------------------------------------
/.ember-cli:
--------------------------------------------------------------------------------
1 | {
2 | /**
3 | Ember CLI sends analytics information by default. The data is completely
4 | anonymous, but there are times when you might want to disable this behavior.
5 |
6 | Setting `disableAnalytics` to true will prevent any data from being sent.
7 | */
8 | "disableAnalytics": false
9 | }
10 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # unconventional js
2 | /blueprints/*/files/
3 |
4 | # compiled output
5 | /dist/
6 | /tmp/
7 |
8 | # dependencies
9 | /bower_components/
10 | /node_modules/
11 |
12 | # misc
13 | /coverage/
14 | !.*
15 | .eslintcache
16 |
17 | # ember-try
18 | /.node_modules.ember-try/
19 | /bower.json.ember-try
20 | /package.json.ember-try
21 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/application.hbs:
--------------------------------------------------------------------------------
1 |
Welcome to Ember
2 |
3 | Arguments:
4 |
5 | {{#each-in this.args as |key value|}}
6 | - {{key}}
7 | - {{value}}
8 | {{/each-in}}
9 |
10 |
11 |
12 | This is content styled by inline CSS.
13 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # unconventional js
2 | /blueprints/*/files/
3 |
4 | # compiled output
5 | /dist/
6 | /tmp/
7 |
8 | # dependencies
9 | /bower_components/
10 | /node_modules/
11 |
12 | # misc
13 | /coverage/
14 | !.*
15 | .*/
16 | .eslintcache
17 |
18 | # ember-try
19 | /.node_modules.ember-try/
20 | /bower.json.ember-try
21 | /package.json.ember-try
22 |
--------------------------------------------------------------------------------
/.dependabot/config.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | update_configs:
3 | - package_manager: "javascript"
4 | directory: "/"
5 | update_schedule: "weekly"
6 | automerged_updates:
7 | - match:
8 | dependency_type: "all"
9 | update_type: "in_range"
10 | version_requirement_updates: "increase_versions"
11 | commit_message:
12 | prefix: ""
13 |
--------------------------------------------------------------------------------
/tests/test-helper.js:
--------------------------------------------------------------------------------
1 | import Application from 'dummy/app';
2 | import config from 'dummy/config/environment';
3 | import * as QUnit from 'qunit';
4 | import { setApplication } from '@ember/test-helpers';
5 | import { setup } from 'qunit-dom';
6 | import { start } from 'ember-qunit';
7 |
8 | setApplication(Application.create(config.APP));
9 |
10 | setup(QUnit.assert);
11 |
12 | start();
13 |
--------------------------------------------------------------------------------
/tests/dummy/app/controllers/application.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import { inject as service } from '@ember/service';
3 |
4 | export default class ApplicationController extends Controller {
5 | @service
6 | embedded;
7 |
8 | // we intentionally do this eagerly, so we can catch in tests that args are available as early as the initial render!
9 | args = this.embedded.args;
10 | }
11 |
--------------------------------------------------------------------------------
/tests/dummy/app/app.js:
--------------------------------------------------------------------------------
1 | import Application from '@ember/application';
2 | import Resolver from 'ember-resolver';
3 | import loadInitializers from 'ember-load-initializers';
4 | import config from 'dummy/config/environment';
5 |
6 | export default class App extends Application {
7 | modulePrefix = config.modulePrefix;
8 | podModulePrefix = config.podModulePrefix;
9 | Resolver = Resolver;
10 | }
11 |
12 | loadInitializers(App, config.modulePrefix);
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.hbs]
16 | insert_final_newline = false
17 |
18 | [*.{diff,md}]
19 | trim_trailing_whitespace = false
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist/
5 | /tmp/
6 |
7 | # dependencies
8 | /bower_components/
9 | /node_modules/
10 |
11 | # misc
12 | /.env*
13 | /.pnp*
14 | /.sass-cache
15 | /.eslintcache
16 | /connect.lock
17 | /coverage/
18 | /libpeerconnection.log
19 | /npm-debug.log*
20 | /testem.log
21 | /yarn-error.log
22 |
23 | # ember-try
24 | /.node_modules.ember-try/
25 | /bower.json.ember-try
26 | /package.json.ember-try
27 |
--------------------------------------------------------------------------------
/tests/dummy/config/ember-cli-update.json:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": "1.0.0",
3 | "packages": [
4 | {
5 | "name": "ember-cli",
6 | "version": "3.27.0",
7 | "blueprints": [
8 | {
9 | "name": "addon",
10 | "outputRepo": "https://github.com/ember-cli/ember-addon-output",
11 | "codemodsSource": "ember-addon-codemods-manifest@1",
12 | "isBaseBlueprint": true,
13 | "options": [
14 | "--yarn"
15 | ]
16 | }
17 | ]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist/
3 | /tmp/
4 |
5 | # dependencies
6 | /bower_components/
7 |
8 | # misc
9 | /.bowerrc
10 | /.editorconfig
11 | /.ember-cli
12 | /.env*
13 | /.eslintcache
14 | /.eslintignore
15 | /.eslintrc.js
16 | /.git/
17 | /.gitignore
18 | /.prettierignore
19 | /.prettierrc.js
20 | /.template-lintrc.js
21 | /.travis.yml
22 | /.watchmanconfig
23 | /bower.json
24 | /config/ember-try.js
25 | /CONTRIBUTING.md
26 | /ember-cli-build.js
27 | /testem.js
28 | /tests/
29 | /yarn-error.log
30 | /yarn.lock
31 | .gitkeep
32 |
33 | # ember-try
34 | /.node_modules.ember-try/
35 | /bower.json.ember-try
36 | /package.json.ember-try
37 |
--------------------------------------------------------------------------------
/addon/services/embedded.js:
--------------------------------------------------------------------------------
1 | import Service from '@ember/service';
2 |
3 | export default class EmbeddedService extends Service {
4 | /**
5 | * The host name of our origin server, where the embedded app itself is hosted
6 | *
7 | * @property originHost
8 | * @type string
9 | * @public
10 | */
11 | get originHost() {
12 | let scriptTag = document.querySelector('script[src$="/embed.js"]');
13 |
14 | return scriptTag
15 | ? scriptTag.src.replace(/(https?:\/\/.*?)\/.*/g, '$1')
16 | : undefined;
17 | }
18 |
19 | args =
20 | typeof window !== undefined
21 | ? window.__ember_embedded_snippet_args ?? {}
22 | : {};
23 | }
24 |
--------------------------------------------------------------------------------
/testem.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | test_page: 'tests/index.html?hidepassed',
5 | disable_watching: true,
6 | launch_in_ci: ['Chrome'],
7 | launch_in_dev: ['Chrome'],
8 | browser_start_timeout: 120,
9 | browser_args: {
10 | Chrome: {
11 | ci: [
12 | // --no-sandbox is needed when running Chrome inside a container
13 | process.env.CI ? '--no-sandbox' : null,
14 | '--headless',
15 | '--disable-dev-shm-usage',
16 | '--disable-software-rasterizer',
17 | '--mute-audio',
18 | '--remote-debugging-port=0',
19 | '--window-size=1440,900',
20 | ].filter(Boolean),
21 | },
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How To Contribute
2 |
3 | ## Installation
4 |
5 | * `git clone `
6 | * `cd ember-embedded-snippet`
7 | * `yarn install`
8 |
9 | ## Linting
10 |
11 | * `yarn lint`
12 | * `yarn lint:fix`
13 |
14 | ## Running tests
15 |
16 | * `ember test` – Runs the test suite on the current Ember version
17 | * `ember test --server` – Runs the test suite in "watch mode"
18 | * `ember try:each` – Runs the test suite against multiple Ember versions
19 |
20 | ## Running the dummy application
21 |
22 | * `ember serve`
23 | * Visit the dummy application at [http://localhost:4200](http://localhost:4200).
24 |
25 | For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/).
26 |
--------------------------------------------------------------------------------
/ember-cli-build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
4 |
5 | module.exports = function (defaults) {
6 | let app = new EmberAddon(defaults, {
7 | // Add options here
8 | });
9 |
10 | /*
11 | This build file specifies the options for the dummy test app of this
12 | addon, located in `/tests/dummy`
13 | This build file does *not* influence how the addon or the app using it
14 | behave. You most likely want to be modifying `./index.js` or app's build file
15 | */
16 |
17 | const { maybeEmbroider } = require('@embroider/test-setup');
18 | const appTree = maybeEmbroider(app);
19 |
20 | return require('./index').process(app, appTree);
21 | };
22 |
--------------------------------------------------------------------------------
/tests/dummy/config/targets.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const browsers = [
4 | 'last 1 Chrome versions',
5 | 'last 1 Firefox versions',
6 | 'last 1 Safari versions',
7 | ];
8 |
9 | // Ember's browser support policy is changing, and IE11 support will end in
10 | // v4.0 onwards.
11 | //
12 | // See https://deprecations.emberjs.com/v3.x#toc_3-0-browser-support-policy
13 | //
14 | // If you need IE11 support on a version of Ember that still offers support
15 | // for it, uncomment the code block below.
16 | //
17 | // const isCI = Boolean(process.env.CI);
18 | // const isProduction = process.env.EMBER_ENV === 'production';
19 | //
20 | // if (isCI || isProduction) {
21 | // browsers.push('ie 11');
22 | // }
23 |
24 | module.exports = {
25 | browsers,
26 | };
27 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | root: true,
5 | parser: 'babel-eslint',
6 | parserOptions: {
7 | ecmaVersion: 2018,
8 | sourceType: 'module',
9 | ecmaFeatures: {
10 | legacyDecorators: true,
11 | },
12 | },
13 | plugins: ['ember'],
14 | extends: [
15 | 'eslint:recommended',
16 | 'plugin:ember/recommended',
17 | 'plugin:prettier/recommended',
18 | ],
19 | env: {
20 | browser: true,
21 | },
22 | rules: {},
23 | overrides: [
24 | // node files
25 | {
26 | files: [
27 | '.eslintrc.js',
28 | '.prettierrc.js',
29 | '.template-lintrc.js',
30 | 'ember-cli-build.js',
31 | 'index.js',
32 | 'testem.js',
33 | 'blueprints/*/index.js',
34 | 'config/**/*.js',
35 | 'tests/dummy/config/**/*.js',
36 | 'lib/**/*',
37 | ],
38 | excludedFiles: [
39 | 'addon/**',
40 | 'addon-test-support/**',
41 | 'app/**',
42 | 'tests/dummy/app/**',
43 | ],
44 | parserOptions: {
45 | sourceType: 'script',
46 | },
47 | env: {
48 | browser: false,
49 | node: true,
50 | },
51 | plugins: ['node'],
52 | extends: ['plugin:node/recommended'],
53 | },
54 | {
55 | // Test files:
56 | files: ['tests/**/*-test.{js,ts}'],
57 | extends: ['plugin:qunit/recommended'],
58 | },
59 | ],
60 | };
61 |
--------------------------------------------------------------------------------
/tests/dummy/config/environment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (environment) {
4 | let ENV = {
5 | modulePrefix: 'dummy',
6 | environment,
7 | rootURL: '/',
8 | locationType: 'hash',
9 | EmberENV: {
10 | FEATURES: {
11 | // Here you can enable experimental features on an ember canary build
12 | // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
13 | },
14 | EXTEND_PROTOTYPES: {
15 | // Prevent Ember Data from overriding Date.parse.
16 | Date: false,
17 | },
18 | },
19 |
20 | APP: {
21 | // Here you can pass flags/options to your application instance
22 | // when it is created
23 | },
24 | };
25 |
26 | if (environment === 'development') {
27 | // ENV.APP.LOG_RESOLVER = true;
28 | // ENV.APP.LOG_ACTIVE_GENERATION = true;
29 | // ENV.APP.LOG_TRANSITIONS = true;
30 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
31 | // ENV.APP.LOG_VIEW_LOOKUPS = true;
32 | }
33 |
34 | if (environment === 'test') {
35 | // Testem prefers this...
36 | ENV.locationType = 'none';
37 |
38 | // keep test console output quieter
39 | ENV.APP.LOG_ACTIVE_GENERATION = false;
40 | ENV.APP.LOG_VIEW_LOOKUPS = false;
41 |
42 | ENV.APP.rootElement = '#ember-testing';
43 | ENV.APP.autoboot = false;
44 | }
45 |
46 | if (environment === 'production') {
47 | // here you can enable a production-specific feature
48 | }
49 |
50 | return ENV;
51 | };
52 |
--------------------------------------------------------------------------------
/tests/dummy/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Dummy
7 |
8 |
9 |
10 | {{content-for "head"}}
11 |
12 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
33 | {{content-for "head-footer"}}
34 |
35 |
36 | {{content-for "body"}}
37 |
38 |
39 |
40 | Outside of Ember
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
53 |
54 | {{content-for "body-footer"}}
55 |
56 |
57 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | name: require('./package').name,
5 |
6 | included() {
7 | let app = this.app;
8 |
9 | if (app.options.fingerprint === undefined) {
10 | app.options.fingerprint = {};
11 | }
12 | if (app.options.fingerprint.exclude === undefined) {
13 | app.options.fingerprint.exclude = [];
14 | }
15 | app.options.fingerprint.exclude.push('embed.js');
16 |
17 | // do not store config in meta tag
18 | app.options.storeConfigInMeta = false;
19 |
20 | // we start the app explicitly
21 | app.options.autoRun = false;
22 | },
23 |
24 | config(env, baseConfig) {
25 | this._rootURL = baseConfig.rootURL;
26 | },
27 |
28 | _process(appTree) {
29 | const mergeTrees = require('broccoli-merge-trees');
30 | const ProcessHtmlPlugin = require('./lib/process-html');
31 |
32 | const processedTree = new ProcessHtmlPlugin(appTree, {
33 | rootURL: this._rootURL,
34 | ui: this.project.ui,
35 | appName: this.app.name,
36 | });
37 |
38 | const babelAddon = this.app.project.findAddonByName('ember-cli-babel');
39 | const compiledTree = babelAddon.transpileTree(processedTree, {
40 | 'ember-cli-babel': {
41 | compileModules: false,
42 | },
43 | });
44 |
45 | return mergeTrees([appTree, compiledTree], { overwrite: true });
46 | },
47 |
48 | process(app, appTree) {
49 | let ownAddon = app.project.findAddonByName('ember-embedded-snippet');
50 |
51 | if (!ownAddon) {
52 | throw new Error(
53 | "Could not find initialized ember-embedded-snippet addon. It must be part of your app's dependencies!"
54 | );
55 | }
56 |
57 | return ownAddon._process(appTree);
58 | },
59 | };
60 |
--------------------------------------------------------------------------------
/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Dummy Tests
7 |
8 |
9 |
10 | {{content-for "head"}}
11 | {{content-for "test-head"}}
12 |
13 |
14 |
15 |
16 |
17 |
26 |
27 |
32 |
33 | {{content-for "head-footer"}}
34 | {{content-for "test-head-footer"}}
35 |
36 |
37 | {{content-for "body"}}
38 | {{content-for "test-body"}}
39 |
40 |
41 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | {{content-for "body-footer"}}
56 | {{content-for "test-body-footer"}}
57 |
58 |
59 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - renovate/*
8 | tags:
9 | - '*'
10 | pull_request:
11 | schedule:
12 | - cron: '0 4 * * 5' # Fridays at 4am
13 |
14 | jobs:
15 | test:
16 | name: Tests
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - name: Checkout code
21 | uses: actions/checkout@v3
22 | - name: Setup node.js
23 | uses: actions/setup-node@v3
24 | with:
25 | node-version: 12
26 | - name: Install dependencies
27 | uses: bahmutov/npm-install@v1
28 | - name: Lint
29 | run: yarn lint
30 | - name: Test
31 | run: yarn test:ember
32 |
33 | test-no-lock:
34 | name: Floating Dependencies
35 | runs-on: ubuntu-latest
36 | needs:
37 | - test
38 | steps:
39 | - name: Checkout code
40 | uses: actions/checkout@v3
41 | - name: Setup node.js
42 | uses: actions/setup-node@v3
43 | with:
44 | node-version: 12
45 | - name: Install dependencies
46 | uses: bahmutov/npm-install@v1
47 | with:
48 | useLockFile: false
49 | - name: Test
50 | run: yarn test:ember
51 |
52 | test-try:
53 | name: Additional Tests
54 | runs-on: ubuntu-latest
55 | needs:
56 | - test
57 | strategy:
58 | matrix:
59 | scenario:
60 | - ember-lts-3.16
61 | - ember-lts-3.20
62 | - ember-lts-3.24
63 | - ember-release
64 | # - ember-beta
65 | - ember-canary
66 | - ember-default-with-jquery
67 | - ember-classic
68 | - embroider-safe
69 | - embroider-optimized
70 | steps:
71 | - name: Checkout code
72 | uses: actions/checkout@v3
73 | - name: Setup node.js
74 | uses: actions/setup-node@v3
75 | with:
76 | node-version: 12
77 | - name: Install dependencies
78 | uses: bahmutov/npm-install@v1
79 | - name: Test
80 | run: yarn ember try:one ${{ matrix.scenario }}
81 |
--------------------------------------------------------------------------------
/config/ember-try.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const getChannelURL = require('ember-source-channel-url');
4 | const { embroiderSafe, embroiderOptimized } = require('@embroider/test-setup');
5 |
6 | module.exports = async function () {
7 | return {
8 | useYarn: true,
9 | scenarios: [
10 | {
11 | name: 'ember-lts-3.16',
12 | npm: {
13 | devDependencies: {
14 | 'ember-source': '~3.16.0',
15 | },
16 | },
17 | },
18 | {
19 | name: 'ember-lts-3.20',
20 | npm: {
21 | devDependencies: {
22 | 'ember-source': '~3.20.5',
23 | },
24 | },
25 | },
26 | {
27 | name: 'ember-lts-3.24',
28 | npm: {
29 | devDependencies: {
30 | 'ember-source': '~3.24.3',
31 | },
32 | },
33 | },
34 | {
35 | name: 'ember-release',
36 | npm: {
37 | devDependencies: {
38 | 'ember-source': await getChannelURL('release'),
39 | },
40 | },
41 | },
42 | {
43 | name: 'ember-beta',
44 | npm: {
45 | devDependencies: {
46 | 'ember-source': await getChannelURL('beta'),
47 | },
48 | },
49 | },
50 | {
51 | name: 'ember-canary',
52 | npm: {
53 | devDependencies: {
54 | 'ember-source': await getChannelURL('canary'),
55 | },
56 | },
57 | },
58 | {
59 | name: 'ember-default-with-jquery',
60 | env: {
61 | EMBER_OPTIONAL_FEATURES: JSON.stringify({
62 | 'jquery-integration': true,
63 | }),
64 | },
65 | npm: {
66 | devDependencies: {
67 | '@ember/jquery': '^1.1.0',
68 | },
69 | },
70 | },
71 | {
72 | name: 'ember-classic',
73 | env: {
74 | EMBER_OPTIONAL_FEATURES: JSON.stringify({
75 | 'application-template-wrapper': true,
76 | 'default-async-observers': false,
77 | 'template-only-glimmer-components': false,
78 | }),
79 | },
80 | npm: {
81 | ember: {
82 | edition: 'classic',
83 | },
84 | },
85 | },
86 | embroiderSafe(),
87 | embroiderOptimized(),
88 | ],
89 | };
90 | };
91 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Release Process
2 |
3 | Releases are mostly automated using
4 | [release-it](https://github.com/release-it/release-it/) and
5 | [lerna-changelog](https://github.com/lerna/lerna-changelog/).
6 |
7 | ## Preparation
8 |
9 | Since the majority of the actual release process is automated, the primary
10 | remaining task prior to releasing is confirming that all pull requests that
11 | have been merged since the last release have been labeled with the appropriate
12 | `lerna-changelog` labels and the titles have been updated to ensure they
13 | represent something that would make sense to our users. Some great information
14 | on why this is important can be found at
15 | [keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall
16 | guiding principle here is that changelogs are for humans, not machines.
17 |
18 | When reviewing merged PR's the labels to be used are:
19 |
20 | * breaking - Used when the PR is considered a breaking change.
21 | * enhancement - Used when the PR adds a new feature or enhancement.
22 | * bug - Used when the PR fixes a bug included in a previous release.
23 | * documentation - Used when the PR adds or updates documentation.
24 | * internal - Used for internal changes that still require a mention in the
25 | changelog/release notes.
26 |
27 | ## Release
28 |
29 | Once the prep work is completed, the actual release is straight forward:
30 |
31 | * First, ensure that you have installed your projects dependencies:
32 |
33 | ```sh
34 | yarn install
35 | ```
36 |
37 | * Second, ensure that you have obtained a
38 | [GitHub personal access token][generate-token] with the `repo` scope (no
39 | other permissions are needed). Make sure the token is available as the
40 | `GITHUB_AUTH` environment variable.
41 |
42 | For instance:
43 |
44 | ```bash
45 | export GITHUB_AUTH=abc123def456
46 | ```
47 |
48 | [generate-token]: https://github.com/settings/tokens/new?scopes=repo&description=GITHUB_AUTH+env+variable
49 |
50 | * And last (but not least 😁) do your release.
51 |
52 | ```sh
53 | npx release-it
54 | ```
55 |
56 | [release-it](https://github.com/release-it/release-it/) manages the actual
57 | release process. It will prompt you to to choose the version number after which
58 | you will have the chance to hand tweak the changelog to be used (for the
59 | `CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging,
60 | pushing the tag and commits, etc.
61 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ember-embedded-snippet",
3 | "version": "0.7.1",
4 | "description": "Embed Ember apps into external pages with a simple snippet",
5 | "keywords": [
6 | "ember-addon"
7 | ],
8 | "repository": "https://github.com/kaliber5/ember-embedded-snippet",
9 | "license": "MIT",
10 | "author": "Simon Ihmig ",
11 | "directories": {
12 | "doc": "doc",
13 | "test": "tests"
14 | },
15 | "scripts": {
16 | "build": "ember build --environment=production",
17 | "lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
18 | "lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
19 | "lint:hbs": "ember-template-lint .",
20 | "lint:hbs:fix": "ember-template-lint . --fix",
21 | "lint:js": "eslint . --cache",
22 | "lint:js:fix": "eslint . --fix",
23 | "start": "ember serve",
24 | "test": "npm-run-all lint test:*",
25 | "test:ember": "ember test",
26 | "test:ember-compatibility": "ember try:each"
27 | },
28 | "dependencies": {
29 | "broccoli-caching-writer": "^3.0.3",
30 | "broccoli-merge-trees": "^4.2.0",
31 | "ember-cli-babel": "^7.26.6",
32 | "jsdom": "^19.0.0"
33 | },
34 | "devDependencies": {
35 | "@ember/optional-features": "2.0.0",
36 | "@ember/test-helpers": "2.8.1",
37 | "@embroider/test-setup": "1.6.0",
38 | "@glimmer/component": "1.1.2",
39 | "@glimmer/tracking": "1.1.2",
40 | "babel-eslint": "10.1.0",
41 | "broccoli-asset-rev": "3.0.0",
42 | "ember-auto-import": "2.4.2",
43 | "ember-cli": "3.28.5",
44 | "ember-cli-dependency-checker": "3.3.1",
45 | "ember-cli-inject-live-reload": "2.1.0",
46 | "ember-cli-htmlbars": "6.1.0",
47 | "ember-cli-sri": "2.1.1",
48 | "ember-cli-terser": "4.0.2",
49 | "ember-disable-prototype-extensions": "1.1.3",
50 | "ember-load-initializers": "2.1.2",
51 | "ember-page-title": "7.0.0",
52 | "ember-qunit": "5.1.5",
53 | "ember-resolver": "8.0.3",
54 | "ember-source": "3.28.9",
55 | "ember-source-channel-url": "3.0.0",
56 | "ember-template-lint": "4.12.0",
57 | "ember-try": "2.0.0",
58 | "eslint": "7.32.0",
59 | "eslint-config-prettier": "8.5.0",
60 | "eslint-plugin-ember": "10.6.1",
61 | "eslint-plugin-node": "11.1.0",
62 | "eslint-plugin-prettier": "4.2.1",
63 | "eslint-plugin-qunit": "7.3.1",
64 | "loader.js": "4.7.0",
65 | "npm-run-all": "4.1.5",
66 | "prettier": "2.7.1",
67 | "qunit": "2.19.1",
68 | "qunit-dom": "2.0.0",
69 | "release-it": "14.14.3",
70 | "release-it-lerna-changelog": "4.0.1",
71 | "webpack": "5.74.0"
72 | },
73 | "engines": {
74 | "node": "12.* || >= 14"
75 | },
76 | "publishConfig": {
77 | "registry": "https://registry.npmjs.org"
78 | },
79 | "ember": {
80 | "edition": "octane"
81 | },
82 | "ember-addon": {
83 | "configPath": "tests/dummy/config",
84 | "after": "ember-export-application-global"
85 | },
86 | "release-it": {
87 | "plugins": {
88 | "release-it-lerna-changelog": {
89 | "infile": "CHANGELOG.md",
90 | "launchEditor": true
91 | }
92 | },
93 | "git": {
94 | "tagName": "v${version}"
95 | },
96 | "github": {
97 | "release": true,
98 | "tokenRef": "GITHUB_AUTH"
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ember-embedded-snippet
2 | ==============================================================================
3 |
4 | 
5 |
6 | Embed your Ember app as a WebComponent into external pages with a simple JavaScript snippet.
7 |
8 |
9 | Compatibility
10 | ------------------------------------------------------------------------------
11 |
12 | * Ember.js v3.16 or above
13 | * Ember CLI v3.20 or above
14 | * Node.js v12 or above
15 |
16 |
17 | Installation
18 | ------------------------------------------------------------------------------
19 |
20 | ```
21 | ember install ember-embedded-snippet
22 | ```
23 |
24 | To allow compatibility with `ember-auto-import` v2 and Embroider, since `v0.7.0` the addon requires some manual
25 | setup to postprocess Ember's build.
26 |
27 | In your `ember-cli-build.js` change the last part:
28 |
29 | ```diff
30 | module.exports = function (defaults) {
31 | let app = new EmberAddon(defaults, {
32 | // ...
33 | });
34 |
35 | - return app.toTree();
36 | + return require('ember-embedded-snippet').process(app, app.toTree());
37 | }
38 | ```
39 |
40 | Then you should also add the custom element invocation to your `app/index.html`, so when running locally using `ember serve`
41 | the app is bootstrapped the same way as when it is embedded in production. See also the "Usage" below!
42 |
43 | ```diff
44 |
45 | {{content-for "body"}}
46 |
47 | +
48 |
49 |
50 |
51 |
52 | {{content-for "body-footer"}}
53 |
54 | ```
55 |
56 | > Note: doing this also for `tests/index.html` will not work, you should keep that file as-is. That means tests use the default
57 | > bootstrapping process of Ember.
58 |
59 | Usage
60 | ------------------------------------------------------------------------------
61 |
62 | Add a snippet like this to your static or server rendered HTML page:
63 |
64 | ```html
65 |
66 |
67 | ```
68 |
69 | `my-app-name` is the name of your app. As custom elements require to contain a dash, if your app name is a single word, append the `-app` suffix.
70 |
71 | ### Shadow DOM
72 |
73 | To prevent styles leaking from the parent page into your app or vice versa, you can enable [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) support:
74 |
75 | ```html
76 |
77 | ```
78 |
79 | > Note that even with shadow DOM, inherited styles will also be inherited by your shadow DOM, thus leak into your app.
80 | > So you might want to [reset inheritable styles](https://developers.google.com/web/fundamentals/web-components/shadowdom#reset)
81 |
82 | ### Custom arguments
83 |
84 | Any other attributes added to the custom element are taken as custom arguments, that you can read from the `embedded` service's `args` property:
85 |
86 | ```html
87 |
88 | ```
89 |
90 | ```js
91 | import Controller from '@ember/controller';
92 | import { inject as service } from '@ember/service';
93 |
94 | export default class FooController extends Controller {
95 | @service
96 | embedded;
97 |
98 | get foo() {
99 | return this.embedded.args.hasOwnProperty('enable-foo') ? this.embedded.args.foo : null;
100 | }
101 | }
102 | ```
103 |
104 |
105 | Contributing
106 | ------------------------------------------------------------------------------
107 |
108 | See the [Contributing](CONTRIBUTING.md) guide for details.
109 |
110 |
111 | License
112 | ------------------------------------------------------------------------------
113 |
114 | This project is licensed under the [MIT License](LICENSE.md).
115 |
--------------------------------------------------------------------------------
/lib/process-html.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const Plugin = require('broccoli-caching-writer');
6 | const { JSDOM } = require('jsdom');
7 |
8 | const INDEX_FILE = 'index.html';
9 |
10 | // convert https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap to simple serializable pojo
11 | function convertAttributesToObject(attributes) {
12 | return [...attributes].reduce(
13 | (hash, { name, value }) => ({ [name]: value, ...hash }),
14 | {}
15 | );
16 | }
17 |
18 | class ProcessHtmlPlugin extends Plugin {
19 | constructor(input, { appName, rootURL, ui }) {
20 | super([input], {
21 | cacheInclude: [/index\.html/],
22 | });
23 | this.appName = appName;
24 | this.rootURL = rootURL;
25 | this.ui = ui;
26 | }
27 |
28 | build() {
29 | if (this._processHtml()) {
30 | this._writeEmbedScript();
31 | }
32 | }
33 |
34 | _processHtml() {
35 | this.references = [];
36 | const html = fs.readFileSync(path.join(this.inputPaths[0], INDEX_FILE), {
37 | encoding: 'utf8',
38 | });
39 |
40 | const dom = new JSDOM(html);
41 | const document = dom.window.document;
42 |
43 | this.customElementName = this.appName;
44 | if (!this.customElementName.includes('-')) {
45 | this.customElementName += '-app';
46 | }
47 |
48 | const customElement = document.querySelector(this.customElementName);
49 | if (!customElement) {
50 | this.ui.writeWarnLine(
51 | `ember-embedded-snippet: could not find invocation of custom element <${this.customElementName}>, skipping processing...`
52 | );
53 | return false;
54 | }
55 |
56 | this.scripts = document.querySelectorAll(
57 | 'script:not([data-embedded-ignore])'
58 | );
59 | this.links = document.querySelectorAll(
60 | 'link[rel="stylesheet"]:not([data-embedded-ignore])'
61 | );
62 | this.styles = document.querySelectorAll(
63 | 'style:not([data-embedded-ignore])'
64 | );
65 |
66 | // Remove all scripts and styles from the final index.html, as those will be loaded form our embed.js script
67 | this.scripts.forEach((ref) => ref.remove());
68 | this.links.forEach((ref) => ref.remove());
69 | this.styles.forEach((ref) => ref.remove());
70 |
71 | // insert embed.js
72 | const embedScript = document.createElement('script');
73 | embedScript.setAttribute('src', `${this.rootURL}embed.js`);
74 | customElement.insertAdjacentElement('beforebegin', embedScript);
75 |
76 | fs.writeFileSync(path.join(this.outputPath, INDEX_FILE), dom.serialize(), {
77 | encoding: 'utf8',
78 | });
79 |
80 | return true;
81 | }
82 |
83 | _writeEmbedScript() {
84 | let js = fs.readFileSync(path.join(__dirname, '..', 'vendor', 'embed.js'), {
85 | encoding: 'utf8',
86 | });
87 |
88 | for (const [key, value] of Object.entries(this._dynamicReplacements)) {
89 | js = js.replace(new RegExp(`/${key}/`, 'g'), value);
90 | js = js.replace(new RegExp(key, 'g'), value);
91 | }
92 |
93 | fs.writeFileSync(path.join(this.outputPath, 'embed.js'), js);
94 | }
95 |
96 | get _dynamicReplacements() {
97 | const links = Array.from(this.links).map((node) => ({
98 | attributes: convertAttributesToObject(node.attributes),
99 | }));
100 | const scripts = Array.from(this.scripts).map((node) => ({
101 | attributes: convertAttributesToObject(node.attributes),
102 | content: node.textContent !== '' ? node.textContent : null,
103 | }));
104 | const styles = Array.from(this.styles).map((node) => ({
105 | attributes: convertAttributesToObject(node.attributes),
106 | content: node.textContent !== '' ? node.textContent : null,
107 | }));
108 |
109 | return {
110 | '###APPNAME###': this.appName,
111 | '###CENAME###': this.customElementName,
112 | '###LINKS###': JSON.stringify(links),
113 | '###SCRIPTS###': JSON.stringify(scripts),
114 | '###STYLES###': JSON.stringify(styles),
115 | };
116 | }
117 | }
118 |
119 | module.exports = ProcessHtmlPlugin;
120 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## v0.7.1 (2022-05-05)
4 |
5 | #### :rocket: Enhancement
6 | * [#181](https://github.com/kaliber5/ember-embedded-snippet/pull/181) Load scripts in parallel instead of sequentially ([@simonihmig](https://github.com/simonihmig))
7 |
8 | #### Committers: 1
9 | - Simon Ihmig ([@simonihmig](https://github.com/simonihmig))
10 |
11 | ## v0.7.0 (2021-10-26)
12 |
13 | #### :boom: Breaking Change
14 | * [#148](https://github.com/kaliber5/ember-embedded-snippet/pull/148) Major refactoring of `embed.js` generation and app integration ([@simonihmig](https://github.com/simonihmig))
15 |
16 | #### :rocket: Enhancement
17 | * [#165](https://github.com/kaliber5/ember-embedded-snippet/pull/165) Support inline `