Giter Site home page Giter Site logo

appfairy's Introduction

Appfairy

appfairy

I'm just tired going through a design and translating it into React components. Appfairy is a CLI tool that does that for you - by running a single command the design will be transpiled into React components. As for now Appfairy works with Webflow only for web React apps, but the near future plans are to have that compatible with Sketch and React Native.

Methodology

Since machine generated assets aren't very easy to maintain due to their complexity, Appfairy takes on an old school approach where a single component is made out of a view and a controller. The view is automatically generated by Appfairy and shouldn't be changed, we treat it as a black box. The controller however is user defined. Every element within the controller is a proxy to an element within the view.

Here's an example of a possible controller:

import React from 'react'
import ConsultFormView from '../views/ConsultFormView'

class ConsultFormController extends React.Component {
  state = {}

  render() {
    return (
      <ConsultFormView>
        <name onChange={this.setName} />
        <phone onChange={this.setPhone} />
        <email onChange={this.setEmail} />
        <description onChange={this.setDescription} />
        <submit onClick={this.submit} />
      </ConsultFormView>
    )
  }

  setName = (e) => {
    this.setState({
      name: e.target.value
    })
  }
  setPhone = (e) => {
    this.setState({
      phone: e.target.value
    })
  }

  setEmail = (e) => {
    this.setState({
      email: e.target.value
    })
  }

  setDescription = (e) => {
    this.setState({
      description: e.target.value
    })
  }

  submit = () => {
    alert(`
      ${this.name}
      ${this.phone}
      ${this.email}
      ${this.description}
    `)
  }
}

export default ConsultFormController

This way the view can be changed without us worrying about re-binding the event listeners and props.

For an in-depth explanation regards Appfairy be sure to check-out the following:

  • Medium blog post - An introduction to Appfairy and the motives behind it.

  • YouTube video - I walk through Appfairy and an implementation of an example app.

  • Example app - An example for a simple app which uses Appfairy.

Docs

Appfairy is a CLI tool that can be installed using NPM:

$ npm install appfairy -g

After exporting your Webflow project into a zip file, simply unzip it into a directory called .appfairy in the root of your project and run $ appfairy. Be sure to stash all your git changes as beforehand as Appfairy uses git as a version control. After doing so you'll notice that a new git-commit has been created saying appfairy: Migrate. This commit include all the changes that Appfairy has made, and shouldn't be edited or reworded.

