Coder Social home page Coder Social logo

tux's Introduction

TUX

Create content-driven React websites with SSR and a plug-and-play configuration.

Tux uses add-ons, containing Neutrino and React Chain middlewares, to configure the build and render pipeline respectively.

Note: Tux is still in an experimental development stage. The documentation is not complete or may be out of date. If you have questions, feel free to reach out on Twitter or Slack.

CircleCI branch npm Slack channel

Quick start

yarn create tux-app hello-tux

cd hello-tux/
npm start

Then open http://localhost:5000/ to see your app.

When you're ready to deploy to production, run npm run build to build production bundles, then npm run serve to serve those bundles. If you don't need SSR, you can ship build/static to your favourite HTTP server.

What you get

  • React app with server side rendering.
  • Modern Babel compilation supporting ES modules, last 2 major browser versions (Node.js 6.9+), async functions, dynamic imports, JSX and object rest spread syntax.
  • Webpack loaders for importing HTML, CSS, images, icons, and fonts.
  • Environment variables to detect BROWSER, SERVER and ADMIN builds and remove unused code.
  • Automatic and overridable creation of the HTML page using the React Document component.
  • Development:
    • Webpack Dev Server during development.
    • Excellent error handling during development. See stack traces with code snippets in the browser.
    • Hot Module Replacement support with React Hot Loader.
    • Hot reload on server.
  • Production
    • Tree-shaking to create smaller bundle.
    • Production-optimised bundles with Babili minification and easy chunking.
    • Use environment variables to remove server dependencies in browser build.
    • Extracted css in production builds.
    • Long term browser caching with automatic cache invalidation.

The following features (and more) are just an add-on away, properly configured for SSR.

  • React Router v4.
  • Async components with code splitting.
  • Data fetching.
  • React Helmet to configure meta tags for better SEO.
  • CSS in JS.
  • Integrated admin for headless CMS data.

How tux works

Your src/app.js file defines a series of middlewares that compile and run differently on browser and server. The last middleware usually returns the main app component while previous middlewares wrap it or influence how it is rendered. Here are some examples of things middlewares can do:

  • Wrap your app with a Provider component, eg BrowserRouter in the browser and StaticRouter on the server.
  • Pre-render the app, eg to fetch data that is needed for initial render.
  • Track rendered components, styles and chunks.

Middlewares can add tags to the html Document on the server. They can also write data into a script tag and use it for the first render in the browser.

Topics

  • Add-ons
  • Dev Server (Coming soon)
  • Admin (Coming soon)

License

MIT

tux's People

Contributors

baering avatar benediktvaldez avatar davidbachmann avatar eirikurn avatar rthor avatar thorsteinsson 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

Watchers

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

tux's Issues

Compare to next

Milestone 1 is quite similar to next.

Let's do more research into the following and document if and why we can't use next.

  • Should not destroy all markup and components when changing pages. For performance and page transitions.
  • Data fetching? Adapter design for later milestones?

Importing svg doesn't work

image

<img class="SocialPlug-logo" src="data:application/svg+xml;base64,PD94bWwgdmVy...

import twitterLogo from './Twitter.svg' in 'tux-example-site/src/components/SocialPlug/index.js

Missing icons in TuxFab

Created my fancy new project by running tux new awesome-project

But I don't seem to get any icons. Is that by design? Feels like it shouldn't, so here's an issue ๐ŸŽ

Be able to edit image fields

  • Create a component to render fields with images
  • Be able to:
    • Add a new image
    • Change an existing image
    • Remove image

Make TuxModal field id consistent with inline editor

I love that there is almost nothing contentful specific in tux anymore.

One remaining thing is that TuxModal still hard codes model.fields[...] instead of sharing dynamic field name logic with the inline editor.

After adding this support, we can change the contentful schemas to have field: 'fields.title' instead of field: 'title'.

Contentful adapter should not override existing localisations

Currently extractLocale and injectLocale remove other locales. They should be persisted somehow. Maybe store both versions in the same object:

{
  "sys": ...,
  "fields": {
    "title": "foo"
  },
  "__locale_fields": {
    "title": {
      "en-US": "foo",
      "de-DE": "lol"
    }
  }
}

