-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
30 changed files
with
555 additions
and
241 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
title: enact-dev | ||
--- | ||
|
||
The enact-dev package includes the following documentation: | ||
|
||
* [Installation](./installation.md) | ||
* [Starting a New App](./starting-a-new-app.md) | ||
* [Loading an Existing App](./loading-existing-app.md) | ||
* [Insomorphic Support](./isomorphic-support.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
--- | ||
title: Installing enact-dev | ||
--- | ||
## Requirements | ||
|
||
Node 4.0 or later. Node 6.x/7.x is significantly faster on some machines and is highly recommended. | ||
|
||
## Installation via NPM | ||
|
||
All that's needed to install enact-dev is to use npm to install it globally. For Linux `sudo` may be required. | ||
|
||
``` | ||
npm install -g enyojs/enact-dev | ||
``` | ||
|
||
This preceding command will install the latest stable version. You can also use tagged versions (for example `enyojs/enact-dev#0.3.0`) or the potentially-unstable development branch (`enyojs/enact-dev#develop`). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
--- | ||
title: Isomorphic Support | ||
--- | ||
Isomorphic code layout is a special feature which builds projects in a JavaScript layout that can be potentially processed by any environment, such as [NodeJS](https://nodejs.org) or the browser. One main benefit is that this code can be evaluated at build-time and prerendered into the HTML document ahead of time. | ||
|
||
## What is "Prerendering"? | ||
Prerendering, with regards to Enact apps, means that we render out the initial state at build time. The app's initial state is rendered via React into an HTML string and placed into the **index.html** file. | ||
|
||
## Why Prerender? | ||
Having the initial app state as HTML allows the app to be visible as soon as the HTML is rendered. We don't have to wait for the JavaScript to be fetched, parsed, and executed to see the general app layout. Furthermore, once the JavaScript does load, the underlying React core will recognize the HTML and just add event listeners; no extra rendering needs to be done. The end result is the appearance of significantly faster app load time. | ||
|
||
## How to Create an Isomorphic Build | ||
Within your **package.json** file, add an `isomorphic` property to the `enact` object: | ||
``` | ||
{ | ||
... | ||
"enact": { | ||
... | ||
"isomorphic":true | ||
} | ||
... | ||
} | ||
``` | ||
If the value is a string filepath instead, it will use that file as the main app entrypoint instead of the default. Whatever the entrypoint, ensure it exports the `ReactElement` in non-browser environments. An example **index.js** entrypoint can be see [here](https://github.com/enyojs/enact-dev/blob/master/template/src/index.js) and is the default included in the Enact app template. | ||
|
||
Then, you can choose to build with isomorphic code layout by adding the `--isomorphic` flag to the pack command: | ||
``` | ||
npm pack -- --isomorphic | ||
npm pack-p -- --isomorphic | ||
``` | ||
|
||
### When to Build Isomorphically | ||
By default, enact-dev will use not use isomorphic code layout, and it should not be considered part of the regular development workflow. It is advisable to only build in isomorphic format when you specifically want to test and ensure prerendering works or to use the app code in non-browser situations. | ||
|
||
### How to Debug When Prerendering Fails | ||
If prerendering fails, there will be a stack trace printed to the console and the build will continue without prerendering. It's useful to build in development mode so that you can use the stack trace to determine where in the code the issue lies without any minification getting in the way. | ||
|
||
Generally, when a prerender fails, it's due to `window` or `document` being used during initial state creation (prior to mounting). Leave all access of those globals until after mount or wrap in an if-statement to check global variable existence. | ||
|
||
> **Important Note**: | ||
> Prerendering requires an app to be coded such that it does not require access to `window` or `document` to create its initial state. The act of prerendering take place in a Node-based environment, so neither `window` nor `document` are available. | ||
> If your app must use `document` or `window` in creation of its initial state, be sure to wrap those in if-statements to avoid prerender failure. For example: | ||
> ``` | ||
> if(typeof window !== 'undefined') { | ||
> // able to access window | ||
> } | ||
>``` | ||
## How It Works | ||
With an isomorphic build, the app is built in a special pseudo-library layout, in a universal module definition ([UMD](https://github.com/umdjs/umd)) format. In a Node environment, the top-level export is the `ReactElement` export of the 'isomorphic' file. In a browser environment, the app executes normally. | ||
|
||
During the build process, a custom webpack plugin, `PrerenderPlugin`, will access the build within its Node environment and use React's own [`ReactDOMServer`](https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostring) to render the initial state of the app into an HTML string and inject that into the **index.html** file. This is the same API used in server-side rendering. | ||
|
||
When the webpage loads up in a browser environment, the built JavaScript is loaded normally (and is expected to render itself into the HTML), except React will detect the DOM tree and will simply attach event listeners and go through the React lifecycle methods. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- | ||
title: Loading an Existing App | ||
--- | ||
## Acquire the Source | ||
|
||
Download the app's source code, usually, from a git repository. Make sure you have correct SSH access rights for the repo. For example: | ||
|
||
``` | ||
git clone [email protected]:user/myapp.git | ||
``` | ||
|
||
## Install the Dependencies | ||
|
||
Enact apps are just like any other NPM package. Navigate to the app's root directory (the base directory with the **package.json**). From there, you can install the dependencies the standard way: | ||
|
||
``` | ||
npm install | ||
``` | ||
|
||
## Available NPM Tasks | ||
NPM tasks vary by package and are defined within a `scripts` object in the **package.json** file. If the app was created via enact-dev, then it should support the following: | ||
|
||
* `npm run serve` - Packages and hosts the app on a local http server using [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html). Supports hot module replacement and inline updates as the source code changes. | ||
* `npm run pack` - Packages the app into **./dist** in development mode (unminified code, with any applicable development code). | ||
* `npm run pack-p` - Packages the app into **./dist** in production mode (minified code, with development code dropped). | ||
* `npm run watch` - Packages in development mode and sets up a watcher that will rebuild the app whenever the source code changes. | ||
* `npm run test` - Builds and executes any test spec files within the project. | ||
* `npm run lint `- Lints the project's JavaScript files according to the Enact ESLint configuration settings. | ||
* `npm run clean` - Deletes the **./dist** directory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
--- | ||
title: Starting a New App | ||
--- | ||
## Generating the Base App Template | ||
With the enact-dev tool installed, you can quickly create a new project with the following command: | ||
|
||
``` | ||
enact init [directory] | ||
``` | ||
Where `[directory]` is the directory for the new project (or the working directory if omitted). This will generate a basic Moonstone template, complete with Enact, its libraries, React, and a fully configured **package.json**. | ||
|
||
## Enact Build Settings | ||
The enact-dev tool will check the project's **package.json** looking for an optional `enact` object for a few customization options: | ||
|
||
* `template` _[string]_ - Filepath to an alternate HTML template to use with the [Webpack html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin). | ||
* `isomorphic` _[boolean|string]_ - If `true`, it indicates the default entrypoint is isomorphic-compatible (and can be built via the `--isomorphic` enact-dev flag). If the value is a string, then it will use that value as a filepath to a custom isomorphic-compatible entrypoint. | ||
* `title` _[string]_ - Title text that should be put within the HTML's `<title></title>` tags. Note: if this is a webOS-project, the title, by default, will be auto-detected from the **appinfo.json** content. | ||
* `ri` _[object]_ - Resolution independence options to be forwarded to the [LESS plugin](https://github.com/enyojs/less-plugin-resolution-independence). | ||
* `proxy` _[string]_ - Proxy target during project `serve` to be used within the [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware). | ||
|
||
For example: | ||
```js | ||
{ | ||
... | ||
"enact": { | ||
"isomorphic": true, | ||
"ri": { | ||
"baseSize":24 | ||
} | ||
} | ||
... | ||
} | ||
``` | ||
The `ri` value here (`baseSize=24`) is designed for 1080p TVs and similar resolutions. | ||
|
||
## Available NPM Tasks | ||
Included within the app template are a number of NPM tasks available to build/run the app: | ||
|
||
* `npm run serve` - Packages and hosts the app on a local http server using [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html). Supports hot module replacement and inline updates as the source code changes. | ||
* `npm run pack` - Packages the app into **./dist** in development mode (unminified code, with any applicable development code). | ||
* `npm run pack-p` - Packages the app into **./dist** in production mode (minified code, with development code dropped). | ||
* `npm run watch` - Packages in development mode and sets up a watcher that will rebuild the app whenever the source code changes. | ||
* `npm run test` - Builds and executes any test spec files within the project. | ||
* `npm run lint `- Lints the project's JavaScript files according to the Enact ESLint configuration settings. | ||
* `npm run clean` - Deletes the **./dist** directory | ||
|
||
That's it! Now you have a fully functioning app environment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
var EnactFrameworkRefPlugin = require('./util/EnactFrameworkRefPlugin') | ||
|
||
module.exports = function(config, opts) { | ||
// Add the reference plugin so the app uses the external framework | ||
config.plugins.push(new EnactFrameworkRefPlugin({ | ||
name: 'enact_framework', | ||
libraries: ['@enact', 'react', 'react-dom'], | ||
external: { | ||
path: opts.externals, | ||
inject: opts['externals-inject'] || opts.inject | ||
} | ||
})); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
var | ||
path = require('path'), | ||
glob = require('glob'), | ||
exists = require('path-exists').sync, | ||
snapshotSetup = require('./snapshot'), | ||
helper = require('./util/config-helper'), | ||
EnactFrameworkPlugin = require('./util/EnactFrameworkPlugin'); | ||
|
||
module.exports = function(config, opts) { | ||
// Form list of framework entries; Every @enact/* js file as well as react/react-dom | ||
var entry = glob.sync('@enact/**/*.@(js|jsx|es6)', { | ||
cwd: path.resolve('./node_modules'), | ||
nodir: true, | ||
ignore: [ | ||
'./webpack.config.js', | ||
'./.eslintrc.js', | ||
'./karma.conf.js', | ||
'./build/**/*.*', | ||
'./dist/**/*.*', | ||
'./node_modules/**/*.*', | ||
'**/tests/*.js' | ||
] | ||
}).concat(['react', 'react-dom']); | ||
if(!exists(path.join(process.cwd(), 'node_modules', 'react-dom', 'lib', 'ReactPerf.js'))) { | ||
entry.push('react/lib/ReactPerf'); | ||
} else { | ||
entry.push('react-dom/lib/ReactPerf'); | ||
} | ||
config.entry = {enact:entry}; | ||
|
||
// Use universal module definition to allow usage and name as 'enact_framework' | ||
config.output.library = 'enact_framework'; | ||
config.output.libraryTarget = 'umd'; | ||
|
||
// Append additional options to the ilib-loader to skip './resources' detection/generation | ||
var ilibLoader = helper.getLoaderByName(config, 'ilib'); | ||
if(ilibLoader) { | ||
ilibLoader.loader += '?noSave&noResources'; | ||
} | ||
|
||
// Remove the HTML generation plugin and webOS-meta plugin | ||
var unneeded = ['HtmlWebpackPlugin', 'WebOSMetaPlugin']; | ||
for(var i=0; i<unneeded.length; i++) { | ||
helper.removePlugin(config, unneeded[i]); | ||
} | ||
|
||
// Add the framework plugin to build in an externally accessible manner | ||
config.plugins.push(new EnactFrameworkPlugin()); | ||
|
||
if(opts.snapshot) { | ||
snapshotSetup(config, {framework:true}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
var | ||
path = require('path'), | ||
exists = require('path-exists').sync, | ||
externalsSetup = require('./externals'), | ||
frameworkSetup = require('./framework'), | ||
isomorphicSetup = require('./isomorphic'), | ||
statsSetup = require('./stats'), | ||
unmangledSetup = require('./unmangled'); | ||
|
||
module.exports = { | ||
apply: function(config, opts) { | ||
if(opts.production && !opts['minify']) { | ||
unmangledSetup(config, opts); | ||
} | ||
|
||
if(opts.framework) { | ||
frameworkSetup(config, opts); | ||
} else { | ||
// Backwards compatibility for <15.4.0 React | ||
if(!exists(path.join(process.cwd(), 'node_modules', 'react-dom', 'lib', 'ReactPerf.js'))) { | ||
config.resolve.alias['react-dom/lib/ReactPerf'] = 'react/lib/ReactPerf'; | ||
} | ||
if(opts.isomorphic) { | ||
isomorphicSetup(config, opts); | ||
} | ||
if(opts.externals) { | ||
externalsSetup(config, opts); | ||
} | ||
} | ||
|
||
if(opts.stats) { | ||
statsSetup(config, opts); | ||
} | ||
}, | ||
externals: externalsSetup, | ||
framework: frameworkSetup, | ||
isomorphic: isomorphicSetup, | ||
stats: statsSetup, | ||
unmangled: unmangledSetup | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
var | ||
path = require('path'), | ||
fs = require('fs-extra'), | ||
chalk = require('chalk'), | ||
exists = require('path-exists').sync, | ||
snapshotSetup = require('./snapshot'), | ||
helper = require('./util/config-helper'), | ||
PrerenderPlugin = require('./util/PrerenderPlugin'); | ||
|
||
function readJSON(file) { | ||
try { | ||
return JSON.parse(fs.readFileSync(file, {encoding:'utf8'})); | ||
} catch(e) { | ||
return undefined; | ||
} | ||
} | ||
|
||
module.exports = function(config, opts) { | ||
var meta = readJSON('package.json') || {}; | ||
var enact = meta.enact || {}; | ||
var iso = enact.isomorphic || enact.prerender; | ||
// Only use isomorphic if an isomorphic entrypoint is specified | ||
if(iso) { | ||
var reactDOM = path.join(process.cwd(), 'node_modules', 'react-dom', 'index.js'); | ||
if(!exists(reactDOM)) { | ||
reactDOM = require.resolve('react-dom'); | ||
} | ||
// Prepend react-dom as top level entrypoint so espose-loader will expose | ||
// it to window.ReactDOM to allow runtime rendering of the app. | ||
config.entry.main.unshift(reactDOM); | ||
|
||
// If 'isomorphic' value is a string, use custom entrypoint. | ||
if(typeof iso === 'string') { | ||
config.entry.main[config.entry.main.length-1] = path.resolve(iso); | ||
} | ||
|
||
// Since we're building for isomorphic usage, expose ReactElement | ||
config.output.library = 'App'; | ||
|
||
// Use universal module definition to allow usage in Node and browser environments. | ||
config.output.libraryTarget = 'umd'; | ||
|
||
// Expose the 'react-dom' on a global context for App's rendering | ||
// Currently maps the toolset to window.ReactDOM. | ||
config.module.loaders.push({ | ||
test: reactDOM, | ||
loader: 'expose?ReactDOM' | ||
}); | ||
|
||
// Update HTML webpack plugin to use the isomorphic template and include screentypes | ||
var htmlPlugin = helper.getPluginByName(config, 'HtmlWebpackPlugin'); | ||
if(htmlPlugin) { | ||
htmlPlugin.options.inject = false; | ||
htmlPlugin.options.template = path.join(__dirname, 'util', 'html-template-isomorphic.ejs'); | ||
htmlPlugin.options.screenTypes = enact.screenTypes | ||
|| readJSON('./node_modules/@enact/moonstone/MoonstoneDecorator/screenTypes.json') | ||
|| readJSON('./node_modules/enact/packages/moonstone/MoonstoneDecorator/screenTypes.json'); | ||
} | ||
|
||
// Include plugin to prerender the html into the index.html | ||
config.plugins.push(new PrerenderPlugin()); | ||
|
||
// Apply snapshot specialization options if needed | ||
if(opts.snapshot && !opts.externals) { | ||
snapshotSetup(config, opts); | ||
} | ||
} else { | ||
console.log(chalk.yellow('Isomorphic entrypoint not found in package.json; building normally')); | ||
} | ||
}; |
Oops, something went wrong.