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

Use Ionic from npm without framework #446

Open
adrm opened this issue Feb 7, 2019 · 18 comments
Open

Use Ionic from npm without framework #446

adrm opened this issue Feb 7, 2019 · 18 comments
Labels
triage New issues

Comments

@adrm
Copy link

adrm commented Feb 7, 2019

Feature Request

Using Ionic v4 from npm is only supported for frameworks through the framework specific packages. There is no documented way of using @ionic/core from npm directly without CDN. I understand the benefits of the CDN but there are some use cases when this is not possible, like corporate proxies or problems with ad blockers.

Ionic version:

[x] 4.x

Describe the Feature Request

Support using @ionic/core from npm without a framework.

Describe Preferred Solution

Document how to do it and explore if any change in the source code would be needed.

Describe Alternatives

Using the CDN, but it may not be possible for every use case.

Related Code

Additional Context

@brandyscarney brandyscarney transferred this issue from ionic-team/ionic-framework Feb 11, 2019
@brandyscarney
Copy link
Member

I've moved this issue to the ionic-docs repository as it is a request for improved documentation. We have an example of using Ionic from npm in a stencil app here: https://github.com/ionic-team/ionic-stencil-conference-app

It should be fairly similar to use it in a non-stencil project.

@brandyscarney brandyscarney added the content Issues related to the contents of the documentation website label Feb 11, 2019
@camwiegert
Copy link
Contributor

Thinking we should include a section on this page.

@brandyscarney
Copy link
Member

Agreed. That's a good spot for it.

@adrm
Copy link
Author

adrm commented Feb 20, 2019

And on top of that, I think that that page @camwiegert mentioned needs to specify that you also need to include ionic stylesheet.

<link href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css" rel="stylesheet" />

@brandyscarney
Copy link
Member

Yes @adrm you can include the css bundle or if you prefer to break it up and only include some of the css files they are the following in npm:

@import "~@ionic/core/css/core.css";
@import "~@ionic/core/css/normalize.css";
@import "~@ionic/core/css/structure.css";
@import "~@ionic/core/css/typography.css";

@import "~@ionic/core/css/padding.css";
@import "~@ionic/core/css/float-elements.css";
@import "~@ionic/core/css/text-alignment.css";
@import "~@ionic/core/css/flex-utils.css";

Here's more of an explanation on what each file is: https://github.com/ionic-team/ionic/blob/master/angular/BREAKING.md#global-css

@coderbuzz
Copy link

coderbuzz commented Sep 19, 2019

How to initialise Ionic app manually using Vanilla JS?

Call setupConfig only seems not working.

Need something like import { setupConfig, init } from '@ionic/core'; init();

The following just utilize JSX to generate HTML Elements

import React from 'react';
import ReactDOM from 'react-dom';
import { App } from './App';

import { setupConfig } from '@ionic/core';

ReactDOM.render(<App />, document.getElementById('app'));

setupConfig({
    mode: 'ios',
});

// init(); ???

@ippeiukai
Copy link

ippeiukai commented Sep 26, 2019

It would be helpful to have a way for bundling imported @ionic/core with Webpack etc. too.

Right now, the vanilla JS files in dist directory tries to find a script tag with src matching specific filename in DOM tree, and then downloads extra files relative to that src URL. Even if we give up bundling and copy entire dist directory, it’s not pretty with our web framework’s static asset management that wants filename with contenthash.

@adrm
Copy link
Author

adrm commented Feb 6, 2020

I understand the need for this feature is lower now since we have Ionic packages for several popular frameworks, but you can easily import Ionic web components to be used everywhere, after npm install @ionic/core, like this:

import { IonicConfig } from "@ionic/core"
import "@ionic/core/css/ionic.bundle.css"
import { defineCustomElements } from "@ionic/core/loader"

const win = window as Window & { Ionic: { config: IonicConfig } }
const Ionic = (win.Ionic = win.Ionic || { config: {} })

Ionic.config = {}
defineCustomElements(window).then(() => { /* Ionic is loaded! */ })

Depending on your setup, you might need to import css in other way. You can also import the bundled files from the CDN but in my case I needed some more control than that, and I would like to control which files are executed in my app, have them version-controlled, and be able to run the app offline for development.

I think this should be stated on the docs, understanding that this is not a very frequent way to use Ionic but it helps demonstrating that Ionic is no longer tied to any framework and you can even use it in a framework agnostic way.

@coderbuzz
Copy link

Hi @adrm , thank you for the hints. Unluckily I still got error rendering simple button:

<template>
  <div>
      <ion-button>Default</ion-button>
  </div>
</template>
import { IonicConfig } from "@ionic/core"
import "@ionic/core/css/ionic.bundle.css"
import { defineCustomElements } from "@ionic/core/loader"

// console.log(IonicConfig) => undefined

// const win = window & { Ionic: { config: IonicConfig } }
// const Ionic = (win.Ionic = win.Ionic || { config: {} })

window.Ionic = { config: {} }

defineCustomElements(window).then(() => { 
	/* Ionic is loaded! */ 
	console.log('Ionic loaded')
})
Ionic loaded
[Error] TypeError: 'text/html' is not a valid JavaScript MIME type.
	promiseReactionJob