Change EditableList to Editable

Use like this:

{articles.map(article =>
  <Editable key={article.id} model={article}>
    <h1>Render mode - {article.name}</h1>
  </Editable>
)}

Admin: Change tracking and publishing

Tux Admin should track changes (outside the adapter). For now, changes should be stored in memory or localstorage, but in the future we might want to sync these changes to some cloud service.

Changes appear in the edit bar on the bottom, which has a button to publish the changes, and a way to list and revert changes. Adapters should provide a friendly name for the model and a title for each instance.

When editing a whole model, the modal should have 3 buttons: Cancel, Preview and Publish. Clicking Publish save all model changes to the adapter. Clicking Preview tracks the changes locally, closes the modal and updates the page to reflect the changes. These changes can be published by clicking the button in the edit bar, or opening the modal again.

When clicking the edit button, tux should toggle between showing published and non-published data.

Questions:

  • Should edit bar list all changed sub-models or just the parent model (eg sections of an article)?
  • How granular should change tracking appear in the edit bar? Field level, or model level?
  • Conflict tracking: Always override with local changes? Prompt user to use server changes or local changes? Apply to whole model or per field?

Initialize management api with locales from server.

The management api has a way to get all configured locales for the site. That has a concept of "default locale". We should fetch that when we initialize the management api.

It's possible to abstract this initialisation in different ways. E.g.

async load(...args) {
  const api = await getManagementApi()
  return await api.load(...args)
}

Rename clientId in contentful adapter to something more relatable

tux-adapter-contentful takes an option called clientId which had me confused for a while since I couldn't find anything called clientId from contentful. Turns out they call it different things, meaning that clientId turned out to be my applications Uid

I can see why you went with clientId in the first place since where you use it (in the 'log in' path to contentful) it is called client_id โ€“ but from an outsiders perspective, the developer that never really considers this path, this is like I mentioned before my applications Uid

My suggestion would be to name it something like applicationUid.

What say thee?

Inline editing

  • As a string value
  • With formatting, ie rich text editing.
  • Initialize editor with fallback value.
  • Custom editor demo, e.g. inline date picker

Field support for Editable

Be able to edit fields inline by supplying the model and name of the field.

<Editable model={article} field="title" />

It should support both dot notation and arrays for field names.

Improve the new site template

  • Should have a bit more (still minimal) render output.
  • Fetch a model and render it with Editable?
  • Better readme. Document app.js contract.

Use neutrino for configuring webpack

We should create one or more tux presets for neutrino. It's a simple way to get started with webpack 2 but still allow websites to extend with more presets or configurations.

A better logged out experience

Now the log in button is almost hidden at the bottom, while the edit button is active but doesn't work obviously.

We could replace the full sidebar with a tux login message+button, but how about changing the tab to say "Login" instead of "Tux", and have it immediately trigger the login flow? So you don't even see the sidebar.

Just an idea.

JavaScript heap out of memory

Happened after not finding an import module:

Security context: 0xXXXXXX <JSObject>
    1: _parseMappings(aka SourceMapConsumer_parseMappings)

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

Admin: Create a demo adapter

We need a demo adapter to better demonstrate the functionality of Tux Admin in tux-example-site.

The adapter should have a simple way to initialise data. Something like this:

import { define } from 'tux-adapter-localstorage'
import { registerEditable, MarkdownField, Input } from 'tux'

// interface Instance {
//   id: string
// }
// function define<T extends Instance>(model: string, instance: T): void

registerEditable('Quote', [
  {
    field: 'quote',
    label: 'Quote',
    component: MarkdownField,
  }
  {
    field: 'author',
    label: 'Author',
    component: Input,
  }
])


define('Quote', {
  id: 'foo',
  quote: '50% of the time, it works 100%',
  author: 'Eirikur',
})

// [snip]

import { Adapter } from 'tux-adapter-localstorage'
import { tuxMiddleware } from 'tux'
createChain()
  .chain(tuxMiddleware({
    adapter: new Adapter()
  }))