The commit consists of the following files (regardless if they were added, modified or deleted):

  • public/ (public assets which should be served by our app's server)

    • images/

    • fonts/

    • css/

  • src/

    • scripts/ (scripts that should be imported in index.js)

    • styles/ (css files that should be imported in index.js)

    • views/ (contains ConsultFormView - further explanation below)

The output can be controlled using a config file named af_config.js which should be located in the root of the project. The config file may (or may not) include some of the following options:

  • prefetch (boolean) - Prefetch the styles and scripts which are necessary for the design to work. If not specified, the scripts and styles will be fetched during runtime. An example app with prefetching enabled can be found here.

  • source (source) - Can either be set to webflow, sketch and represents the studio name that generated the basic CSS and HTML assets. If not set there will be little to no difference in the transpilation process but it will however make the CSS encapsulation more accurate. Examples for Webflow and Sketch apps can be found here.

  • input (string) - The input dir for the Webflow exported files. Defaults to .appfairy dir in the root of the project.

  • output (string/object) - If a string was provided, the output will be mapped to the specified dir. If an object, each key in the object will map its asset type to the specified dir in the value. The object has the following schema:

    • public (string) - Public dir. Defaults to public.

    • src (string/object) - Source dir. If a string is provided, all its content will be mapped to the specified dir, otherwise the mapping will be done according to the following object:

      • scripts (string) - Scripts dir. Defaults to src/scripts.

      • styles (string) - Scripts dir. Defaults to src/styles.

      • views (string) - Scripts dir. Defaults to src/views.

Alternatively, you may provide (extra) options through the command line like the following:

$ appfairy [...options]

The CLI tool supports the following options:

  • --prefetch

  • --source/--src

  • --input/--in

  • --output/--out

  • --config

The behavior of Appfairy will change according to the specified options as detailed above, and the rest is self explanatory.

LICENSE

MIT

appfairy's People

Contributors

dab0mb avatar rub1e avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

appfairy's Issues

Compilation warnings

Hi Eytan!

Trying to follow your tutorial (which is amazing tho). I get the following message:

Failed to compile warning with the following message: ./src/index.js
Attempted import error: './views/IndexView' does not contain a default export (imported as 'IndexView').

This message is given by the default generated code (with the importing changes in the video tutorial), which has module.exports = IndexView; at the bottom of IndexView.js file. As a first guess and you suggested the same: I changed it to export default IndexView; but now I get a different message with no success on compiling my files:

**Compiled with warnings.

./src/views/IndexView.js
Module not found: Can't resolve '../controllers/IndexController' in '/Users/CuentaHTS/Desktop/Heimer Web React/heimer/src/views'

Search for the keywords to learn more about each warning.
To ignore, add // eslint-disable-next-line to the line before.**

This one is my git repository URL: https://github.com/juancarloselorriaga/heimerweb.git

I'm not quite sure how to retrieve the appfairy version.

Thanks in advance!!
JCE

Files missing/Error when using appfairy command

I keep getting this error message when running the appfairy command:
TypeError: Cannot read property 'replace' of undefined at replace (/usr/local/lib/node_modules/appfairy/build/webpack:/src/utils/index.js:6:13) at escape (/usr/local/lib/node_modules/appfairy/build/webpack:/src/writers/view-writer.js:347:31) at Array.map (<anonymous>) at ViewWriter.map (/usr/local/lib/node_modules/appfairy/build/webpack:/src/writers/view-writer.js:344:28) at ViewWriter.composeScriptsDeclerations (/usr/local/lib/node_modules/appfairy/build/webpack:/src/writers/view-writer.js:275:22) at compose (/usr/local/lib/node_modules/appfairy/build/webpack:/src/writers/view-writer.js:258:77) at Generator.next (<anonymous>) at step (/usr/local/lib/node_modules/appfairy/build/appfairy.js:604:191) at /usr/local/lib/node_modules/appfairy/build/appfairy.js:604:437 at new Promise (<anonymous>)

Although it is an Error I still get all of my view files except the home IndexView.js.

I tried installing previous versions with no avail.. Is there something I might need to configure? Let me know if you need me to include my index html file. Thanks!

Unhandled Rejection (ReferenceError): Stats is not defined

Hi, I have yet to get appfairy working. Right now this is the error I'm blocked on:
Unhandled Rejection (ReferenceError): Stats is not defined

I followed the instructions on the blog. When I refresh the site (localhost), I can see my website for a split second and then I see the error screen.

For context, I am a mobile developer and am very junior to React. Not sure If something messed up with appfairy or something is wrong with configuration.

Any help or context on this is greatly appreciated.

Screen Shot 2021-11-16 at 7 09 24 PM

React-router warnings

First off, love this app! Rely on it a lot.

I noticed that when I was using react-router to navigate (Link and history.push) it was throwing me an error of

TypeError: e is not a function
r.define
src/views/DiscoverView.js:38
35 | componentDidMount() {
36 | scripts.concat(Promise.resolve()).reduce((loaded, loading) => {
37 | return loaded.then(script => {
**> 38 | new Function(with (this) {eval(arguments[0])}** | ^ 39 | ).call(window, script);
40 |
41 | return loading;

I managed to fix it by manually going into the appfairy generated view page and adding a "$" in front of it, changing it to "$ {eval(arguments[0])}", and now it works fine with react-router

Not sure whether its just the way I am using appfairy, or generating the pages, but posting this here just in case other people have the same issue

Reusable components & content mapping

Is it possible to assign "af-el" to multiple elements with the same class to make them act as a singular component and have content mapped so that the components render content as well?

Currently, it renders something like this:

<div>
    <MenuLinkView.Controller />
    <MenuLinkView.Controller />
    <MenuLinkView.Controller />
    <MenuLinkView.Controller />
</div>

And the intended behavior would be something like this

<nav>
    <MenuLinkView.Controller label="Home" />
    <MenuLinkView.Controller label="Features" />
    <MenuLinkView.Controller label="Pricing" />
    <MenuLinkView.Controller label="Contact" />
</nav>

Also, since we're using BEM, classes are pretty well named, but it looks like Appfairy renames all classes. Any way to make certain classes preserve their original name? e.g. if they start with a prefix, such as abr-c- in our case:

Original class: abr-c-menu__dropdown
Appfairy class: af-class-abr-c-menu__dropdown

Any thoughts? @DAB0mB

Thanks!
Alex

zsh: command not found: appfairy

I am trying to build react components using appfairy command after installing appfairy globally. I am getting this error: zsh: command not found: appfairy please help.

Interactions and observers not working with appfairy

I wasn't able to see any of my js scripts run on my pages when I ran the appfairy command. It seems like the issue was that appfairy renames all classes on the html files with "af-class-yourclass" so then the js file cannot attach to those after.

A quick workaround, a little time consuming but works:

Just search for selectors on bottom of webflow js file and add "af-class-" to them. i.e. ".thisClass" to ".af-class-thisClass"

They are all within these 2 initializer functions at the bottom of the Webflow generated script:
Webflow.require('ix').init(....)

Webflow.require('ix2').init(...)

Also, I don't know if its because I am rendering the pages on the server with NextJS, but I also had to add some attributes to my html tag for other animations to work correctly using:
var doc = document.getElementsByTagName("html")[0] doc.setAttribute('data-wf-page', 'yourPageID') doc.setAttribute('data-wf-site', 'yourWebflowSiteID') //optional for language doc.setAttribute('lang', 'en')

Also, with nextJS I had to wrap these two initializer functions so they would only run on client side and not give me a "document not defined" when compiled on server using:
$( document ).ready(function() {}

Hope this saves someone else a day of debugging!

Css not working

I followed the video step by step and successfully ran the react app but noticed that it only worked for the HTML files and CSS was nowhere to be found.

Controllers architecture

Thank you for an 🌟Awesome🌟 project, @DAB0mB !

I want to discuss several things I noticed related to the controller architecture.

The controllers is not part of the auto-magic-generation, but something which the developer fully custom-writes on his own. And currently I can see 2 problems with this:

  1. Controller-components are plugged in into the View-component in a hardcoded way (the name of the Controller has to be magically specific, otherwise nothing will work).

    Possible solution: Precreate controllers/ folder automatically with all the magic Controller files (unless the file already exists) with the basic structure.

  2. sub-Controllers (like ContractFormController).

    The usual usecase for the top-level page Controllers (like IndexController, ThankYouController) is that you'll render them through the router, like react-router.

    But the ContactFormController is going to end up being plugged in into the project by a complete magic. Neither used in the router, neither used anywhere (unless you know that it's being required implicitly in the views/)

    Possible solution: Force developer to use it in the parent Controller -- maybe allow to use the actual ContactFormController somehow instead of the contact-form socket here. Overall creating both: the af-el contact-form AND the af-sock contact-form seemed strange. I think it would be great if af-el can somehow play the af-sock role.

Would be great to know what you think about those items. And thanks for the awesome library once again!

Can't resolve '..controllers/IndexController' in 'C:\path\appfairy\src\views'

Getting this issue everytime I run Appfairy.
I got this issue simply by following this tutorial

Compiled with warnings.

./src/views/IndexView.js
Module not found: Can't resolve '..controllers/IndexController' in 'C:\path\appfairy\src\views'

Search for the keywords to learn more about each warning.
To ignore, add // eslint-disable-next-line to the line before.

I got the same issue over and over, the webflow files that were used for this convertation will be attached bellow
test-with-cms.webflow.zip

Column element from webflow doesn't display well

Hi!

First, thanks a lot fo this awesome library, it saves us so much time !

I want to share a problem we are experiencing with the column element from webflow.

It seems that some of the columns classes names aren't replaced well ("w-row", "w-col", etc...) as they are for the other elements (prefixed with "af-class"), creating conflicts and thus some styles are not applying. It does work on desktop view but stops as soon as the columns should be displayed vertically.

Any idea on how to resolve this ?

Thanks a lot in advance :)

unable to inject af-el components

Hi Eytan, first of all, great work here, this concept can allow people to save so much time.

In the latest version (0.7.3), the views generated by the appfairy command are a bit different and I don't know how to use child components, could you provide a snippet as an example of how to use it? if you do, I can send you a PR with an up to date example.

The HTML bit exported from webflow is as follows. I'll call it MainView

<body class="body">
  <div af-el="prod-form" af-sock="prod-form" class="div-block-2">
    <div class="w-form">
      <form id="wf-form-Producdt-Identification-Form" name="wf-form-Producdt-Identification-Form" data-name="Producdt Identification Form">
          <label for="name">Product Name</label>
          <input type="text" class="w-input" maxlength="256" name="name" af-sock="prod-name" data-name="Name" id="name" required="">
          [...]
          <input type="submit" value="Submit" data-wait="Please wait..." af-sock="prod-submit" class="w-button">
</form>
      <div class="w-form-done">
        <div>Thank you! Your submission has been received!</div>
      </div>
      <div class="w-form-fail">
        <div>Oops! Something went wrong while submitting the form.</div>
      </div>
    </div>
  </div>

In the generated MainView, in the place of the div with af-el=prod-form it generates some lines like these

<div className="af-class-body">
  <ProdFormView.Controller-af-sock-prod-form />
       {/* [if lte IE 9]><![endif] */}
</div>

Then in MainController I did the following, according to the 'prefetch' tutorial

import React from 'react';
import ProdFormController from './ProdFormController';
import MainView from '../views/MainView';

export default (params) => (
  <MainView>
      <prod-form {...params} />
  </MainView>
);

when running a project with this view and controller renderd by the Router, I get an error like this:

TypeError: Property property of MemberExpression expected node to be of a type ["Identifier","PrivateName"] but instead got "StringLiteral"

Trying to find out what's wrong, I saw the view on your example, and it's a bit different, there the af-el element would be parsed as

<div className="__af-container-2 __af-w-container">
            <h1 className="__af-heading-3">Registered Immigration Agent in Sydney, Australia</h1>
            {proxies['contact-form'] && <ContactFormView.Controller {...proxies['contact-form']}>{proxies['contact-form'].children}</ContactFormView.Controller>}
</div>

It doesn't look like something generated by the current version.

Could you guide me on how the new parsed views are supposed to be used?

Thanks! keep up the great work!.

appfairy_config.js not working

When trying to use a custom config, it won't read the config from the project root. Also, when triggered via the CLI, it says it can't find a path. Any thoughts?

When using Appfairy, my whole page gets overwritten with the current date

This is a bit of a weird issue! But bear with me.

I have just run Appfairy on my webflow exported code, and I now have two versions, my react one, and my original webflow files.

My original webflow files work as expected (deployed from src/public_site/.appfairy)- see here.
My new Appfairy react-ified webflow loads the page, and then covers the whole thing with some kind of override that deletes all elements and replaces them with the current date - see here.

All the code for reproducing this issue is available in my repository here. The site code is contained in src/public_site.

Interactions don't seem to work after appfairy migration

Hello,
I have looked through the two other interaction-related issues and i don't understand them. How exactly does one get click interactions working after migrating a Webflow project to React? There is literally no documentation on this...

Webflow to Gatsby - what do I do with webflow.js and jQuery?

I’m hoping to create a workflow where I can easily port Webflow code to Gatsby while minimizing recurring manual changes when using AppFairy.

The intermediary step was to get my site working using a create react app project. Using AppFairy, I’m able to get most of the website working with create react app.

When I run gatsby develop and gatsby build, the CSS styling seems to work, but everything is still off. I think it has to do with how some of the scripts are added via AppFairy, particularly webflow.js.

Before I get into the AppFairy questions - I’m reading that combing jQuery with React breaks a lot of patterns. Frankly, I don’t care so long as it works, but could this prevent me from porting Webflow to Gatsby?

Here is a snippet from the AppFairy generated IndexView.js for my project:

  componentDidMount() {
    const scripts = [
      fetch("https://d3e54v103j8qbb.cloudfront.net/js/jquery-3.4.1.min.220afd743d.js").then(body => body.text()),
      fetch("js/webflow.js").then(body => body.text()),
    ]
    scripts.concat(Promise.resolve()).reduce((loaded, loading) => {
      return loaded.then((script) => {
        new Function(`
          with (this) {
            eval(arguments[0])
          }
        `).call(window, script)

        return loading
      })
    })
  }

I moved const scripts into comonentDidMount because global is not exposed during the gatsby build process (but this does not cause problems during gatsby develop).

This is my understanding of the code - after the script has fully loaded, execute the script in the window context

  • Is this akin to dependency injection? Like script injection, but for that specific react component?
  • What happens to this script during react-scripts start and react-scripts build? I can’t find the <script> related to jquery or webflow.js. Is it “integrated” into the React component?
  • Can I treat webflow.js like any other script i.e. can I create an npm package from that file and fetch it via unpkg?

Lastly, what is going on with the following from scripts.index.js:

  {
    type: 'code',
    body: '!function(o,c){var n=c.documentElement,t=" w-mod-";n.className+=t+"js",("ontouchstart"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+"touch")}(window,document);',
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.