[Error] Unhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'Cstr.isProxied')
	(anonymous function)
	rejectPromise
	promiseReactionJob

@uriannrima
Copy link

I understand the need for this feature is lower now since we have Ionic packages for several popular frameworks, but you can easily import Ionic web components to be used everywhere, after npm install @ionic/core, like this:

import { IonicConfig } from "@ionic/core"
import "@ionic/core/css/ionic.bundle.css"
import { defineCustomElements } from "@ionic/core/loader"

const win = window as Window & { Ionic: { config: IonicConfig } }
const Ionic = (win.Ionic = win.Ionic || { config: {} })

Ionic.config = {}
defineCustomElements(window).then(() => { /* Ionic is loaded! */ })

Depending on your setup, you might need to import css in other way. You can also import the bundled files from the CDN but in my case I needed some more control than that, and I would like to control which files are executed in my app, have them version-controlled, and be able to run the app offline for development.

I think this should be stated on the docs, understanding that this is not a very frequent way to use Ionic but it helps demonstrating that Ionic is no longer tied to any framework and you can even use it in a framework agnostic way.

Can't say how much I'm grateful for your tip, man. Worked like a charm to me. Thank you so much again.

@coderbuzz
Copy link

Can't say how much I'm grateful for your tip, man. Worked like a charm to me. Thank you so much again.

Hi @uriannrima , might you share with us how you get the code working while I got an error?

@uriannrima
Copy link

Here is what I have and what I did:

I've an Vue application that I don't want to use @ionic/vue but use directly the web components without something in between. Since it is SSR App I've two entry points, one for client side and other for server. I don't want the web components in server so I've added the example given by @adrm only in the client entry just after the Vue app bootstrap, like so:

import { IonicConfig } from "@ionic/core";

//import "@ionic/core/css/ionic.bundle.css";
import "./ionic.scss";

import { defineCustomElements } from "@ionic/core/loader";

export function setupIonic() {
  if (window === undefined) {
    throw new Error("Setup ionic should be called client side only.");
  }

  const win = (window as unknown) as Window & {
    Ionic: { config: IonicConfig };
  };
  const Ionic = (win.Ionic = win.Ionic || { config: {} });

  Ionic.config = {};

  return new Promise((resolve, reject) => {
    defineCustomElements(window)
      .then(resolve)
      .catch(reject);
  });
}

export default setupIonic;

The ionic.scss imports the ionic styles like @brandyscarney recommend.

In entry-client I have:

import { loadAsyncComponents } from "@akryum/vue-cli-plugin-ssr/client";
import "./registerServiceWorker";

import { createApp } from "./main";
import { setupIonic } from "./plugins/ionic";

createApp({
  async beforeApp({ router }) {
    await loadAsyncComponents({ router });
  },

  afterApp({ app, router, store }) {
    store.replaceState(window.__INITIAL_STATE__);
    router.onReady(() => {
      app.$mount("#app");
      setupIonic();
    });
  }
});

You may ignore most of what is written, the only important thing is the setup ionic after the vue mount. As I register the components only after vue mounts maybe it solves something that is happening to you @coderbuzz.
I'll try to create a simple raw JavaScript app with webpack to see if also happens to me.

@coderbuzz
Copy link

coderbuzz commented Feb 27, 2020 via email

@uriannrima
Copy link

@coderbuzz I've used Codesandbox (that uses Parcel behind it) to create a vanilla JS project with the solution given by @adrm and it worked as expected.

It takes a few milliseconds to ionic to "bootstrap", but it loads and apply the Ionic theme to the buttons created in in the HTML and even in the innerHTML version using plain js.

I would recommend you to try to remove some lines from the example given by @adrm and see in which one you start to have trouble, cause I can't see why it would give an error for you (unless, like I said if you're trying to use it server side, which cause problems).

@coderbuzz
Copy link

@uriannrima still got error

[Error]: TypeError: 'text/html' is not a valid JavaScript MIME type.
[Error] Unhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'Cstr.isProxied')

Vue is loaded after Ionic loaded, see: index.js

I created repository here: https://github.com/coderbuzz/ionic-vue

Please take a look

@touletan
Copy link

I understand the need for this feature is lower now since we have Ionic packages for several popular frameworks, but you can easily import Ionic web components to be used everywhere, after npm install @ionic/core, like this:

import { IonicConfig } from "@ionic/core"
import "@ionic/core/css/ionic.bundle.css"
import { defineCustomElements } from "@ionic/core/loader"

const win = window as Window & { Ionic: { config: IonicConfig } }
const Ionic = (win.Ionic = win.Ionic || { config: {} })

Ionic.config = {}
defineCustomElements(window).then(() => { /* Ionic is loaded! */ })

Depending on your setup, you might need to import css in other way. You can also import the bundled files from the CDN but in my case I needed some more control than that, and I would like to control which files are executed in my app, have them version-controlled, and be able to run the app offline for development.
I think this should be stated on the docs, understanding that this is not a very frequent way to use Ionic but it helps demonstrating that Ionic is no longer tied to any framework and you can even use it in a framework agnostic way.