The define method should only save the instance if one doesn't already exist with the same id. It should only perform soft-deletes (so instances aren't recreated when you refresh).

The adapter's query api should be able to query in instance by id and type.

tux.svg in /src throws error ENAMETOOLONG

I get this error when using yarn start (n7.0.0)

Error: ENAMETOOLONG: name too long, stat '/Users/seb/Sites/tux/my-app/src/"data:image/svg+xml,<svg xmlns='http:/www.w3.org/2000/svg' viewBox='0 0 496.1 367.5' style='enable-background:new 0 0 496.1 367.5;'> <path d='M93.8 277.9c-4 .7-7.8 1.1-11.6 1.1-13.4 0-23-3.8-28.8-11.4-5.7-7.6-8.6-17.1-8.6-28.6V109.8H7.5v-7.1h37V52.3h8.2v50.4h50.4v7.1H52.7V239c0 11.7 2.9 20.1 8.6 25.2 5.7 5.1 13.3 7.7 22.8 7.7 7 0 13.3-1.1 19.1-3.4l1.1 6.4c-3.1 1.2-6.6 2.2-10.5 3z'/> <path d='M267.7 250.8c-4.6 6.4-9.9 11.6-15.9 15.9-6 4.2-12.5 7.5-19.4 9.7-7 2.2-14.2 3.4-21.7 3.4-12 0-21.9-2.1-29.9-6.4-8-4.2-14.3-9.8-19.1-16.8-4.7-7-8.1-14.8-10.1-23.5s-3-17.6-3-26.5V102.7h8.2v103.1c0 7.2.7 14.8 2.2 22.6 1.5 7.8 4.3 15 8.4 21.5 4.1 6.5 9.6 11.9 16.4 16.2 6.8 4.4 15.7 6.5 26.7 6.5 9.5 0 18.4-1.9 26.7-5.8s15.6-9.4 21.7-16.6c6.1-7.2 11-16 14.6-26.3 3.6-10.3 5.4-22.1 5.4-35.3v-85.9h8.2v128.5c0 2.7.1 6.1.2 10.1s.2 8 .4 12.1c.1 4.1.3 8 .6 11.8.2 3.7.5 6.9.7 9.3h-8.2c-.3-2.5-.4-5.6-.6-9.3-.1-3.7-.3-7.8-.4-12.1-.1-4.4-.3-8.6-.4-12.7-.1-4.1-.2-7.8-.2-11h-.7c-2.6 7.9-6.2 15.1-10.8 21.4z'/> <path d='M410.9 189.4l-62.8 85.2h-10.5l68-90.8-59.4-81.1h10.5l54.5 75.5 54.2-75.5h10.8l-59.8 81.1 69.1 90.8h-10.8l-63.8-85.2z'/> </svg>"'

this being the tux.svg in /src

Contribution guide

Hello there!

I think this project needs some contribution guide. I've installed it locally, opened example project and that's all. I can not even edit the example project data.

Also https locally not working well - chrome is blocking it.

Tree shaking

Make sure that we are removing unused codepaths in production builds.

Refactor contentful logic out of TuxModal

TuxModal should not know that there's a .fields parent object or a en-US field structure.

  1. type should support 'fields.title' and ['fields', 'title'] like the inline editor. For now, let's make all contentful schemas refer to fields.<fieldname> instead of <fieldname>.
  2. In the contentful adapter, let's make load and save unwrap the locale object for now. So adapter.load(model) returns a full model that's structurally similar to model, with fullModel.fields.title instead of fullModel.fields.title['en-US']. And adapter.save(fullModel) adds these locale objects back before saving.
    • This may require a concept of "current locale" (e.g. Aranja's is 'en-US' while Kolibri's is 'en-GB'. See if we can get this from contentful somehow).
    • Also, be careful not to "lose" other locale data when saving. (so store the actual full model and merge current locale changes into it).

[RFC] Separate into multiple packages

Packages

Offline, we agreed on that the project should be managed in a monorepo fashion. The unanswered questions are:

  • What should the separate packages contain?
  • How should we manage dependencies?

Below I outline one proposal for tackling those questions.

Design