Can't say how much I'm grateful for your tip, man. Worked like a charm to me. Thank you so much again.

I'm getting and error mentionning that IonicConfig is not found in @ionic/core ????

@liamdebeasi liamdebeasi added triage New issues and removed content Issues related to the contents of the documentation website labels Sep 20, 2022
@DamianoP
Copy link

DamianoP commented Mar 2, 2023

I understand the need for this feature is lower now since we have Ionic packages for several popular frameworks, but you can easily import Ionic web components to be used everywhere, after npm install @ionic/core, like this:

import { IonicConfig } from "@ionic/core"
import "@ionic/core/css/ionic.bundle.css"
import { defineCustomElements } from "@ionic/core/loader"

const win = window as Window & { Ionic: { config: IonicConfig } }
const Ionic = (win.Ionic = win.Ionic || { config: {} })

Ionic.config = {}
defineCustomElements(window).then(() => { /* Ionic is loaded! */ })

Depending on your setup, you might need to import css in other way. You can also import the bundled files from the CDN but in my case I needed some more control than that, and I would like to control which files are executed in my app, have them version-controlled, and be able to run the app offline for development.

I think this should be stated on the docs, understanding that this is not a very frequent way to use Ionic but it helps demonstrating that Ionic is no longer tied to any framework and you can even use it in a framework agnostic way.

The proposed solution doesn't work anymore with the current version of Ionic

@LeviticusMB
Copy link

I've spent a lot of time recently — too much — trying to bundle @ionic/core in a fresh Vite+Lit project, but I just couldn't make it work. And there seem to be next to nothing about consuming plain Ionic (without any framework bindings) with Vite on the web either ...

There really ought to be a section in the Ionic Packages & CDN page about how to bundle Ionic with popular bundlers such as Vite, Rollup and Webpack at least.

Anyway, adding

    optimizeDeps: {
        exclude: ['@ionic/core']
    }

to the Vite config did make the dev server work, but when building for production, all components (like ion-app_8.entry.js etc) are missing from the assets folder and fails to load. I tried to copy them manually from node_modules/@ionic/core/dist/esm/, but that just lead to more weird runtime exceptions.

In the end, I gave up on lazy-loading the Ionic components (including the optimizeDeps.exclude hack). Instead, I use the following build-ionic-loader.cjs script to create a src/ionic-loader.ts file to manually define the components I use, and which I then import in the Vite project.

#!/usr/bin/env node

const tagsMap = Object.fromEntries(require('@ionic/core/dist/docs.json').components.map((c) => [c.tag, c]));
const pattern = [...new Set(process.argv.slice(2))].map((arg) => `(${arg})`).join('|') || '.*';
const matcher = new RegExp(`^(${pattern})$`);
const allTags = new Set();
const addTags = (tag) => { allTags.add(tag); tagsMap[tag]?.dependencies.forEach(addTags); }

// Gather all matching tags and their dependencies
Object.keys(tagsMap).filter((tag) => matcher.test(tag)).forEach(addTags);

// If interpreted as a TS file, we need to ignore the missing 'ion-icon' declarations
console.log(`// @ts-nocheck`);

// Import and define all matching tags and their dependencies
[...allTags].sort().forEach((tag) => {
    const fn = tag.replace(/-/g, '_');
    console.log(`import { defineCustomElement as ${fn} } from '@ionic/core/components/${tag}'; ${fn}();`);
});

I can run this script as

./build-ionic-loader.cjs > src/ionic-loader.ts `grep -rho '<ion-[^ />]*' src | cut -c2-`

to only bundle the Ionic components I actually use in my project. And then I just bootstrap Ionic as usual, except that I also import the src/ionic-loader.ts to "preload" the components I use.

import { initialize } from '@ionic/core/components';
import { defineCustomElements } from '@ionic/core/loader';

/* Core CSS required for Ionic components to work properly */
import '@ionic/core/css/core.css';

/* Basic CSS for apps built with Ionic */
import '@ionic/core/css/normalize.css';
import '@ionic/core/css/structure.css';
import '@ionic/core/css/typography.css';

/* Optional CSS utils that can be commented out */
import '@ionic/core/css/padding.css';
import '@ionic/core/css/float-elements.css';
import '@ionic/core/css/text-alignment.css';
import '@ionic/core/css/text-transformation.css';
import '@ionic/core/css/flex-utils.css';
import '@ionic/core/css/display.css';

/**
 * Ionic Dark Mode
 * -----------------------------------------------------
 * For more info, please see:
 * https://ionicframework.com/docs/theming/dark-mode
 */

/* import '@ionic/core/css/palettes/dark.always.css'; */
/* import '@ionic/core/css/palettes/dark.class.css'; */
import '@ionic/core/css/palettes/dark.system.css';

/** Initialize Ionic */
import './ionic-loader';

defineCustomElements();
initialize({
    ...navigator.platform?.startsWith('Mac') ? { mode: 'ios'}  : {},
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage New issues
Projects
None yet
Development

No branches or pull requests

10 participants