Packages

  • @tux/provider: Everything concerning the Contentful integrations. Eg connect, provider, etc.
  • @tux/components: Components for rendering/editing data from the @tux/provider. Eg <Editable />. These should probably not be coupled directly with specifics of the API. It shouldn't care what "backend" is being used, only generically fetch and post data [somehow].
  • @tux/admin This would be the main entry point for the admin itself. It will either need to:
    • support multiple sites,
    • or, be easy to replicate for different sites.

Dependency management

We don't really have that much to maintain in the beginning so maybe this isn't something to worry about. I just think that having this solid to start with will be beneficial in the long run. I recommend we use lerna with the --independent flag so that single package updates will be simple.

[Possible] Drawbacks

  • It might be hard to decouple @tux/provider and @tux/components in practice.
  • Lerna forces a very strict folder structure.

Document deployment scripts

We should probably document how to deploy Tux apps. Like with now:

"now-start": "tux-scripts serve",
"now-build": "tux-scripts build --admin",

Problems running lerna bootstrap

Tried running lerna bootstrap โ€“ which makes sense since this seems to be a lerna monorepo, worked fine until it tried to run the prepublish on tux-cli, at which point it pretends to not find yargs (although it is clearly installed in tux-cli's node_modules)

Not sure what the problem is, I'll leave the whole lerna-debug.log here if someone would like to dissect it. Not really a blocker for me, but might revisit if help is needed.

lerna-debug.log raw output from lerna-debug.log
lerna(verbose) GitUtilities.isInitialized    ()
lerna(verbose) GitUtilities.isInitialized    () => true
lerna(verbose) GitUtilities.getTopLevelDirectory()
lerna(verbose) GitUtilities.getTopLevelDirectory() => "."
lerna(verbose) FileSystemUtilities.existsSync("./lerna.json")
lerna(verbose) FileSystemUtilities.existsSync("./lerna.json") => true
lerna(verbose) FileSystemUtilities.readFileSync("./lerna.json")
lerna(verbose) FileSystemUtilities.readFileSync("./lerna.json") => "{\n  \"lerna\": \"2.0.0-beta.38\",\n  \"packages\": [\n    \"packages/*\"\n  ],\n  \"version\": \"independent\"\n}"
lerna(verbose) FileSystemUtilities.existsSync("./package.json")
lerna(verbose) FileSystemUtilities.existsSync("./package.json") => true
lerna(verbose) FileSystemUtilities.readFileSync("./package.json")
lerna(verbose) FileSystemUtilities.readFileSync("./package.json") => "{\n  \"private\": true,\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"cd packages/tux-example-site && npm start\",\n    \"postinstall\": \"npm run bootstrap\",\n    \"lint\": \"tslint -c './tslint.json' -e './packages/**/node_modules/**/*' -e './packages/**/es/**/*' -e './packages/**/lib/**/*' './packages/**/*.{ts,tsx}'\",\n    \"lerna\": \"lerna\",\n    \"bootstrap\": \"lerna bootstrap --hoist\",\n    \"watch\": \"lerna run watch --stream --no-sort\",\n    \"test\": \"lerna run test\"\n  },\n  \"dependencies\": {\n    \"@types/react-day-picker\": \"^1.2.37\",\n    \"core-js\": \"2.4.1\",\n    \"moment\": \"^2.17.1\",\n    \"react\": \"15.4.2\",\n    \"react-day-picker\": \"^5.1.1\",\n    \"react-dom\": \"15.4.2\",\n    \"react-icons\": \"^2.2.3\",\n    \"typescript\": \"^2.2.2\"\n  },\n  \"devDependencies\": {\n    \"@types/chalk\": \"^0.4.31\",\n    \"@types/classnames\": \"0.0.32\",\n    \"@types/enzyme\": \"^2.7.5\",\n    \"@types/express\": \"^4.0.35\",\n    \"@types/jest\": \"^18.1.1\",\n    \"@types/lodash\": \"^4.14.61\",\n    \"@types/material-ui\": \"^0.16.48\",\n    \"@types/mz\": \"0.0.30\",\n    \"@types/moment\": \"^2.13.0\",\n    \"@types/node\": \"^7.0.4\",\n    \"@types/ramda\": \"0.0.5\",\n    \"@types/react\": \"^15.0.4\",\n    \"@types/react-addons-css-transition-group\": \"^15.0.1\",\n    \"@types/react-dom\": \"^0.14.21\",\n    \"@types/semver\": \"^5.3.31\",\n    \"@types/webpack\": \"^2.2.7\",\n    \"@types/webpack-chain\": \"^3.0.0\",\n    \"@types/yargs\": \"^6.6.0\",\n    \"babel-jest\": \"^18.0.0\",\n    \"babel-plugin-transform-runtime\": \"^6.23.0\",\n    \"babel-preset-es2015\": \"^6.24.1\",\n    \"babel-preset-react\": \"^6.24.1\",\n    \"del\": \"^2.2.2\",\n    \"enzyme\": \"^2.7.1\",\n    \"gulp\": \"^3.9.1\",\n    \"gulp-babel\": \"^6.1.2\",\n    \"gulp-cli\": \"^1.2.2\",\n    \"gulp-clone\": \"^1.0.0\",\n    \"gulp-sourcemaps\": \"^2.4.1\",\n    \"gulp-typescript\": \"^3.1.4\",\n    \"gulp-util\": \"^3.0.8\",\n    \"jest\": \"^18.1.0\",\n    \"lerna\": \"2.0.0-beta.38\",\n    \"merge2\": \"^1.0.3\",\n    \"react-addons-test-utils\": \"15.4.2\",\n    \"react-hot-loader\": \"^3.0.0-beta.6\",\n    \"react-test-renderer\": \"15.4.2\",\n    \"run-sequence\": \"^1.2.2\",\n    \"styled-jsx\": \"^0.5.4\",\n    \"tslint\": \"^5.0.0\",\n    \"typescript\": \"^2.1.5\",\n    \"webpack\": \"^2.2.1\",\n    \"yargs\": \"^6.6.0\"\n  },\n  \"babel\": {\n    \"env\": {\n      \"test\": {\n        \"plugins\": [\n          \"styled-jsx/babel\",\n          [\n            \"transform-runtime\",\n            {\n              \"helpers\": false,\n              \"polyfill\": false,\n              \"regenerator\": true\n            }\n          ]\n        ],\n        \"presets\": [\n          \"react\",\n          \"es2015\"\n        ]\n      }\n    }\n  }\n}"
lerna(info)    Lerna v2.0.0-beta.38
lerna(info)    Independent Versioning Mode
lerna(verbose) FileSystemUtilities.existsSync("./package.json")
lerna(verbose) FileSystemUtilities.existsSync("./package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./lerna.json")
lerna(verbose) FileSystemUtilities.existsSync("./lerna.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./VERSION")
lerna(verbose) FileSystemUtilities.existsSync("./VERSION") => false
lerna(verbose) FileSystemUtilities.existsSync("./packages/jsx-html-webpack-plugin/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/jsx-html-webpack-plugin/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-adapter-contentful/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-adapter-contentful/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-cli/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-cli/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json") => true
lerna(verbose) Attempting running BootstrapCommand.initialize
lerna(verbose) Successfully ran BootstrapCommand.initialize
lerna(verbose) Attempting running BootstrapCommand.execute
lerna(info)    Bootstrapping 7 packages
lerna(info)    Preinstalling packages
lerna(info)    Symlinking packages and binaries
lerna(verbose) FileSystemUtilities.existsSync("./packages/jsx-html-webpack-plugin/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/jsx-html-webpack-plugin/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/node_modules/jsx-html-webpack-plugin")
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/node_modules/jsx-html-webpack-plugin") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/neutrino-preset-tux/node_modules/jsx-html-webpack-plugin")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/neutrino-preset-tux/node_modules/jsx-html-webpack-plugin") => "./packages/jsx-html-webpack-plugin"
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-adapter-contentful/node_modules/tux")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-adapter-contentful/node_modules/tux") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-adapter-contentful/node_modules/tux")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-adapter-contentful/node_modules/tux") => "./packages/tux"
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/neutrino-preset-tux")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/neutrino-preset-tux") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/neutrino-preset-tux")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/neutrino-preset-tux") => "./packages/neutrino-preset-tux"
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/tux")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/tux") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/tux")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/tux") => "./packages/tux"
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/tux-scripts")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/tux-scripts") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/tux-scripts")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/tux-scripts") => "./packages/tux-scripts"
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-adapter-contentful/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-adapter-contentful/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/tux-adapter-contentful")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-example-site/node_modules/tux-adapter-contentful") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/tux-adapter-contentful")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-example-site/node_modules/tux-adapter-contentful") => "./packages/tux-adapter-contentful"
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/neutrino-preset-tux/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/node_modules/neutrino-preset-tux")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/node_modules/neutrino-preset-tux") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-scripts/node_modules/neutrino-preset-tux")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-scripts/node_modules/neutrino-preset-tux") => "./packages/neutrino-preset-tux"
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux/package.json") => true
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/node_modules/tux")
lerna(verbose) FileSystemUtilities.existsSync("./packages/tux-scripts/node_modules/tux") => true
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-scripts/node_modules/tux")
lerna(verbose) FileSystemUtilities.isSymlink ("./packages/tux-scripts/node_modules/tux") => "./packages/tux"
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/neutrino-preset-tux/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/neutrino-preset-tux/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/jsx-html-webpack-plugin", "./packages/neutrino-preset-tux/node_modules/jsx-html-webpack-...)
lerna(verbose) FileSystemUtilities.symlink   ("./packages/jsx-html-webpack-plugin", "./packages/neutrino-preset-tux/node_modules/jsx-html-webpack-...) => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-adapter-contentful/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-adapter-contentful/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux", "./packages/tux-adapter-contentful/node_modules/tux", "junction")
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux", "./packages/tux-adapter-contentful/node_modules/tux", "junction") => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/neutrino-preset-tux", "./packages/tux-example-site/node_modules/neutrino-preset-tux", "j...)
lerna(verbose) FileSystemUtilities.symlink   ("./packages/neutrino-preset-tux", "./packages/tux-example-site/node_modules/neutrino-preset-tux", "j...) => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux", "./packages/tux-example-site/node_modules/tux", "junction")
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux", "./packages/tux-example-site/node_modules/tux", "junction") => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux-scripts", "./packages/tux-example-site/node_modules/tux-scripts", "junction")
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux-scripts", "./packages/tux-example-site/node_modules/tux-scripts", "junction") => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules/.bin")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules/.bin") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux-scripts/bin/tux-scripts", "./packages/tux-example-site/node_modules/.bin/tux-scripts...)
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux-scripts/bin/tux-scripts", "./packages/tux-example-site/node_modules/.bin/tux-scripts...) => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-example-site/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux-adapter-contentful", "./packages/tux-example-site/node_modules/tux-adapter-contentfu...)
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux-adapter-contentful", "./packages/tux-example-site/node_modules/tux-adapter-contentfu...) => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-scripts/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-scripts/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/neutrino-preset-tux", "./packages/tux-scripts/node_modules/neutrino-preset-tux", "juncti...)
lerna(verbose) FileSystemUtilities.symlink   ("./packages/neutrino-preset-tux", "./packages/tux-scripts/node_modules/neutrino-preset-tux", "juncti...) => 
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-scripts/node_modules")
lerna(verbose) FileSystemUtilities.mkdirp    ("./packages/tux-scripts/node_modules") => null
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux", "./packages/tux-scripts/node_modules/tux", "junction")
lerna(verbose) FileSystemUtilities.symlink   ("./packages/tux", "./packages/tux-scripts/node_modules/tux", "junction") => 
lerna(info)    Postinstalling packages
lerna(info)    Prepublishing packages
lerna(verbose) NpmUtilities.runScriptInDir   ("prepublish", [], "./packages/tux-cli")
lerna(verbose) NpmUtilities.execInDir        ("run prepublish", [], "./packages/tux-cli")
lerna(verbose) NpmUtilities.runScriptInDir   ("prepublish", [], "./packages/tux")
lerna(verbose) NpmUtilities.execInDir        ("run prepublish", [], "./packages/tux")
lerna(error)   NpmUtilities.execInDir        ("run prepublish", [], "./packages/tux-cli")
    Error: Command failed: npm run prepublish 
    module.js:472
        throw err;
        ^
    
    Error: Cannot find module 'yargs'
        at Function.Module._resolveFilename (module.js:470:15)
        at Function.Module._load (module.js:418:25)
        at Module.require (module.js:498:17)
        at require (internal/module.js:20:19)
        at Object.<anonymous> (/Users/benediktvaldez/code/tux/tasks/build-package.js:7:14)
        at Module._compile (module.js:571:32)
        at Object.Module._extensions..js (module.js:580:10)
        at Module.load (module.js:488:32)
        at tryModuleLoad (module.js:447:12)
        at Function.Module._load (module.js:439:3)
    
    npm ERR! Darwin 16.4.0
    npm ERR! argv "/usr/local/Cellar/node/7.8.0/bin/node" "/usr/local/bin/npm" "run" "prepublish"
    npm ERR! node v7.8.0
    npm ERR! npm  v4.2.0
    npm ERR! code ELIFECYCLE
    npm ERR! errno 1
    npm ERR! [email protected] prepublish: `TARGET=commonjs NODE_ENV=production ../../tasks/build-package.js`
    npm ERR! Exit status 1
    npm ERR! 
    npm ERR! Failed at the [email protected] prepublish script 'TARGET=commonjs NODE_ENV=production ../../tasks/build-package.js'.
    npm ERR! Make sure you have the latest version of node.js and npm installed.
    npm ERR! If you do, this is most likely a problem with the tux-cli package,
    npm ERR! not with npm itself.
    npm ERR! Tell the author that this fails on your system:
    npm ERR!     TARGET=commonjs NODE_ENV=production ../../tasks/build-package.js
    npm ERR! You can get information on how to open an issue for this project with:
    npm ERR!     npm bugs tux-cli
    npm ERR! Or if that isn't available, you can get their info via:
    npm ERR!     npm owner ls tux-cli
    npm ERR! There is likely additional logging output above.
    
    npm ERR! Please include the following file with any support request:
    npm ERR!     /Users/benediktvaldez/.npm/_logs/2017-04-14T16_50_15_559Z-debug.log
    
        at ChildProcess.exithandler (child_process.js:205:12)
        at emitTwo (events.js:106:13)
        at ChildProcess.emit (events.js:194:7)
        at maybeClose (internal/child_process.js:899:16)
        at Socket.<anonymous> (internal/child_process.js:342:11)
        at emitOne (events.js:96:13)
        at Socket.emit (events.js:191:7)
        at Pipe._handle.close [as _onclose] (net.js:509:12)
lerna(error)   
> [email protected] prepublish /Users/benediktvaldez/code/tux/packages/tux-cli
> TARGET=commonjs NODE_ENV=production ../../tasks/build-package.js


lerna(error)   NpmUtilities.runScriptInDir   ("prepublish", [], "./packages/tux-cli")
lerna(error)   
> [email protected] prepublish /Users/benediktvaldez/code/tux/packages/tux-cli
> TARGET=commonjs NODE_ENV=production ../../tasks/build-package.js


lerna(error)   Errored while running BootstrapCommand.execute

Sidebar Tweaks

  • Remove 20 px padding where page scroll bar was.
  • Fixed header or always visible "Update" button.
  • Fix shadow on sidebar.

[RFC] Middleware based design

A render pipeline would allow different functionality to be plugged in. With special logic for client vs server.

A middleware may:

  • Wrap react element (e.g. to set up react context, layout).
  • Wrap render? (e.g. to detect rendered styles like glamor).
  • Pass props/context to (meta tags, store, styles, data for hydrating).
import tux, { startClient } from 'tux'
tux.use(redux())
tux.use(helmet())
tux.use(glamor())
tux.use(router(routes))
startClient(tux)

Examples of middlewares:

  • Data API
  • Style renderer
  • Code split optimiser
  • Router
  • Redux
  • Helmet
  • Admin
  • Scroll history

More code examples:

export const redux = (reducers) => () => ({
  async element(next, context) => {
    context.store = createStore(reducers, context.data.redux)
    context.dispatch = context.store.dispatch
    const element = await next()

    return (
      <Provider store={context.store}>
        {element}
      </Provider>
    )
  }

  onServerRender(render, context) => {
    render()
    context.data.redux = context.store.getState()
  }
})

export const helmet = () => ({
  onServerRender(render, context) => {
    render()
    context.htmlProps.helmet = Helmet.rewind()
  }
})

[RFC] Custom editors

  • Start Date: 2017-02-28

Summary

Use custom components to edit model fields.

Motivation

Tux provides good default editors based on the data type. Developers can
replace the default ones or pick a specific editor component for a field in a model.

Detailed design

Tux should export a function to register a custom editor. Default editors are provided by Tux, but all of them replaceable with custom ones.
Each editor has a React component to that renders the editor and settings that get passed to the component as props along with the model itself.
Editors can be applied to a data type, model and/or a field. If only fieldId is supplied it will be applied to all fields with that ID across all models, but if modelId is supplied as well, it's only for that one field.

import { registerEditor } from 'tux'
import { MyCustomMarkdownEditor } from './components'

// Editor component for a data type globally
registerEditor({
  dataType: 'boolean',
  component: ToggleField,
})

// Editor component for email across all models
registerEditor({
  fieldId: 'email',
  component: TextField,
})

// Editor component for one field in one model
registerEditor({
  modelId: 'article'
  fieldId: 'description',
  component: MyCustomMarkdownEditor,
  settings: {
    helpText: 'Edit your content with style',
  },
})

The editor component gets the field as props.

interface Props {
  field: {
    id: string
    value: string
    label: string
    onChange: () => void
  },
  helpText?: string, // Just a normal prop passed in as settings
}

class MyCustomMarkdownEditor extends Component<Props, any> {
  render() {
    const { label, value, onChange } = this.props.field
    return (
      <TextField label={label} value={value} onChange={onChange} />
    )
  }
}

Alternatives

Contentful already offers this but they use iframes, we get a much better UX using React components. It's interesting to check out their UI Extensions for example usage of editor components.

Unresolved questions

  • Should editors have full access to the adapter?
  • Should they have only get the field or the whole model?
  • Should you be able to combine fieldId, modelId and dataType as you want or be more restrictive, like only a specfic field or a data type?

Create E2E testing utilities for addons

It should be simple to create a folder with .neutrinorc.js and app.js files which are built and run in node and the browser.

It should be possible to assert the state of the dom before and after hydration as well as assert things inside rendering. E.g. a set of flags that should be set during a test run. If any part fails, some of the flags wouldn't be set so the test fails with a "friendly message".

It should be possible to test dev and prod setup.

Here are some assertions for different addons.

Tux
- assert babel es6 and jsx
- assert extract css
- assert error overlay?
- assert server render
- assert client render

React router
- assert server render route for url
- assert client render route for url

Styled components
- assert server render of styles
- assert client render of styles
- assert reuse of styles, same ids

Async bootloader
- assert async callback on server and client

Async jobs
- assert ssr of async job
- assert hydration in browser

Helmet
- assert ssr of meta tags

Better support for monorepos in server bundle externals

We're using nodeExternals (webpack-node-externals) to externalize node_modules during server build. This is necessary because a lot of node modules (like mongoose) do fancy dynamic imports which are incompatible with webpack.

However, nodeExternals by default only works for standard repos, by scanning a single node_modules folder for packages to externalize. Monorepos often store packages in another folder.

Another issue with monorepos is when you want webpack to build your own package dependencies, you don't want those to be externalized.

I don't know a good way to make this "just work", but we can at least make it configurable in .neutrinorc.js:

module.exports = {
  use: [
    ['tux/neutrino', {
      ssr: {
        nodeExternals: [
          { modulesDir: 'node_modules' },
          { modulesDir: '../../node_modules', whitelist: [/my-library/] },
        ],
      },
    ],
  ],
}

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.