├── .eslintrc.yml
├── .eslintignore
├── packages
├── edge-express
│ ├── .env
│ ├── .babelrc
│ ├── src
│ │ ├── index.js
│ │ ├── addErrorMiddleware.js
│ │ ├── addCoreMiddleware.js
│ │ ├── addFallbackHandler.js
│ │ ├── createExpressServer.js
│ │ └── addSecurityMiddleware.js
│ ├── package.json
│ └── readme.md
├── edge-boilerplate
│ ├── src
│ │ ├── Init.js
│ │ ├── Variables.css
│ │ ├── views
│ │ │ ├── Missing
│ │ │ │ ├── Missing.css
│ │ │ │ └── Missing.js
│ │ │ ├── Counter
│ │ │ │ ├── Counter.css
│ │ │ │ └── Counter.js
│ │ │ ├── Localization
│ │ │ │ ├── Localization.css
│ │ │ │ └── Localization.js
│ │ │ └── Home
│ │ │ │ ├── Home.css
│ │ │ │ └── Home.js
│ │ ├── components
│ │ │ ├── htmlhead
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── favicon-16x16.png
│ │ │ │ ├── favicon-32x32.png
│ │ │ │ ├── mstile-150x150.png
│ │ │ │ ├── apple-touch-icon.png
│ │ │ │ ├── android-chrome-192x192.png
│ │ │ │ ├── android-chrome-512x512.png
│ │ │ │ ├── manifest.webmanifest
│ │ │ │ ├── HtmlHead.js
│ │ │ │ └── safari-pinned-tab.svg
│ │ │ ├── view
│ │ │ │ ├── ErrorPlaceholder.module.css
│ │ │ │ ├── LoadingPlaceholder.js
│ │ │ │ ├── ErrorPlaceholder.js
│ │ │ │ └── ViewWrapper.js
│ │ │ ├── Story.test.js
│ │ │ ├── navigation
│ │ │ │ ├── Navigation.story.js
│ │ │ │ └── Navigation.js
│ │ │ └── __snapshots__
│ │ │ │ └── Story.test.js.snap
│ │ ├── fonts
│ │ │ └── source-sans-pro
│ │ │ │ ├── SourceSansPro-It.otf.woff
│ │ │ │ ├── SourceSansPro-Bold.otf.woff
│ │ │ │ ├── SourceSansPro-It.otf.woff2
│ │ │ │ ├── SourceSansPro-Black.otf.woff
│ │ │ │ ├── SourceSansPro-Black.otf.woff2
│ │ │ │ ├── SourceSansPro-BlackIt.otf.woff
│ │ │ │ ├── SourceSansPro-Bold.otf.woff2
│ │ │ │ ├── SourceSansPro-BoldIt.otf.woff
│ │ │ │ ├── SourceSansPro-BoldIt.otf.woff2
│ │ │ │ ├── SourceSansPro-Light.otf.woff
│ │ │ │ ├── SourceSansPro-Light.otf.woff2
│ │ │ │ ├── SourceSansPro-LightIt.otf.woff
│ │ │ │ ├── SourceSansPro-Regular.otf.woff
│ │ │ │ ├── SourceSansPro-BlackIt.otf.woff2
│ │ │ │ ├── SourceSansPro-LightIt.otf.woff2
│ │ │ │ ├── SourceSansPro-Regular.otf.woff2
│ │ │ │ ├── SourceSansPro-Semibold.otf.woff
│ │ │ │ ├── SourceSansPro-Semibold.otf.woff2
│ │ │ │ ├── SourceSansPro-ExtraLight.otf.woff
│ │ │ │ ├── SourceSansPro-ExtraLight.otf.woff2
│ │ │ │ ├── SourceSansPro-ExtraLightIt.otf.woff
│ │ │ │ ├── SourceSansPro-SemiboldIt.otf.woff
│ │ │ │ ├── SourceSansPro-SemiboldIt.otf.woff2
│ │ │ │ ├── SourceSansPro-ExtraLightIt.otf.woff2
│ │ │ │ └── SourceSansPro.css
│ │ ├── Init.css
│ │ ├── Application.css
│ │ ├── dev.js
│ │ ├── messages
│ │ │ ├── en.json
│ │ │ ├── de.json
│ │ │ ├── es.json
│ │ │ └── fr.json
│ │ ├── Responsive.css
│ │ ├── client
│ │ │ └── index.js
│ │ ├── modules
│ │ │ ├── Env.js
│ │ │ └── Counter.js
│ │ ├── binary.js
│ │ ├── State.js
│ │ ├── server
│ │ │ └── index.js
│ │ └── Application.js
│ ├── .babelrc
│ ├── postcss.config.js
│ ├── jest.config.js
│ ├── .env
│ ├── .env-dev
│ ├── browserslist
│ ├── hooks
│ │ └── webpack.js
│ ├── .edgerc.yml
│ └── package.json
├── edge-webpack
│ ├── .gitignore
│ ├── .babelrc
│ ├── __tests__
│ │ └── project
│ │ │ ├── src
│ │ │ ├── client
│ │ │ │ └── index.js
│ │ │ ├── components
│ │ │ │ └── logo
│ │ │ │ │ ├── Logo.js
│ │ │ │ │ └── logo.svg
│ │ │ └── App.js
│ │ │ ├── project.test.js
│ │ │ └── __snapshots__
│ │ │ └── project.test.js.snap
│ ├── jest.config.js
│ ├── src
│ │ ├── index.test.js
│ │ ├── modules
│ │ │ ├── Environment.js
│ │ │ ├── Static.js
│ │ │ ├── Locales.js
│ │ │ ├── Optimization.js
│ │ │ └── Experience.js
│ │ ├── config.js
│ │ └── index.js
│ ├── readme.md
│ └── package.json
├── edge-useragent
│ ├── .babelrc
│ ├── test
│ │ ├── mocha.opts
│ │ ├── fixtures
│ │ │ └── static.custom.yaml
│ │ ├── satisfies.test.js
│ │ └── parser.qa.js
│ ├── static
│ │ ├── user_agent.before.yaml
│ │ └── user_agent.after.yaml
│ ├── bin
│ │ ├── update.js
│ │ └── testfiles.js
│ ├── credits.md
│ └── package.json
├── edge-builder
│ ├── .babelrc
│ ├── src
│ │ ├── index.js
│ │ ├── plugins
│ │ │ ├── Status.js
│ │ │ ├── ChunkNames.js
│ │ │ └── VerboseProgress.js
│ │ ├── commands
│ │ │ └── build.js
│ │ ├── webpack
│ │ │ └── dev.js
│ │ └── binary.js
│ ├── readme.md
│ └── package.json
├── edge-common
│ ├── .babelrc
│ ├── src
│ │ ├── index.js
│ │ └── logging.js
│ └── package.json
├── edge-postcss
│ ├── .babelrc
│ ├── __tests__
│ │ ├── fixtures
│ │ │ ├── import-a.css
│ │ │ ├── import-b.css
│ │ │ ├── import-c.css
│ │ │ ├── other
│ │ │ │ └── Home.css
│ │ │ ├── formula.png
│ │ │ ├── americano.png
│ │ │ └── font
│ │ │ │ ├── SourceSansPro-Light.otf.woff
│ │ │ │ ├── SourceSansPro-Light.otf.woff2
│ │ │ │ └── SourceSansPro.css
│ │ ├── __snapshots__
│ │ │ ├── merge.js.snap
│ │ │ ├── mediaqueries.js.snap
│ │ │ ├── optimization.js.snap
│ │ │ ├── sass.js.snap
│ │ │ ├── assets.js.snap
│ │ │ ├── color.js.snap
│ │ │ ├── effects.js.snap
│ │ │ ├── fixes.js.snap
│ │ │ ├── layout.js.snap
│ │ │ └── extensions.js.snap
│ │ ├── merge.js
│ │ ├── mediaqueries.js
│ │ ├── optimization.js
│ │ ├── effects.js
│ │ ├── extensions.js
│ │ ├── sass.js
│ │ ├── assets.js
│ │ ├── color.js
│ │ ├── fixes.js
│ │ ├── layout.js
│ │ └── core.js
│ ├── browserslist
│ └── package.json
├── edge-storybook
│ ├── src
│ │ ├── babelrc
│ │ ├── addons.js
│ │ ├── storyshot.js
│ │ ├── webpack.config.js
│ │ └── config.js
│ ├── .babelrc
│ ├── package.json
│ └── readme.md
├── edge-style
│ ├── postcss.config.js
│ ├── src
│ │ ├── Normalize.css
│ │ ├── index.js
│ │ ├── BoxSizing.css
│ │ ├── Reset.css
│ │ ├── Aria.css
│ │ ├── Intl.css
│ │ ├── OpenType.css
│ │ └── Sanitize.css
│ ├── package.json
│ └── readme.md
├── edge-core
│ ├── .babelrc
│ ├── browserslist
│ ├── src
│ │ ├── client
│ │ │ ├── updateState.js
│ │ │ ├── renderApp.js
│ │ │ └── getBrowserLocale.js
│ │ ├── server
│ │ │ ├── prepareResponse.js
│ │ │ ├── getLocaleData.js
│ │ │ ├── renderApplication.js
│ │ │ └── renderPage.js
│ │ ├── common
│ │ │ ├── ApolloClient.test.js
│ │ │ ├── fetchData.js
│ │ │ ├── deepFetch.js
│ │ │ ├── State.test.js
│ │ │ ├── createKernel.js
│ │ │ ├── wrapApplication.js
│ │ │ ├── ApolloClient.js
│ │ │ ├── Intl.js
│ │ │ └── State.js
│ │ ├── client.js
│ │ ├── common.js
│ │ └── server.js
│ ├── readme.md
│ └── package.json
└── jest-preset-edge
│ ├── test.js
│ ├── transform
│ ├── graphql.js
│ ├── css.js
│ ├── babel.js
│ └── file.js
│ ├── package.json
│ ├── jest-preset.js
│ ├── readme.md
│ └── setup.js
├── .stylelintrc.yml
├── .gitignore
├── .editorconfig
├── lerna.json
├── .prettierrc.yml
├── appveyor.yml
├── package.json
├── .travis.yml
└── .gitattributes
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | extends:
2 | - readable
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | packages/edge-useragent/src/*.js
2 |
--------------------------------------------------------------------------------
/packages/edge-express/.env:
--------------------------------------------------------------------------------
1 | SERVER_PORT = 1339
2 |
--------------------------------------------------------------------------------
/.stylelintrc.yml:
--------------------------------------------------------------------------------
1 | extends:
2 | - stylelint-config-readable
3 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/Init.js:
--------------------------------------------------------------------------------
1 | import "./Init.css"
2 |
--------------------------------------------------------------------------------
/packages/edge-webpack/.gitignore:
--------------------------------------------------------------------------------
1 | .cache-loader
2 | dist
3 |
--------------------------------------------------------------------------------
/packages/edge-useragent/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "edge" ]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "edge"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-builder/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "edge"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-common/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "edge"
4 | ]
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/packages/edge-express/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "edge"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-postcss/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "edge"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/import-a.css:
--------------------------------------------------------------------------------
1 | .root {
2 | color: #f00;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/import-b.css:
--------------------------------------------------------------------------------
1 | .section {
2 | color: #00d;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/edge-storybook/src/babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "edge"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-style/postcss.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | module.exports = require("edge-postcss")
3 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/postcss.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | module.exports = require("edge-postcss")
3 |
--------------------------------------------------------------------------------
/packages/edge-core/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [ "edge", { "target": "current" }]
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/import-c.css:
--------------------------------------------------------------------------------
1 | .image {
2 | background: url("./formula.png");
3 | }
4 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/test.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | test("Empty test", () => {
3 | // empty
4 | })
5 |
--------------------------------------------------------------------------------
/packages/edge-useragent/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --reporter spec
2 | --ui bdd
3 | --require should
4 | --require @babel/register
5 |
--------------------------------------------------------------------------------
/packages/edge-webpack/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [ "edge", { "target": "node", "modules": false } ]
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/jest.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | module.exports = {
3 | "preset": "jest-preset-edge"
4 | }
5 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/Variables.css:
--------------------------------------------------------------------------------
1 | $red: #bf2f2f;
2 | $gray-dark: #4e4d4d;
3 | $gray-light: #f7f7f7;
4 | $full-site-padding: 1rem;
5 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/other/Home.css:
--------------------------------------------------------------------------------
1 | .preloader {
2 | background: url("./logo.svg");
3 | border: 1px solid #000;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Missing/Missing.css:
--------------------------------------------------------------------------------
1 | @import "../../Variables.css";
2 |
3 | .root {
4 | padding: 2rem;
5 |
6 | color: $red;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/edge-common/src/index.js:
--------------------------------------------------------------------------------
1 | export { NAME, VERSION, LOGPREFIX, SCHEMA, loadConfig } from "./config"
2 | export { notify, colorize } from "./logging"
3 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/formula.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-postcss/__tests__/fixtures/formula.png
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/americano.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-postcss/__tests__/fixtures/americano.png
--------------------------------------------------------------------------------
/packages/edge-postcss/browserslist:
--------------------------------------------------------------------------------
1 | and_chr >= 50
2 | chrome >= 50
3 | edge >= 12
4 | firefox >= 45
5 | ie >= 10
6 | ios_saf >= 10
7 | safari >= 10
8 | samsung >= 4
9 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Counter/Counter.css:
--------------------------------------------------------------------------------
1 | @import "../../Variables.css";
2 | @import "../../Responsive.css";
3 |
4 | .root {
5 | /* nothing */
6 | }
7 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/components/htmlhead/favicon.ico
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Localization/Localization.css:
--------------------------------------------------------------------------------
1 | @import "../../Variables.css";
2 | @import "../../Responsive.css";
3 |
4 | .root {
5 | /* nothing */
6 | }
7 |
--------------------------------------------------------------------------------
/packages/edge-webpack/__tests__/project/src/client/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { render } from "react-dom"
3 | import App from "../App"
4 |
5 | render()
6 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/.env:
--------------------------------------------------------------------------------
1 | SERVER_PORT = 1339
2 |
3 | ENABLE_CSP = false
4 | ENABLE_NONCE = false
5 |
6 | API_URL = http://localhost:7339
7 | APOLLO_URL = http://localhost:8339
8 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/.env-dev:
--------------------------------------------------------------------------------
1 | SERVER_PORT = 1339
2 |
3 | ENABLE_CSP = false
4 | ENABLE_NONCE = false
5 |
6 | API_URL = http://localhost:7339
7 | APOLLO_URL = http://localhost:8339
8 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/components/htmlhead/favicon-16x16.png
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/components/htmlhead/favicon-32x32.png
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/view/ErrorPlaceholder.module.css:
--------------------------------------------------------------------------------
1 | .log {
2 | margin-top: 20px;
3 | padding: 10px;
4 |
5 | background: #f4f2f4;
6 | font-size: 12px;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/components/htmlhead/mstile-150x150.png
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/components/htmlhead/apple-touch-icon.png
--------------------------------------------------------------------------------
/packages/edge-style/src/Normalize.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This depends on postcss-normalize to select the amount of normalization
3 | * required by the projects browserslist.
4 | */
5 | @import-normalize;
6 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/font/SourceSansPro-Light.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-postcss/__tests__/fixtures/font/SourceSansPro-Light.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/components/htmlhead/android-chrome-192x192.png
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/components/htmlhead/android-chrome-512x512.png
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-It.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-It.otf.woff
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/font/SourceSansPro-Light.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-postcss/__tests__/fixtures/font/SourceSansPro-Light.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Bold.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Bold.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-It.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-It.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Black.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Black.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Black.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Black.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BlackIt.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BlackIt.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Bold.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Bold.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BoldIt.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BoldIt.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BoldIt.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BoldIt.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Light.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Light.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Light.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Light.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-LightIt.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-LightIt.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Regular.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Regular.otf.woff
--------------------------------------------------------------------------------
/packages/edge-style/src/index.js:
--------------------------------------------------------------------------------
1 | import "./Normalize.css"
2 | import "./Reset.css"
3 | import "./Sanitize.css"
4 | import "./BoxSizing.css"
5 | import "./Aria.css"
6 | import "./OpenType.css"
7 | import "./Intl.css"
8 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BlackIt.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-BlackIt.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-LightIt.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-LightIt.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Regular.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Regular.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Semibold.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Semibold.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Semibold.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-Semibold.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLight.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLight.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLight.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLight.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLightIt.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLightIt.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-SemiboldIt.otf.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-SemiboldIt.otf.woff
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-SemiboldIt.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-SemiboldIt.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-webpack/__tests__/project/src/components/logo/Logo.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import logoUrl from "./logo.svg"
3 |
4 | export default function Logo() {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLightIt.otf.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sebastian-software/edge/HEAD/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro-ExtraLightIt.otf.woff2
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/Story.test.js:
--------------------------------------------------------------------------------
1 | import { dirname } from "path"
2 | import initStoryshots from "@storybook/addon-storyshots"
3 |
4 | initStoryshots({
5 | configPath: dirname(require.resolve("edge-storybook"))
6 | })
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | coverage/
3 |
4 | *debug.log
5 | *error.log
6 | .cache
7 | .DS_Store
8 | .vs
9 |
10 | package-lock.json
11 |
12 | packages/*/lib
13 | packages/*/build
14 | packages/*/bin
15 | packages/*/docs
16 |
17 | *.log
18 |
--------------------------------------------------------------------------------
/packages/edge-webpack/__tests__/project/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import Logo from "./components/logo/Logo"
3 |
4 | export default function App() {
5 | return (
6 |
7 |
8 |
9 | )
10 | }
11 |
--------------------------------------------------------------------------------
/packages/edge-core/browserslist:
--------------------------------------------------------------------------------
1 | [production]
2 | safari >= 10
3 | ios >= 10
4 | edge >= 13
5 | chrome >= 50
6 | firefox >= 50
7 | ie >= 11
8 |
9 | [development]
10 | safari >= 10.1
11 | ios >= 10.3
12 | edge >= 15
13 | chrome >= 58
14 | firefox >= 53
15 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/browserslist:
--------------------------------------------------------------------------------
1 | [production]
2 | safari >= 10
3 | ios >= 10
4 | edge >= 13
5 | chrome >= 50
6 | firefox >= 50
7 | ie >= 11
8 |
9 | [development]
10 | safari >= 10.1
11 | ios >= 10.3
12 | edge >= 15
13 | chrome >= 60
14 | firefox >= 56
15 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/navigation/Navigation.story.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { storiesOf } from "@storybook/react"
3 | import Navigation from "./Navigation"
4 |
5 | storiesOf("Navigation", module)
6 | .add("basic demo", () => )
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 | quote_type = double
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/packages/edge-webpack/jest.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 | module.exports = {
3 | preset: "jest-preset-edge",
4 | verbose: true,
5 | testPathIgnorePatterns: [
6 | "/node_modules/",
7 | "/dist/",
8 | "/__tests__/.*/src"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/hooks/webpack.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/unambiguous, import/no-commonjs */
2 | module.exports = function webpack(config, { isServer, isClient, isProduction, isDevelopment }) {
3 | // Extend and manipulate the Webpack configuration here.
4 | return config
5 | }
6 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/merge.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Import Basic 1`] = `
4 | ".root{
5 | color:red
6 | }"
7 | `;
8 |
9 | exports[`Import with Merge 1`] = `
10 | ".section{
11 | color:#00d;
12 | background:#333
13 | }"
14 | `;
15 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixtures/font/SourceSansPro.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | src:
3 | url("./SourceSansPro-Light.otf.woff2") format("woff2"),
4 | url("./SourceSansPro-Light.otf.woff") format("woff");
5 |
6 | font-family: Source Sans Pro;
7 | font-weight: 300;
8 | font-style: normal;
9 | }
10 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/transform/graphql.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 |
3 | const loader = require("graphql-tag/loader")
4 |
5 | module.exports = {
6 | process(source) {
7 | return loader.call({
8 | cacheable() {
9 | // empty
10 | }
11 | }, source)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/edge-core/src/client/updateState.js:
--------------------------------------------------------------------------------
1 | import { createRootReducer } from "../common/State"
2 |
3 | export default function updateState(NextState, kernel) {
4 | console.log("[EDGE]: Updating application state...")
5 | kernel.store.replaceReducer(
6 | createRootReducer(NextState.getReducers(), kernel.router)
7 | )
8 | }
9 |
--------------------------------------------------------------------------------
/packages/edge-useragent/static/user_agent.before.yaml:
--------------------------------------------------------------------------------
1 | user_agent_parsers:
2 | # Rival IQ crawler/bot
3 | - regex: '(Rival IQ, rivaliq.com)'
4 | family_replacement: 'Rival IQ'
5 |
6 | device_parsers:
7 | # Rival IQ crawler/bot
8 | - regex: '(Rival IQ, rivaliq.com)'
9 | device_replacement: 'Spider'
10 |
11 | os_parsers:
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.5.1",
3 | "packages": ["packages/*"],
4 | "version": "independent",
5 | "npmClient": "yarn",
6 | "useWorkspaces": true,
7 | "changelog": {
8 | "labels": {
9 | "enhancement": ":rocket: Enhancement",
10 | "bug": ":bug: Bug Fix"
11 | },
12 | "cacheDir": ".cache/changelog"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Home/Home.css:
--------------------------------------------------------------------------------
1 | @import "../../Variables.css";
2 | @import "../../Responsive.css";
3 |
4 | .preloader {
5 | width: calc(width("./logo.svg") / 2);
6 | height: calc(width("./logo.svg") / 2);
7 |
8 | background: url("./logo.svg");
9 | border: 1px solid #000;
10 | }
11 |
12 | .intro {
13 | font-size: 20px;
14 | }
15 |
--------------------------------------------------------------------------------
/packages/edge-storybook/src/addons.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
2 |
3 | import "@storybook/addon-actions/register"
4 | import "@storybook/addon-links/register"
5 | import "@storybook/addon-viewport/register"
6 | import "@storybook/addon-jest/register"
7 | import "@storybook/addon-storysource/register"
8 |
--------------------------------------------------------------------------------
/packages/edge-core/src/server/prepareResponse.js:
--------------------------------------------------------------------------------
1 | import { parse } from "edge-useragent"
2 |
3 | import getLocaleData from "./getLocaleData"
4 |
5 | export default function prepareResponse(request) {
6 | const intl = getLocaleData(request)
7 | const browser = parse(request.headers["user-agent"])
8 |
9 | return {
10 | intl,
11 | browser
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/edge-builder/src/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | cleanClient,
3 | cleanServer,
4 | buildClient,
5 | buildServer
6 | } from "./commands/build"
7 | import { connectWithWebpack, createMiddleware } from "./webpack/dev"
8 |
9 | export {
10 | cleanClient,
11 | cleanServer,
12 | buildClient,
13 | buildServer,
14 | connectWithWebpack,
15 | createMiddleware
16 | }
17 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/ApolloClient.test.js:
--------------------------------------------------------------------------------
1 | import { createApolloClient } from "./ApolloClient"
2 |
3 | test("Create Apollo Client - No Data", () => {
4 | expect(createApolloClient()).toBeDefined()
5 | })
6 |
7 | test("Create Apollo Client - With Initial Data and URL", () => {
8 | expect(createApolloClient({ uri: "http://my.apollo.uri" })).toBeDefined()
9 | })
10 |
--------------------------------------------------------------------------------
/packages/edge-useragent/static/user_agent.after.yaml:
--------------------------------------------------------------------------------
1 | user_agent_parsers:
2 | # command line tools
3 | - regex: '(Wget)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)'
4 |
5 | - regex: '(curl)/(\d+)\.(\d+)\.(\d+)'
6 | family_replacement: 'cURL'
7 |
8 | os_parsers:
9 | # See #33 for matching the iOS AFHTTPClient
10 | - regex: '(iOS) (\d+)\.(\d+)(?:\.(\d+))?'
11 |
12 | device_parsers:
--------------------------------------------------------------------------------
/packages/edge-webpack/src/index.test.js:
--------------------------------------------------------------------------------
1 | import { core, full } from "./index"
2 | import webpack from "webpack"
3 |
4 | test("Webpack parses core config", () => {
5 | const compiler = webpack(core())
6 | expect(compiler).toBeDefined()
7 | })
8 |
9 | test("Webpack parses full config", () => {
10 | const compiler = webpack(full())
11 | expect(compiler).toBeDefined()
12 | })
13 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/view/LoadingPlaceholder.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { FormattedMessage } from "react-intl"
3 |
4 | export default function LoadingPlaceholder() {
5 | return (
6 | <>
7 |
8 |
9 | >
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/packages/edge-core/src/client/renderApp.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { hydrate } from "react-dom"
3 |
4 | import wrapApplication from "../common/wrapApplication"
5 |
6 | export default function renderApp(Application, kernel) {
7 | console.log("[EDGE]: Rendering application...")
8 | hydrate(wrapApplication(, kernel), document.getElementById("root"))
9 | }
10 |
--------------------------------------------------------------------------------
/packages/edge-express/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as addCoreMiddleware } from "./addCoreMiddleware"
2 | export { default as addErrorMiddleware } from "./addErrorMiddleware"
3 | export { default as addFallbackHandler } from "./addFallbackHandler"
4 | export { default as addSecurityMiddleware } from "./addSecurityMiddleware"
5 | export { default as createExpressServer } from "./createExpressServer"
6 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/mediaqueries.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Custom Media 1`] = `
4 | "@media (max-width:30em){
5 | body{
6 | font-size:12px
7 | }
8 | }"
9 | `;
10 |
11 | exports[`Media Query Min/Max 1`] = `
12 | "@media screen and (min-width:500px) and (max-width:1200px){
13 | .elem{
14 | display:block
15 | }
16 | }"
17 | `;
18 |
--------------------------------------------------------------------------------
/packages/edge-style/src/BoxSizing.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-max-type, selector-max-universal */
2 |
3 | /**
4 | * Add box sizing inheritence in all browsers (opinionated).
5 | */
6 |
7 | *,
8 | ::before,
9 | ::after {
10 | box-sizing: inherit;
11 | }
12 |
13 | /**
14 | * Add border box sizing in all browsers (opinionated).
15 | */
16 |
17 | html {
18 | box-sizing: border-box;
19 | }
20 |
--------------------------------------------------------------------------------
/packages/edge-webpack/src/modules/Environment.js:
--------------------------------------------------------------------------------
1 | import { getEnvironment } from "universal-dotenv"
2 | import webpack from "webpack"
3 |
4 | import { IS_PRODUCTION, BUILD_TARGET } from "../config"
5 |
6 | export default {
7 | mode: IS_PRODUCTION ? "production" : "development",
8 | name: BUILD_TARGET,
9 |
10 | plugins: [
11 | new webpack.DefinePlugin(getEnvironment().webpack)
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/packages/edge-webpack/readme.md:
--------------------------------------------------------------------------------
1 | # Common Webpack Utility Belt
2 |
3 | ## Features
4 |
5 | - Support for React, GraphQL, CSS Modules, ...
6 | - Tweaked for nice user experience.
7 | - Configuration via environment variables using [Universal Dotenv](https://www.npmjs.com/package/universal-dotenv).
8 | - Enabled for using multi threading and advanced caching.
9 | - Able to generate static HTML with SRI support.
10 |
--------------------------------------------------------------------------------
/packages/edge-useragent/test/fixtures/static.custom.yaml:
--------------------------------------------------------------------------------
1 | test_cases:
2 |
3 | - user_agent_string: 'curl/7.12.1 (i686-redhat-linux-gnu) libcurl/7.12.1 OpenSSL/0.9.7a zlib/1.2.1.2 libidn/0.5.6'
4 | family: 'cURL'
5 | major: '7'
6 | minor: '12'
7 | patch: '1'
8 |
9 | - user_agent_string: 'Wget/1.10.1 (Red Hat modified)'
10 | family: 'Wget'
11 | major: '1'
12 | minor: '10'
13 | patch: '1'
14 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Missing/Missing.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types"
2 | import React from "react"
3 |
4 | import Styles from "./Missing.css"
5 |
6 | function Missing() {
7 | return (
8 |
9 |
Sorry, that page was not found.
10 |
11 | )
12 | }
13 |
14 | Missing.propTypes = {
15 | intl: PropTypes.object
16 | }
17 |
18 | export default Missing
19 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/transform/css.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return "module.exports = {};"
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return "cssTransform"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/Init.css:
--------------------------------------------------------------------------------
1 | @import "./Variables.css";
2 | @import "./fonts/source-sans-pro/SourceSansPro.css";
3 |
4 | /* stylelint-disable selector-max-type, selector-max-universal */
5 |
6 | /*
7 | apply a natural box layout model to all elements, but allowing
8 | components to change
9 | */
10 |
11 | html {
12 | font-family: Source Sans Pro, sans-serif;
13 | }
14 |
15 | body {
16 | background: $gray-light;
17 | }
18 |
--------------------------------------------------------------------------------
/packages/edge-useragent/bin/update.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Update our definition file.
3 | */
4 | import { update } from "../src/update"
5 | update((err, data) => {
6 | if (err) {
7 | console.error("Update unsuccessfull due to reasons")
8 | console.log(err.message)
9 | console.log(err.stack)
10 |
11 | return
12 | }
13 | console.log(
14 | "Successfully fetched and generated new parsers from the internets."
15 | )
16 | })
17 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/transform/babel.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 |
3 | // Import .env files to make it possible to access environment variables inside tests.
4 | require("universal-dotenv")
5 |
6 | // Babel transformation but with the possibility to add test-specific plugins/presets.
7 | const babelJest = require("babel-jest")
8 |
9 | module.exports = babelJest.createTransformer({
10 | // any specific babel settings
11 | })
12 |
--------------------------------------------------------------------------------
/packages/edge-storybook/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "development": {
4 | "presets": [
5 | [
6 | "edge",
7 | {
8 | "modules": "cjs",
9 | "env": "production"
10 | }
11 | ]
12 | ]
13 | },
14 | "test": {
15 | "presets": [
16 | [
17 | "edge",
18 | {
19 | "target": "test"
20 | }
21 | ]
22 | ]
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/fetchData.js:
--------------------------------------------------------------------------------
1 | import deepFetch from "./deepFetch"
2 |
3 | export default async function fetchData(App) {
4 | // Asynchronous magic... loading required application data
5 | // Supports parallel loading of either Apollo-style (aka fetchData())
6 | const start = new Date()
7 | console.log("[EDGE] Fetching data...")
8 | const result = await deepFetch(App)
9 | console.log(`[EDGE] Done in ${new Date() - start}ms`)
10 |
11 | return result
12 | }
13 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/merge.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // ================== MERGING =========================
5 | // ====================================================
6 |
7 | test("Import Basic", () =>
8 | compile("@import './fixtures/import-a.css';")
9 | )
10 |
11 | test("Import with Merge", () =>
12 | compile("@import './fixtures/import-b.css'; .section { background: #333; }")
13 | )
14 |
--------------------------------------------------------------------------------
/packages/edge-style/src/Reset.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-max-type */
2 |
3 | /*
4 | * Reset margins and paddings on all block level elements
5 | */
6 |
7 | html,
8 | body,
9 | p,
10 | ol,
11 | ul,
12 | li,
13 | dl,
14 | dt,
15 | dd,
16 | blockquote,
17 | figure,
18 | fieldset,
19 | legend,
20 | textarea,
21 | pre,
22 | iframe,
23 | hr,
24 | h1,
25 | h2,
26 | h3,
27 | h4,
28 | h5,
29 | h6,
30 | button,
31 | input,
32 | select {
33 | padding: 0;
34 | margin: 0;
35 | }
36 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/manifest.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Edge",
3 | "icons": [
4 | {
5 | "src": "/android-chrome-192x192.png",
6 | "sizes": "192x192",
7 | "type": "image/png"
8 | },
9 | {
10 | "src": "/android-chrome-512x512.png",
11 | "sizes": "512x512",
12 | "type": "image/png"
13 | }
14 | ],
15 | "theme_color": "#ffffff",
16 | "background_color": "#ffffff",
17 | "display": "standalone"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/edge-storybook/src/storyshot.js:
--------------------------------------------------------------------------------
1 | import initStoryshots, {
2 | multiSnapshotWithOptions
3 | } from "@storybook/addon-storyshots"
4 |
5 | initStoryshots({
6 | // Delegate to centralized config
7 | configPath: __dirname,
8 |
9 | // Storing seperate snapshots for each individual story
10 | test: multiSnapshotWithOptions({}),
11 |
12 | // Ignore all containers, only snapshot pure components
13 | // without any app logic or data fetching
14 | storyKindRegex: /^((?!container).)*$/i
15 | })
16 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/navigation/Navigation.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Link } from "@reach/router"
3 |
4 | export default function Navigation() {
5 | return (
6 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Home/Home.js:
--------------------------------------------------------------------------------
1 | import Helmet from "react-helmet"
2 | import React from "react"
3 |
4 | import Styles from "./Home.css"
5 |
6 | export default function Home() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | Produced with ❤ by Sebastian Software
14 |
15 |
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/packages/edge-webpack/__tests__/project/src/components/logo/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/edge-webpack/src/modules/Static.js:
--------------------------------------------------------------------------------
1 | import HtmlWebpackPlugin from "html-webpack-plugin"
2 | import SriPlugin from "webpack-subresource-integrity"
3 |
4 | import { IS_PRODUCTION } from "../config"
5 |
6 | export default {
7 | plugins: [
8 | IS_PRODUCTION ?
9 | new SriPlugin({
10 | hashFuncNames: [ "sha256", "sha512" ],
11 | enabled: IS_PRODUCTION
12 | }) :
13 | null,
14 |
15 | new HtmlWebpackPlugin({
16 | inject: true,
17 | title: process.env.APP_TITLE || null
18 | })
19 | ].filter(Boolean)
20 | }
21 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/.edgerc.yml:
--------------------------------------------------------------------------------
1 | entry:
2 | serverMain: src/server/index.js
3 | clientMain: src/client/index.js
4 | serverVendor: src/server/vendor.js
5 | clientVendor: src/client/vendor.js
6 |
7 | build:
8 | enableSourceMaps: true
9 | bundleCompression: uglify
10 | useCacheLoader: true
11 | babelEnvPrefix: edge
12 |
13 | locale:
14 | default: de-DE
15 | supported: [ de-DE, de-AT, de-CH, fr-CH, en-US ]
16 |
17 | output:
18 | server: build/server
19 | client: build/client
20 | public: /static/
21 |
22 | hook:
23 | webpack: hooks/webpack.js
24 |
--------------------------------------------------------------------------------
/packages/edge-core/src/client.js:
--------------------------------------------------------------------------------
1 | // This file is just for exporting infrastructure to applications built upon this.
2 |
3 | // Polyfill for fetch() API
4 | // https://github.com/developit/unfetch
5 | import "unfetch/polyfill"
6 |
7 | // Polyfill for RequestAnimationFrame which is required since React v16
8 | import "raf/polyfill"
9 |
10 | export * from "./common"
11 |
12 | export { default as getBrowserLocale } from "./client/getBrowserLocale"
13 | export { default as renderApp } from "./client/renderApp"
14 | export { default as updateState } from "./client/updateState"
15 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/optimization.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`CSS-O (Optimizer) 1`] = `
4 | ".elem{
5 | color:red
6 | }"
7 | `;
8 |
9 | exports[`Calc Keep 1`] = `
10 | ".elem{
11 | width:calc(100px + 2%)
12 | }"
13 | `;
14 |
15 | exports[`Calc Trivial 1`] = `
16 | ".elem{
17 | width:310px
18 | }"
19 | `;
20 |
21 | exports[`Calc Variable 1`] = `
22 | ".elem{
23 | width:210px
24 | }"
25 | `;
26 |
27 | exports[`zIndex 1`] = `
28 | ".first{
29 | z-index:1
30 | }
31 |
32 | .second{
33 | z-index:2
34 | }"
35 | `;
36 |
--------------------------------------------------------------------------------
/packages/edge-useragent/test/satisfies.test.js:
--------------------------------------------------------------------------------
1 | describe("useragent/satisfies", () => {
2 | const useragent = require("../src"),
3 | ua =
4 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.24 Safari/535.2"
5 |
6 | describe("#satisfies", () => {
7 | it("should satisfy that range selector", () => {
8 | const agent = useragent.parse(ua)
9 |
10 | agent.satisfies("15.x || >=19.5.0 || 25.0.0 - 17.2.3").should.be_true
11 | agent.satisfies(">16.12.0").should.be_false
12 | })
13 | })
14 | })
15 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/mediaqueries.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // =============== MEDIA QUERIES ======================
5 | // ====================================================
6 |
7 | test("Media Query Min/Max", () =>
8 | compile("@media screen and (width >= 500px) and (width <= 1200px) { .elem { display: block; } }")
9 | )
10 |
11 | test("Custom Media", () =>
12 | compile(`
13 | @custom-media --small-viewport (max-width: 30em);
14 | @media (--small-viewport) {
15 | body { font-size: 12px; }
16 | }
17 | `)
18 | )
19 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/Application.css:
--------------------------------------------------------------------------------
1 | @import "./Variables.css";
2 |
3 | .root {
4 | &::after {
5 | content: "";
6 |
7 | position: absolute;
8 | top: 0;
9 | bottom: 0;
10 | left: 0;
11 | right: 0;
12 | z-index: 1000;
13 |
14 | background: rgba($gray-dark, 0.5);
15 | transition: opacity ease-out 200ms, transform linear 0ms 200ms;
16 | will-change: transform, opacity;
17 | }
18 | }
19 |
20 | .alive {
21 | &::after {
22 | opacity: 0;
23 | transform: scale(0);
24 | }
25 | }
26 |
27 | .content {
28 | min-height: 20rem;
29 |
30 | background: $gray-light;
31 | }
32 |
--------------------------------------------------------------------------------
/packages/edge-express/src/addErrorMiddleware.js:
--------------------------------------------------------------------------------
1 | import PrettyError from "pretty-error"
2 |
3 | const pretty = new PrettyError()
4 |
5 | // this will skip events.js and http.js and similar core node files
6 | pretty.skipNodeFiles()
7 |
8 | // this will skip all the trace lines about express` core and sub-modules
9 | pretty.skipPackage("express")
10 |
11 | export default function addErrorMiddleware(server) {
12 | // and use it for our app's error handler:
13 | server.use((error, request, response, next) => {
14 | // eslint-disable-line max-params
15 | console.log(pretty.render(error))
16 | next()
17 | })
18 | }
19 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/view/ErrorPlaceholder.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types"
2 | import React from "react"
3 | import { FormattedMessage } from "react-intl"
4 |
5 | import Styles from "./ErrorPlaceholder.module.css"
6 |
7 | export default function ErrorPlaceholder({ error }) {
8 | return (
9 | <>
10 |
11 |
12 |
13 | {error.message}
14 |
15 | >
16 | )
17 | }
18 |
19 | Error.propTypes = {
20 | error: PropTypes.object
21 | }
22 |
--------------------------------------------------------------------------------
/.prettierrc.yml:
--------------------------------------------------------------------------------
1 | # We generally allow wider code lines, but for auto formatting this
2 | # is quite a good rule to produce readable code.
3 | printWidth: 80
4 |
5 | # Use two spaces for tabs
6 | tabWidth: 2
7 |
8 | # Unify with convention used in JSX, HTML and CSS to use double quotes
9 | singleQuote: false
10 |
11 | # Don't use semicolons where they are not required
12 | semi: false
13 |
14 | # Don't do stupid trailing commas reducing noise ratio.
15 | trailingComma: none
16 |
17 | # More space is better for readability
18 | bracketSpacing: true
19 |
20 | # Put the > of a multi-line JSX element at the end of the last line
21 | jsxBracketSameLine: false
22 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/deepFetch.js:
--------------------------------------------------------------------------------
1 | import reactTreeWalker from "react-tree-walker"
2 |
3 | /* eslint-disable no-shadow */
4 | /* eslint-disable max-params */
5 | export default function deepFetch(rootElement) {
6 | function visitor(element, instance, context) {
7 | if (instance && typeof instance.fetchData === "function") {
8 | const value = instance.fetchData();
9 | if (value instanceof Promise) {
10 | return value.catch((err) => {
11 | console.log("[EDGE] Fetch failed: " + err);
12 | })
13 | }
14 | }
15 |
16 | return true
17 | }
18 |
19 | return reactTreeWalker(rootElement, visitor)
20 | }
21 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/__snapshots__/Story.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Storyshots Navigation basic demo 1`] = `
4 |
32 | `;
33 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/transform/file.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs */
2 |
3 | const path = require("path")
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/en/webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | const assetFilename = JSON.stringify(path.basename(filename))
11 |
12 | if (filename.match(/\.svg$/)) {
13 | return `module.exports = {
14 | __esModule: true,
15 | default: ${assetFilename},
16 | ReactComponent: () => ${assetFilename},
17 | };`
18 | }
19 |
20 | return `module.exports = ${assetFilename};`
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/sass.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Calc Complex 1`] = `
4 | "h1{
5 | width:calc(29.9997% - 22px)
6 | }"
7 | `;
8 |
9 | exports[`Calc Simple 1`] = `
10 | "h1{
11 | width:13%
12 | }"
13 | `;
14 |
15 | exports[`Nested Basic 1`] = `
16 | "body h1{
17 | font-weight:700
18 | }
19 |
20 | body h2{
21 | font-weight:400
22 | }"
23 | `;
24 |
25 | exports[`Nested Parent Selector 1`] = `
26 | "body ul li:first-child{
27 | margin-top:0
28 | }"
29 | `;
30 |
31 | exports[`Sassy Mixins 1`] = `
32 | "h1{
33 | color:#ff4136
34 | }"
35 | `;
36 |
37 | exports[`Sassy Variables 1`] = `
38 | "h1{
39 | background:#ff4136
40 | }"
41 | `;
42 |
--------------------------------------------------------------------------------
/packages/edge-style/src/Aria.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Change the cursor on busy elements (opinionated).
3 | */
4 |
5 | [aria-busy="true"] {
6 | cursor: progress;
7 | }
8 |
9 | /*
10 | * Change the cursor on control elements (opinionated).
11 | */
12 |
13 | [aria-controls] {
14 | cursor: pointer;
15 | }
16 |
17 | /*
18 | * Change the display on visually hidden accessible elements (opinionated).
19 | */
20 |
21 | [aria-hidden="false"][hidden]:not(:focus) {
22 | position: absolute;
23 | display: inherit;
24 | clip: rect(0, 0, 0, 0);
25 | }
26 |
27 | /*
28 | * Change the cursor on disabled, not-editable, or otherwise
29 | * inoperable elements (opinionated).
30 | */
31 |
32 | [aria-disabled] {
33 | cursor: default;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common.js:
--------------------------------------------------------------------------------
1 | export {
2 | createReduxStore,
3 | createRootReducer,
4 | emptyReducer,
5 | emptyMiddleware,
6 | emptyEnhancer,
7 | edgeReducer
8 | } from "./common/State"
9 |
10 | export { createApolloClient } from "./common/ApolloClient"
11 |
12 | export {
13 | requiresIntlPolyfill,
14 | installIntlPolyfill,
15 | requiresReactIntl,
16 | installReactIntl,
17 | getRegion,
18 | getLanguage,
19 | getLocale
20 | } from "./common/Intl"
21 |
22 | export { default as wrapApplication } from "./common/wrapApplication"
23 | export { default as deepFetch } from "./common/deepFetch"
24 | export { default as createKernel } from "./common/createKernel"
25 | export { default as fetchData } from "./common/fetchData"
26 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/view/ViewWrapper.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types"
2 | import React from "react"
3 |
4 | import ErrorPlaceholder from "./ErrorPlaceholder"
5 | import LoadingPlaceholder from "./LoadingPlaceholder"
6 |
7 | export default function ViewWrapper(props) {
8 | const { Component, loading, error, ownProps } = props
9 | if (loading) {
10 | return
11 | }
12 |
13 | if (error) {
14 | return
15 | }
16 |
17 | return Component ? : null
18 | }
19 |
20 | ViewWrapper.propTypes = {
21 | Component: PropTypes.func,
22 | loading: PropTypes.bool,
23 | error: PropTypes.object,
24 | ownProps: PropTypes.object
25 | }
26 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # http://www.appveyor.com/docs/appveyor-yml
2 |
3 | clone_depth: 10
4 |
5 | environment:
6 | matrix:
7 | - nodejs_version: 6
8 | - nodejs_version: 8
9 | - nodejs_version: 10
10 |
11 | platform:
12 | - x86
13 |
14 | matrix:
15 | fast_finish: true
16 |
17 | version: "{build}"
18 | build: off
19 | deploy: off
20 |
21 | install:
22 | - ps: Install-Product node $env:nodejs_version $env:platform
23 | - yarn install --ignore-engines
24 |
25 | test_script:
26 | - yarn test
27 |
28 | notifications:
29 | - provider: Slack
30 | incoming_webhook:
31 | secure: 42qYgf76P/QjYb5QJ18gFFJ67iTlXc1QzEva9BFofwh5KzpF/QJ/pvRark1i3aux6uwL53zdDKTjXfy8Ozpqqk9DhnU5M1oA96bQYWOnmZU=
32 |
33 | cache:
34 | - "%LOCALAPPDATA%\\Yarn"
35 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/optimization.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 |
4 | // ====================================================
5 | // ================ OPTIMIZATION ======================
6 | // ====================================================
7 |
8 | test("Calc Trivial", () =>
9 | compile(".elem { width: calc(300px + 10px); }")
10 | )
11 |
12 | test("Calc Variable", () =>
13 | compile("$margin: 10px; .elem { width: calc(200px + $margin); }")
14 | )
15 |
16 | test("Calc Keep", () =>
17 | compile(".elem { width: calc(100px + 2%); }")
18 | )
19 |
20 | test("zIndex", () =>
21 | compile(".first { z-index: 1000; } .second { z-index: 2000; }")
22 | )
23 |
24 | test("CSS-O (Optimizer)", () =>
25 | compile(".elem { color: #ff0000; }")
26 | )
27 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/dev.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { connectWithWebpack, createMiddleware } from "edge-builder"
4 | import { createExpressServer } from "edge-express"
5 | import { loadConfig } from "edge-common"
6 | import "universal-dotenv"
7 |
8 | async function main() {
9 | const { config } = await loadConfig()
10 | const { middleware, multiCompiler } = createMiddleware(config)
11 |
12 | const server = createExpressServer({
13 | staticConfig: {
14 | public: config.output.public,
15 | path: config.output.client
16 | },
17 | localeConfig: config.locale,
18 | afterSecurity: [],
19 | beforeFallback: [ ...middleware ]
20 | })
21 |
22 | connectWithWebpack(server, multiCompiler)
23 | }
24 |
25 | process.nextTick(main)
26 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/messages/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "generic.error.title": "Error",
3 | "generic.info.title": "Info",
4 |
5 | "lifecycle.error": "The data could not be loaded.",
6 | "lifecycle.loading": "Loading data...",
7 | "lifecycle.skip": "Cannot load the data because a required parameter is missing.",
8 |
9 | "router.notfound": "The page was unfortunately not found!",
10 | "router.codesplit.error": "Unfortunately, an error occurred during the loading process: ",
11 | "router.codesplit.loading": "The requested page is loaded...",
12 |
13 | "locale.value.auto": "Automatic",
14 | "locale.value.de-DE": "German (Germany)",
15 | "locale.value.fr-FR": "Français (France)",
16 | "locale.value.es-ES": "Espagnol (Espagne)",
17 | "locale.value.en-US": "English (USA)"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/effects.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // ================== EFFECTS =========================
5 | // ====================================================
6 |
7 | test("Magic Animations", () =>
8 | compile(".animation { animation-name: magic; }")
9 | )
10 |
11 | test("Will Change Compat", () =>
12 | compile(".scaled { will-change: width; }")
13 | )
14 |
15 | test("Easings", () =>
16 | compile(".snake { transition: all 600ms ease-in-sine; }")
17 | )
18 |
19 | test("Pleeease Filters", () =>
20 | compile(".box { filter: drop-shadow(16px 16px 20px blue); }")
21 | )
22 |
23 | test("Transform Shortcut", () =>
24 | compile(".transform { scale: 2; translate: 10px 20px; }")
25 | )
26 |
27 |
--------------------------------------------------------------------------------
/packages/edge-useragent/credits.md:
--------------------------------------------------------------------------------
1 | The regex library that the useragent parser uses if from; code.google.com/p/ua-parser/
2 | which is released under Apache license:
3 |
4 | # Copyright 2009 Google Inc.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/messages/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "generic.error.title": "Fehler",
3 | "generic.info.title": "Information",
4 |
5 | "lifecycle.error": "Die Daten konnten nicht geladen werden.",
6 | "lifecycle.loading": "Lade Daten...",
7 | "lifecycle.skip": "Kann die Daten nicht laden, da ein benötigter Parameter fehlt.",
8 |
9 | "router.notfound": "Die Seite wurde leider nicht gefunden!",
10 | "router.codesplit.error": "Leider ist während des Ladevorgangs ein Fehler aufgetreten: ",
11 | "router.codesplit.loading": "Die angeforderte Seite wird geladen...",
12 |
13 | "locale.value.auto": "Automatisch",
14 | "locale.value.de-DE": "Deutsch (Deutschland)",
15 | "locale.value.fr-FR": "Français (France)",
16 | "locale.value.es-ES": "Espagnol (Espagne)",
17 | "locale.value.en-US": "English (USA)"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/messages/es.json:
--------------------------------------------------------------------------------
1 | {
2 | "generic.error.title": "Desperfecto",
3 | "generic.info.title": "Inteligencia",
4 |
5 | "lifecycle.error": "No se han podido cargar los datos.",
6 | "lifecycle.loading": "Carga de datos...",
7 | "lifecycle.skip": "No se pueden cargar los datos porque falta un parámetro requerido.",
8 |
9 | "router.notfound": "Desafortunadamente la página no fue encontrada!",
10 | "router.codesplit.error": "Desafortunadamente, un error ocurrió durante el proceso de carga: ",
11 | "router.codesplit.loading": "Se carga la página solicitada...",
12 |
13 | "locale.value.auto": "Automático",
14 | "locale.value.de-DE": "Deutsch (Deutschland)",
15 | "locale.value.fr-FR": "Français (France)",
16 | "locale.value.es-ES": "Espagnol (Espagne)",
17 | "locale.value.en-US": "English (USA)"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/edge-builder/src/plugins/Status.js:
--------------------------------------------------------------------------------
1 | export default class Status
2 | {
3 | constructor({ name, start, done })
4 | {
5 | this.name = name
6 |
7 | this.start = start
8 | this.done = done
9 |
10 | this.watcher = null
11 | this.running = false
12 | }
13 |
14 | checkDone = () => {
15 | this.running = false
16 | this.done()
17 | }
18 |
19 | apply(compiler)
20 | {
21 | compiler.plugin("done", (stats) => {
22 | if (!stats.hasErrors()) {
23 | this.watcher = setTimeout(this.checkDone, 0)
24 | }
25 | })
26 |
27 | compiler.plugin("compile", (stats) => {
28 | if (this.watcher) {
29 | clearTimeout(this.watcher)
30 | }
31 |
32 | if (!this.running) {
33 | this.running = true
34 | this.start()
35 | }
36 | })
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/edge-useragent/bin/testfiles.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import request from "request"
4 | import path from "path"
5 | import fs from "fs"
6 |
7 | const files = {
8 | "pgts.yaml":
9 | "https://raw.githubusercontent.com/ua-parser/uap-core/master/test_resources/pgts_browser_list.yaml",
10 | "firefoxes.yaml":
11 | "https://raw.githubusercontent.com/ua-parser/uap-core/master/test_resources/firefox_user_agent_strings.yaml"
12 | }
13 |
14 | /**
15 | * Update the fixtures
16 | */
17 |
18 | Object.keys(files).forEach(key => {
19 | request(files[key], function response(err, res, data) {
20 | if (err || res.statusCode !== 200) return console.error("failed to update")
21 |
22 | console.log("downloaded", files[key])
23 | fs.writeFileSync(path.join(__dirname, "..", "test", "fixtures", key), data)
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/extensions.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // ================= EXTENSIONS =======================
5 | // ====================================================
6 |
7 | test("Responsive Type", () =>
8 | compile("html { font-size: responsive 12px 21px; font-range: 420px 1280px; }")
9 | )
10 |
11 | test("Clearfix", () =>
12 | compile(".row { clear: fix; }")
13 | )
14 |
15 | test("System UI", () =>
16 | compile("body { font-family: system-ui; }")
17 | )
18 |
19 | test("Normalize.css", () =>
20 | compile(".before { color: red; } @import-normalize; .after { color: green; }")
21 | )
22 |
23 | test("Initial", () =>
24 | compile("h1 { font-family: initial; }")
25 | )
26 |
27 | test("Initial - All", () =>
28 | compile("ul { all: initial; }")
29 | )
30 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/messages/fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "generic.error.title": "Défaut",
3 | "generic.info.title": "Renseignement",
4 |
5 | "lifecycle.error": "Les données n'ont pas pu être chargées.",
6 | "lifecycle.loading": "Chargement des données...",
7 | "lifecycle.skip": "Impossible de charger les données parce qu'il manque un paramètre requis.",
8 |
9 | "router.notfound": "La page n'a malheureusement pas été trouvée!",
10 | "router.codesplit.error": "Malheureusement, une erreur s'est produite pendant le processus de chargement.: ",
11 | "router.codesplit.loading": "La page demandée est chargée...",
12 |
13 | "locale.value.auto": "Automatique",
14 | "locale.value.de-DE": "Deutsch (Deutschland)",
15 | "locale.value.fr-FR": "Français (France)",
16 | "locale.value.es-ES": "Espagnol (Espagne)",
17 | "locale.value.en-US": "English (USA)"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/edge-webpack/src/config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | import "universal-dotenv"
3 |
4 | export const IS_PRODUCTION = process.env.NODE_ENV === "production"
5 | export const IS_TEST = process.env.NODE_ENV === "test"
6 | export const IS_DEVELOPMENT = !IS_PRODUCTION && !IS_TEST
7 |
8 | export const BUILD_TARGET = process.env.BUILD_TARGET || "client"
9 |
10 | export const ENABLE_SOURCE_MAPS = true
11 |
12 | export const ASSET_EXTS = /\.(eot|woff|woff2|ttf|otf|svg|png|jpg|jpeg|jp2|jpx|jxr|gif|webp|mp4|mp3|ogg|pdf|html|ico|xml)$/
13 | export const BABEL_EXTS = /\.(js|mjs|jsx)$/
14 | export const POSTCSS_EXTS = /\.(css|sss|pcss)$/
15 | export const POSTCSS_MODULE_EXTS = /\.module\.(css|sss|pcss)$/
16 | export const COMPRESSABLE_EXTS = /\.(ttf|otf|svg|pdf|html|ico|txt|md|html|js|css|json|xml)$/
17 | export const YAML_EXTS = /\.(yml|yaml)$/
18 | export const GRAPHQL_EXTS = /\.(graphql|gql)$/
19 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/Responsive.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-max-type, property-no-unknown */
2 |
3 | @mixin mobile {
4 | @media screen and (width >= 20em) and (width < 30em) {
5 | @content;
6 | }
7 | }
8 |
9 | @mixin desktop {
10 | @media screen and (width >= 48em) {
11 | @content;
12 | }
13 | }
14 |
15 | /*
16 | Adaptive Sizing for Mobile
17 | See also: https://github.com/seaneking/postcss-responsive-type
18 | */
19 | @include mobile {
20 | html {
21 | /* min-size, max-size */
22 | font-size: responsive 16px 18px;
23 |
24 | /* viewport widths between which font-size is fluid */
25 | font-range: 320px 400px;
26 | }
27 | }
28 |
29 | @include desktop {
30 | html {
31 | /* min-size, max-size */
32 | font-size: responsive 16px 18px;
33 |
34 | /* viewport widths between which font-size is fluid */
35 | font-range: 1280px 1600px;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/sass.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // ================ SASS INSPIRED =====================
5 | // ====================================================
6 |
7 | test("Sassy Mixins", () =>
8 | compile("@mixin simple{ color: red; } h1 { @include simple; }")
9 | )
10 |
11 | test("Sassy Variables", () =>
12 | compile("$bgColor: red; h1 { background: $bgColor; }")
13 | )
14 |
15 | test("Nested Basic", () =>
16 | compile("body { h1 { font-weight: bold; } h2 { font-weight: normal; }}")
17 | )
18 |
19 | test("Nested Parent Selector", () =>
20 | compile("body { ul { li { &:first-child { margin-top: 0; }}}}")
21 | )
22 |
23 | test("Calc Simple", () =>
24 | compile("h1 { width: calc(10% + 3%); }")
25 | )
26 |
27 | test("Calc Complex", () =>
28 | compile("h1 { width: calc(99.999% * 3 / 10 - 22px); }")
29 | )
30 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jest-preset-edge",
3 | "version": "0.2.1-alpha.18",
4 | "description": "Centralized Jest configuration for Edge-based projects.",
5 | "main": "jest-preset.js",
6 | "scripts": {
7 | "test": "jest",
8 | "prepack": "echo"
9 | },
10 | "files": [
11 | "setup.js",
12 | "transform"
13 | ],
14 | "author": {
15 | "name": "Sebastian Software",
16 | "email": "s.werner@sebastian-software.de",
17 | "url": "https://www.sebastian-software.de"
18 | },
19 | "license": "Apache-2.0",
20 | "dependencies": {
21 | "babel-jest": "^23.6.0",
22 | "graphql-tag": "^2.9.2",
23 | "identity-obj-proxy": "^3.0.0",
24 | "jest": "^23.6.0",
25 | "jest-canvas-mock": "^1.1.0",
26 | "jest-fetch-mock": "^1.6.6",
27 | "jest-mock-now": "^1.2.0",
28 | "raf": "^3.4.0",
29 | "universal-dotenv": "^1.9.1",
30 | "url-polyfill": "^1.1.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/packages/edge-core/src/server/getLocaleData.js:
--------------------------------------------------------------------------------
1 | export default function getLocaleData(request) {
2 | let locale = request.locale
3 | let language = null
4 | let region = null
5 | let source = null
6 |
7 | if (locale)
8 | {
9 | language = locale.language
10 | region = locale.region
11 | source = locale.source
12 | locale = `${language}-${region}`
13 | }
14 | else
15 | {
16 | console.warn("Locale not auto-detected by server!")
17 |
18 | locale = process.env.DEFAULT_LOCALE
19 | if (locale) {
20 | source = "env"
21 | let splitted = locale.split("-")
22 | language = splitted[0]
23 | region = splitted[1]
24 | } else {
25 | locale = "en-US"
26 | language = "en"
27 | region = "US"
28 | source = "default"
29 | }
30 | }
31 |
32 | console.log(`Using locale: ${locale} via ${source}`)
33 |
34 | return {
35 | locale,
36 | language,
37 | region
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/client/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { hydrate, render } from "react-dom"
3 |
4 | import Application from "../Application"
5 | import State from "../State"
6 |
7 | // eslint-disable-next-line no-console
8 | console.log(`[APP] Build: ${process.env.NODE_ENV}-${process.env.BUILD_TARGET}`)
9 |
10 |
11 | const root = document.getElementById("root")
12 | hydrate(, root)
13 |
14 |
15 |
16 |
17 | if (process.env.NODE_ENV === "development" && module.hot) {
18 | // Any changes to our application will cause a hotload re-render.
19 | module.hot.accept("../Application", () => {
20 | const NextApplication = require("../Application").default
21 | render(, root)
22 | })
23 |
24 | // Any changes to our state machinery will update the reducers.
25 | module.hot.accept("../State", () => {
26 | const NextState = require("../State").default
27 | updateState(NextState)
28 | })
29 | }
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "devDependencies": {
4 | "eslint": "^5.6.0",
5 | "eslint-config-readable": "^2.2.0",
6 | "flow-bin": "^0.81.0",
7 | "lerna": "^3.4.0",
8 | "lerna-changelog": "^0.8.0",
9 | "lint-staged": "^7.2.2",
10 | "prettier": "^1.14.2",
11 | "stylelint": "^9.5.0",
12 | "stylelint-config-readable": "^1.4.0"
13 | },
14 | "scripts": {
15 | "clean": "lerna clean --yes && rimraf node_modules",
16 | "update": "ncu -ua && lerna exec ncu -- -ua",
17 | "test": "lerna run --stream --sort test",
18 | "pretest": "npm run prepack && lerna link",
19 | "xprecommit": "lint-staged",
20 | "prepack": "lerna run --stream --sort prepack",
21 | "publish": "npm run prepack && lerna publish"
22 | },
23 | "pre-commit": "lint-staged",
24 | "lint-staged": {
25 | "*.js": "eslint --quiet",
26 | "*.css": "stylelint --quiet"
27 | },
28 | "workspaces": [
29 | "packages/*"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/packages/edge-express/src/addCoreMiddleware.js:
--------------------------------------------------------------------------------
1 | import compression from "compression"
2 | import createLocaleMiddleware from "express-locale"
3 | import cookieParser from "cookie-parser"
4 | import bodyParser from "body-parser"
5 |
6 | export default function addCoreMiddleware(server, { locale }) {
7 | // Parse cookies via standard express tooling
8 | server.use(cookieParser())
9 |
10 | // Detect client locale and match it with configuration
11 | server.use(
12 | createLocaleMiddleware({
13 | priority: [ "query", "cookie", "accept-language", "default" ],
14 | default: locale.default.replace(/-/, "_"),
15 | allowed: locale.supported.map(entry => entry.replace(/-/, "_"))
16 | })
17 | )
18 |
19 | // Parse application/x-www-form-urlencoded
20 | server.use(bodyParser.urlencoded({ extended: false }))
21 |
22 | // Parse application/json
23 | server.use(bodyParser.json())
24 |
25 | // Compress output stream
26 | server.use(compression())
27 | }
28 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/modules/Env.js:
--------------------------------------------------------------------------------
1 | export const SET_ENV = "env/SET"
2 |
3 | /**
4 | * Selector for accessing the env values from inside the global state.
5 | *
6 | * @param {state} state Global Redux state.
7 | */
8 | export function getEnv(state) {
9 | return state.env
10 | }
11 |
12 | /**
13 | * Action creator for setting the env values.
14 | *
15 | * @param {number} value New values to set for the env.
16 | */
17 | export function setEnv(value) {
18 | return { type: SET_ENV, value }
19 | }
20 |
21 | const initialState = {}
22 |
23 | /**
24 | * Reducer for all env relevant action types.
25 | *
26 | * @param previousState Previous state object of this reducer.
27 | * @param {string} action Action to process.
28 | */
29 | export function envReducer(previousState = initialState, action) {
30 | switch (action.type) {
31 | case SET_ENV:
32 | return { ...previousState, ...action.value }
33 |
34 | default:
35 | return previousState
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/edge-core/src/server.js:
--------------------------------------------------------------------------------
1 | // This file is just for exporting infrastructure to applications built upon this.
2 |
3 | // Polyfill for fetch() API in NodeJS based on code from
4 | // https://github.com/matthew-andrews/isomorphic-fetch/blob/master/fetch-npm-node.js
5 | if (!global.fetch) {
6 | var realFetch = require("node-fetch")
7 | global.fetch = function fetch(url, options) {
8 | const normalized = (/^\/\//).test(url) ? `https:${url}` : url
9 | return realFetch.call(this, normalized, options)
10 | }
11 | global.Response = realFetch.Response
12 | global.Headers = realFetch.Headers
13 | global.Request = realFetch.Request
14 | }
15 |
16 | export * from "./common"
17 |
18 | export { default as renderPage } from "./server/renderPage"
19 | export { default as renderApplication } from "./server/renderApplication"
20 | export { default as getLocaleData } from "./server/getLocaleData"
21 | export { default as prepareResponse } from "./server/prepareResponse"
22 |
23 | export * from "./server/debug"
24 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/binary.js:
--------------------------------------------------------------------------------
1 | import { resolve } from "path"
2 | import { createExpressServer } from "edge-express"
3 | import { loadConfig } from "edge-common"
4 | import "universal-dotenv"
5 |
6 | /* eslint-disable no-console, security/detect-non-literal-require */
7 | async function main() {
8 | const { config } = await loadConfig()
9 |
10 | const clientStats = require(resolve(config.output.client, "stats.json"))
11 | const serverRender = require(resolve(config.output.server, "main.js")).default
12 |
13 | const server = createExpressServer({
14 | staticConfig: {
15 | public: config.output.public,
16 | path: config.output.client
17 | },
18 | localeConfig: config.locale,
19 | afterSecurity: [],
20 | beforeFallback: [
21 | serverRender({
22 | clientStats
23 | })
24 | ]
25 | })
26 |
27 | server.listen(process.env.SERVER_PORT, () => {
28 | console.log(`React Server Started @ Port ${process.env.SERVER_PORT}`)
29 | })
30 | }
31 |
32 | process.nextTick(main)
33 |
--------------------------------------------------------------------------------
/packages/edge-webpack/src/modules/Locales.js:
--------------------------------------------------------------------------------
1 | import webpack from "webpack"
2 |
3 | export const APP_LOCALES = process.env.APP_LOCALES ?
4 | process.env.APP_LOCALES.split(",") :
5 | [ process.env.APP_DEFAULT_LOCALE || "en-US" ]
6 |
7 | const LOCALES_MATCHER = new RegExp(`\\b(${APP_LOCALES.join("|")})\\b`)
8 | const LANGUAGES_MATCHER = new RegExp(
9 | `\\b(${APP_LOCALES.map((entry) => entry.split("-")[0]).join("|")})\\b`
10 | )
11 |
12 | export default {
13 | plugins: [
14 | // Fix context imports in Webpack to the supported locales
15 | // This entry is for lean-intl which uses locale specific data packs
16 | new webpack.ContextReplacementPlugin(
17 | /lean-intl[/\\]locale-data[/\\]js$/,
18 | LOCALES_MATCHER
19 | ),
20 |
21 | // Fix context imports in Webpack to the supported locales
22 | // This entry is for react-intl which uses language specific data packs
23 | new webpack.ContextReplacementPlugin(
24 | /react-intl[/\\]locale-data$/,
25 | LANGUAGES_MATCHER
26 | )
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/packages/edge-style/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-style",
3 | "version": "1.0.0-alpha.14",
4 | "description": "Styling Essentials for Edge. Part of the Edge Platform.",
5 | "main": "lib/index.js",
6 | "browser": "lib/index.js",
7 | "scripts": {
8 | "test": "echo",
9 | "build": "rimraf lib && prepublish",
10 | "prepack": "npm run build"
11 | },
12 | "engines": {
13 | "node": ">=6.0.0",
14 | "yarn": ">=1.0.0",
15 | "npm": ">=4.0.0"
16 | },
17 | "keywords": [
18 | "css",
19 | "normalize",
20 | "sanitize",
21 | "reset",
22 | "opentype",
23 | "cssreset"
24 | ],
25 | "author": {
26 | "name": "Sebastian Software",
27 | "email": "s.werner@sebastian-software.de",
28 | "url": "https://www.sebastian-software.de"
29 | },
30 | "files": [
31 | "bin/",
32 | "docs/",
33 | "lib/"
34 | ],
35 | "license": "Apache-2.0",
36 | "dependencies": {
37 | "edge-postcss": "^1.0.0-alpha.14"
38 | },
39 | "devDependencies": {
40 | "prepublish": "2.2.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/State.test.js:
--------------------------------------------------------------------------------
1 | import { createReduxStore, createRootReducer } from "./State"
2 |
3 | test("Create Redux Store - Basic", () => {
4 | const reducers = {}
5 | const middlewares = []
6 | const enhancers = []
7 |
8 | expect(createReduxStore({ reducers, middlewares, enhancers })).toBeDefined()
9 | })
10 |
11 | test("Create Redux Store - No Reducers", () => {
12 | const middlewares = []
13 | const enhancers = []
14 |
15 | expect(createReduxStore({ middlewares, enhancers })).toBeDefined()
16 | })
17 |
18 | test("Create Redux Store - Empty Param", () => {
19 | expect(createReduxStore({})).toBeDefined()
20 | })
21 |
22 | test("Create Redux Store - No Params", () => {
23 | expect(createReduxStore()).toBeDefined()
24 | })
25 |
26 | test("Create Root Reducer", () => {
27 | expect(createRootReducer()).toBeDefined()
28 | })
29 |
30 | test("Create Root Reducer with one reducer", () => {
31 | function dummy(prevState) {
32 | return prevState
33 | }
34 |
35 | expect(createRootReducer({ dummy })).toBeDefined()
36 | })
37 |
--------------------------------------------------------------------------------
/packages/edge-express/src/addFallbackHandler.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-magic-numbers, max-params */
2 | export default function addFallbackHandler(server) {
3 | // Handle 404 errors.
4 | // Note: the react application middleware hands 404 paths, but it is good to
5 | // have this backup for paths not handled by the universal middleware. For
6 | // example you may bind a /api path to express.
7 | server.use((request, response, next) => {
8 | // eslint-disable-line no-unused-vars,max-len
9 | response.status(404).send("Sorry, that resource was not found.")
10 | })
11 |
12 | // Handle all other errors (i.e. 500).
13 | // Note: You must provide specify all 4 parameters on this callback function
14 | // even if they aren't used, otherwise it won't be used.
15 | server.use((error, request, response, next) => {
16 | if (error) {
17 | /* eslint-disable no-console */
18 | console.log(error)
19 | console.log(error.stack)
20 | }
21 |
22 | response.status(500).send("Sorry, an unexpected error occurred.")
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/packages/edge-common/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-common",
3 | "description": "Edge common contains NodeJS based common utilities and helpers. Part of the Edge Platform.",
4 | "version": "1.0.0-alpha.10",
5 | "author": {
6 | "name": "Sebastian Software",
7 | "email": "s.werner@sebastian-software.de",
8 | "url": "https://www.sebastian-software.de"
9 | },
10 | "main": "lib/index.cjs.js",
11 | "module": "lib/index.esm.js",
12 | "license": "Apache-2.0",
13 | "scripts": {
14 | "prepack": "npm run build",
15 | "build": "rimraf bin && rimraf lib && preppy",
16 | "test": "echo"
17 | },
18 | "engines": {
19 | "node": ">=6.0.0",
20 | "yarn": ">=1.0.0",
21 | "npm": ">=4.0.0"
22 | },
23 | "dependencies": {
24 | "app-root-dir": "^1.0.2",
25 | "chalk": "^2.4.1",
26 | "cosmiconfig": "^5.0.6",
27 | "jsome": "^2.5.0",
28 | "lodash": "^4.17.11",
29 | "node-notifier": "^5.2.1",
30 | "yn": "^2.0.0"
31 | },
32 | "devDependencies": {
33 | "jest": "23.6.0",
34 | "preppy": "^4.4.0",
35 | "rimraf": "^2.6.2"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/edge-common/src/logging.js:
--------------------------------------------------------------------------------
1 | import chalk from "chalk"
2 | import notifier from "node-notifier"
3 |
4 | import { NAME, VERSION } from "./config"
5 |
6 | export function colorize(message, level = null) {
7 | switch (level) {
8 | case "warn":
9 | return chalk.yellow(message)
10 |
11 | case "error":
12 | return chalk.red(message)
13 |
14 | case "info":
15 | return chalk.green(message)
16 |
17 | default:
18 | return message
19 | }
20 | }
21 |
22 | export function notify(message, level = null) {
23 | notifier.notify({
24 | title: `${NAME}-${VERSION}`,
25 | message
26 | })
27 |
28 | /* eslint-disable no-console */
29 | const consoleMessage = `${chalk.bold(NAME)}: ${colorize(message, level)}`
30 | switch (level) {
31 | case "warn":
32 | console.warn(consoleMessage)
33 | break
34 |
35 | case "error":
36 | console.error(consoleMessage)
37 | break
38 |
39 | case "info":
40 | console.log(consoleMessage)
41 | break
42 |
43 | default:
44 | console.log(consoleMessage)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/assets.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Asset Size (Same Folder) 1`] = `
4 | ".icon{
5 | background-size:304px 85px
6 | }"
7 | `;
8 |
9 | exports[`Asset Size 1`] = `
10 | ".icon{
11 | background-size:304px 85px
12 | }"
13 | `;
14 |
15 | exports[`Asset URL (Same Folder) 1`] = `
16 | ".icon{
17 | background:url(./formula.png)
18 | }"
19 | `;
20 |
21 | exports[`Asset URL 1`] = `
22 | ".icon{
23 | background:url(../fixtures/formula.png)
24 | }"
25 | `;
26 |
27 | exports[`Import with Asset URL 1`] = `
28 | ".image{
29 | background:url(../fixtures/formula.png)
30 | }"
31 | `;
32 |
33 | exports[`Import with SVG URL 1`] = `
34 | ".preloader{
35 | background:url(../fixtures/other/logo.svg);
36 | border:1px solid #000
37 | }"
38 | `;
39 |
40 | exports[`Import with Webfonts 1`] = `
41 | "@font-face{
42 | src:url(../fixtures/font/SourceSansPro-Light.otf.woff2) format(\\"woff2\\"),url(../fixtures/font/SourceSansPro-Light.otf.woff) format(\\"woff\\");
43 | font-family:Source Sans Pro;
44 | font-weight:300;
45 | font-style:normal
46 | }"
47 | `;
48 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 |
4 | node_js:
5 | - 6
6 | - 8
7 | - 10
8 |
9 | matrix:
10 | fast_finish: true
11 |
12 | env:
13 | - CXX=g++-4.8
14 |
15 | addons:
16 | apt:
17 | sources:
18 | - ubuntu-toolchain-r-test
19 | packages:
20 | - g++-4.8
21 |
22 | install:
23 | yarn install --ignore-engines
24 |
25 | notifications:
26 | email: false
27 | slack:
28 | secure: bvUKXISN63vf7XnvOb9zI4KzgIb59HeDgZYrKSq63XpM3iX9Hm/j6njYPBFzYoVn6FTXwAdWmAG4EzbRIl0We7NNFivqCtFDdA3FMEaksLyb02OkPEfjyunChDpRoGdV5EzlS3YpsyWW/jYGSg22STBynWnbsDXEQZXu5SU9v58MJDV9w1kvbex4aLxlTt15M1cMjNmgHRhduHo8+dIS1Pb5MSl3hQUCgBppuD4rDFESC1MTAd047ZYF5PNbuAfGCpXcEyRVZMsD+A2kcO7VE3anaFvma7Qm9u9EN7yPuBKF2/mcZCx2Anmh8/XBK5/fAg4DeYq6pqjuQNiiq/SwZxvM+hEupwHXRZ13BkIzmSC6gnRlp9bhqU1HHotRwxm0gS8MrnEKCWhQi3f+ZWSIpIFXWQrdcqKNdw/zZvIn69UdAxqnzr3DTML7G8gKuXAky2Ibnx3bErUNA2wZP2vIYS9VUG85S1WQCbxTgxDfelDXoPHtZDWhqIM257g8WzLc51tJr4WSkIuXTxMBs9GBFdi9mrdvaAA3u4N+S9FK94VrpExnP9PEFQxo/KTY1wmhhi7hcvOgy03l/YoHl1EmVUEmamdbYM9nCXla6/KK5MHJ2HudiZwVMlXWinETC2MJ/ApHqy41cTit3hhy0EB7vc85Amr2QjOOeGTxCE89ThY=
29 |
30 | cache:
31 | yarn: true
32 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/color.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`CSS4 HSL Colors 1`] = `
4 | ".hsl{
5 | color:red;
6 | border-color:rgba(0,255,255,.2)
7 | }"
8 | `;
9 |
10 | exports[`CSS4 HWB Colors 1`] = `
11 | ".hwb{
12 | color:rgba(128,255,0,.5)
13 | }"
14 | `;
15 |
16 | exports[`Color Function 1`] = `
17 | ".yellow{
18 | color:rgba(255,220,0,.9)
19 | }"
20 | `;
21 |
22 | exports[`Easing Gradients 1`] = `
23 | ".demo{
24 | background:linear-gradient(to bottom,#111 ,rgba(17,17,17,.90909) 12.34%,rgba(17,17,17,.80331) 23.32%,rgba(17,17,17,.6876) 33.19%,rgba(17,17,17,.56694) 42.17%,rgba(17,17,17,.44628) 50.5%,rgba(17,17,17,.33058) 58.42%,rgba(17,17,17,.22479) 66.16%,rgba(17,17,17,.13388) 73.95%,rgba(17,17,17,.06281) 82.03%,rgba(17,17,17,.01653) 90.64%,rgba(17,17,17,0))
25 | }"
26 | `;
27 |
28 | exports[`Hex with Alpha 1`] = `
29 | ".blue{
30 | color:rgba(17,17,255,.8)
31 | }"
32 | `;
33 |
34 | exports[`Improved Color Palette 1`] = `
35 | ".red{
36 | color:#ff4136
37 | }"
38 | `;
39 |
40 | exports[`RGBA with Hex 1`] = `
41 | ".red{
42 | color:rgba(255,17,17,.8)
43 | }"
44 | `;
45 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/assets.js:
--------------------------------------------------------------------------------
1 | import { compile, compileSameFolder } from "./core"
2 |
3 | // ====================================================
4 | // ================= URLS/ASSETS ======================
5 | // ====================================================
6 |
7 | test("Asset URL", () =>
8 | compile(".icon { background: url('./fixtures/formula.png'); }"))
9 |
10 | test("Asset URL (Same Folder)", () =>
11 | compileSameFolder(".icon { background: url('./formula.png'); }"))
12 |
13 | test("Asset Size", () =>
14 | compile(
15 | ".icon { background-size: width('./fixtures/formula.png') height('./fixtures/formula.png'); }"
16 | ))
17 |
18 | test("Asset Size (Same Folder)", () =>
19 | compileSameFolder(
20 | ".icon { background-size: width('./formula.png') height('./formula.png'); }"
21 | ))
22 |
23 | test("Import with Asset URL", () =>
24 | compile("@import './fixtures/import-c.css';"))
25 |
26 | test("Import with SVG URL", () =>
27 | compile("@import './fixtures/other/Home.css';"))
28 |
29 | test("Import with Webfonts", () =>
30 | compile("@import './fixtures/font/SourceSansPro.css';"))
31 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/color.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // ================== COLOR ===========================
5 | // ====================================================
6 |
7 | test("Improved Color Palette", () =>
8 | compile(".red { color: red; }")
9 | )
10 |
11 | test("RGBA with Hex", () =>
12 | compile(".red { color: rgba(#f11, 0.8); }")
13 | )
14 |
15 | test("Hex with Alpha", () =>
16 | compile(".blue { color: #11fc; }")
17 | )
18 |
19 | test("Color Function", () =>
20 | compile(".yellow { color: color(yellow a(90%)) }")
21 | )
22 |
23 | test("Easing Gradients", () =>
24 | compile(`
25 | .demo {
26 | background: linear-gradient(
27 | to bottom,
28 | black,
29 | cubic-bezier(0.48, 0.30, 0.64, 1.00),
30 | transparent
31 | );
32 | }`))
33 |
34 | test("CSS4 HSL Colors", () =>
35 | compile(`
36 | .hsl {
37 | color: hsl(0 100% 50%);
38 | border-color: hsl(200grad 100% 50% / 20%);
39 | }`))
40 |
41 | test("CSS4 HWB Colors", () =>
42 | compile(`
43 | .hwb {
44 | color: hwb(90, 0%, 0%, 0.5);
45 | }`))
46 |
47 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/fixes.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // ================== FIXES ===========================
5 | // ====================================================
6 |
7 | test("Font Variant", () =>
8 | compile(`
9 | h2 {
10 | font-variant-caps: small-caps;
11 | }
12 |
13 | table {
14 | font-variant-numeric: lining-nums;
15 | }`))
16 |
17 | test("Gradient Fix", () =>
18 | compile(".elem { background-image: linear-gradient(green, transparent); }")
19 | )
20 |
21 | test("Flexbox Fix", () =>
22 | compile(".elem { flex: 1; }")
23 | )
24 |
25 | test("Input Style Fixes", () =>
26 | compile(`
27 | input[type="range"]::track {
28 | height: 3px;
29 | }
30 |
31 | input[type="range"]::thumb {
32 | width: 16px;
33 | height: 8px;
34 | }
35 | `)
36 | )
37 |
38 | test("Autoprefixer", () =>
39 | compile(":fullscreen a { display: flex }")
40 | )
41 |
42 | test("Pseudoelements", () =>
43 | compile("a::before { color: red; }")
44 | )
45 |
46 | test("Selector matches()", () =>
47 | compile("p:matches(:first-child, .special) { color: red; }")
48 | )
49 |
--------------------------------------------------------------------------------
/packages/edge-webpack/__tests__/project/project.test.js:
--------------------------------------------------------------------------------
1 | /* global __dirname */
2 |
3 | import { join, resolve } from "path"
4 | import { readdirSync, readFileSync } from "fs"
5 | import rimraf from "rimraf"
6 | import webpack from "webpack"
7 |
8 | process.env.NODE_ENV = "production"
9 |
10 | /* eslint-disable-next-line import/no-commonjs */
11 | const edge = require("../../src")
12 |
13 | const config = edge.full({ root: __dirname, quiet: true })
14 |
15 | beforeEach((done) => {
16 | rimraf(resolve(__dirname, "dist"), done)
17 | })
18 |
19 | test("Executes correctly", (done) => {
20 | const compiler = webpack(config)
21 | compiler.run((err, stats) => {
22 | if (err || stats.hasErrors()) {
23 | // Handle errors here
24 | throw new Error(err)
25 | }
26 |
27 | const dist = join(__dirname, "dist")
28 |
29 | expect(readdirSync(dist)).toMatchSnapshot("dirlist")
30 | expect(readFileSync(`${dist}/index.html`, "utf-8")).toMatchSnapshot("htmlfile")
31 | expect(readFileSync(`${dist}/file-1UZ6YEQK.svg`, "utf-8")).toMatchSnapshot("logofile")
32 | })
33 |
34 | compiler.hooks.done.tap("Test", () => setTimeout(done))
35 | })
36 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/layout.js:
--------------------------------------------------------------------------------
1 | import { compile } from "./core"
2 |
3 | // ====================================================
4 | // ================== LAYOUT ==========================
5 | // ====================================================
6 |
7 | test("Lost Grid", () =>
8 | compile(".grid { lost-column: 3/12 }")
9 | )
10 |
11 | test("Grid KISS", () =>
12 | compile(`
13 | .gridTest {
14 | grid-kiss:
15 | "+-------------------------------+ "
16 | "| header ↑ | 120px"
17 | "+-------------------------------+ "
18 | " "
19 | "+-- 30% ---+ +--- auto --------+ "
20 | "| .sidebar | | main | auto "
21 | "+----------+ +-----------------+ "
22 | " "
23 | "+-------------------------------+ "
24 | "| ↓ | 60px "
25 | "| → footer ← | "
26 | "+-------------------------------+ "
27 | }
28 | `)
29 | )
30 |
31 | test("Flow Root", () =>
32 | compile(".selector { display: flow-root; }")
33 | )
34 |
--------------------------------------------------------------------------------
/packages/edge-webpack/src/modules/Optimization.js:
--------------------------------------------------------------------------------
1 | import UglifyJsPlugin from "uglifyjs-webpack-plugin"
2 | import OptimizeCSSAssetsPlugin from "optimize-css-assets-webpack-plugin"
3 |
4 | import { IS_PRODUCTION, ENABLE_SOURCE_MAPS } from "../config"
5 |
6 | export default {
7 | optimization: {
8 | // Docs: https://webpack.js.org/plugins/split-chunks-plugin/
9 | splitChunks: {
10 | // There are some issues with HtmlWebpackPlugin and the automatic vendor chunk right now.
11 | // chunks: "all",
12 | // Since the chunk name includes all origin chunk names it’s recommended for production builds
13 | // with long term caching to NOT include [name] in the filenames, or switch off name generation
14 | // Via: https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
15 | // name: false
16 | },
17 | minimizer: IS_PRODUCTION ?
18 | [
19 | new UglifyJsPlugin({
20 | cache: true,
21 | parallel: true,
22 | sourceMap: ENABLE_SOURCE_MAPS
23 | }),
24 | new OptimizeCSSAssetsPlugin({})
25 | ] :
26 | []
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/State.js:
--------------------------------------------------------------------------------
1 | import { counterReducer } from "./modules/Counter"
2 | import { envReducer } from "./modules/Env"
3 |
4 | export default {
5 | /**
6 | * Returns configuration objects for different areas of the Edge
7 | * powered application infrastructure.
8 | *
9 | * @param state {Object} Current application state.
10 | * @param topic {String} Any of "apollo", ...
11 | */
12 | getConfig(state, topic) {
13 | if (topic === "apollo") {
14 | return {
15 | uri: state.env.APOLLO_URL
16 |
17 | // headers: {},
18 | // batchRequests: false,
19 | // trustNetwork: true,
20 | // queryDeduplication: true
21 | }
22 | }
23 |
24 | return null
25 | },
26 |
27 | /**
28 | * Return list of Redux store enhancers to use.
29 | */
30 | getEnhancers() {
31 | return []
32 | },
33 |
34 | /**
35 | * Create mapping of reducers to use for the Redux store.
36 | */
37 | getReducers() {
38 | return {
39 | counter: counterReducer,
40 | env: envReducer
41 | }
42 | },
43 |
44 | /**
45 | * Create list of Redux middleware to use.
46 | */
47 | getMiddlewares() {
48 | return []
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/edge-webpack/src/modules/Experience.js:
--------------------------------------------------------------------------------
1 | import webpack from "webpack"
2 | import ErrorOverlayPlugin from "error-overlay-webpack-plugin"
3 | import FriendlyPlugin from "friendly-errors-webpack-plugin"
4 |
5 | import { IS_DEVELOPMENT, IS_PRODUCTION } from "../config"
6 |
7 | const stats = "minimal"
8 | const logLevel = "warn"
9 |
10 | export default {
11 | stats,
12 |
13 | // The new development web server of Webpack
14 | // See also: https://github.com/webpack-contrib/webpack-serve
15 | serve: {
16 | devMiddleware: {
17 | logLevel,
18 | stats
19 | },
20 |
21 | hotClient: {
22 | logLevel
23 | }
24 | },
25 |
26 | // The legacy development web server of Webpack
27 | // See also: https://webpack.js.org/configuration/dev-server/
28 | devServer: {
29 | stats,
30 | clientLogLevel: logLevel
31 | },
32 |
33 | plugins: [
34 | IS_DEVELOPMENT || IS_PRODUCTION ?
35 | new FriendlyPlugin({
36 | clearConsole: false
37 | }) :
38 | null,
39 |
40 | IS_DEVELOPMENT ? new ErrorOverlayPlugin() : null,
41 |
42 | // Does not work well with HMR and Dev Server
43 | IS_PRODUCTION ? new webpack.ProgressPlugin() : null
44 | ].filter(Boolean)
45 | }
46 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Use Unix line breaks for all text by default
2 | # Unfortunately this requires to define binary types as well as
3 | # this applies to all files - not just text.
4 | * text eol=lf
5 |
6 | # GRAPHICS
7 | *.ai binary
8 | *.bmp binary
9 | *.eps binary
10 | *.gif binary
11 | *.ico binary
12 | *.jng binary
13 | *.jp2 binary
14 | *.jpg binary
15 | *.jpeg binary
16 | *.jpx binary
17 | *.jxr binary
18 | *.pdf binary
19 | *.png binary
20 | *.psb binary
21 | *.psd binary
22 | *.svg text
23 | *.svgz binary
24 | *.tif binary
25 | *.tiff binary
26 | *.wbmp binary
27 | *.webp binary
28 |
29 | # AUDIO
30 | *.kar binary
31 | *.m4a binary
32 | *.mid binary
33 | *.midi binary
34 | *.mp3 binary
35 | *.ogg binary
36 | *.ra binary
37 |
38 | # VIDEO
39 | *.3gpp binary
40 | *.3gp binary
41 | *.as binary
42 | *.asf binary
43 | *.asx binary
44 | *.fla binary
45 | *.flv binary
46 | *.m4v binary
47 | *.mng binary
48 | *.mov binary
49 | *.mp4 binary
50 | *.mpeg binary
51 | *.mpg binary
52 | *.swc binary
53 | *.swf binary
54 | *.webm binary
55 |
56 | # ARCHIVES
57 | *.7z binary
58 | *.gz binary
59 | *.rar binary
60 | *.tar binary
61 | *.zip binary
62 |
63 | # FONTS
64 | *.ttf binary
65 | *.eot binary
66 | *.otf binary
67 | *.woff binary
68 | *.woff2 binary
69 |
--------------------------------------------------------------------------------
/packages/edge-storybook/src/webpack.config.js:
--------------------------------------------------------------------------------
1 | import { core } from "edge-webpack"
2 |
3 | /* eslint-disable import/no-commonjs */
4 | // Export a function. Accept the base config as the only param.
5 | module.exports = (storybookBaseConfig, configType) => {
6 | // configType has a value of 'DEVELOPMENT' or 'PRODUCTION'
7 | // You can change the configuration based on that.
8 | // 'PRODUCTION' is used when building the static version of storybook.
9 |
10 | // Replace Storybooks Babel Loader with local one.
11 | // This enables Babel v7 support.
12 | storybookBaseConfig.module.rules.forEach((rule) => {
13 | if (/babel/.exec(rule.loader)) {
14 | rule.loader = require.resolve("babel-loader")
15 | }
16 | })
17 |
18 | const options = {}
19 | const config = core(options)
20 |
21 | storybookBaseConfig.node = config.node
22 |
23 | // Do not flood the console with thousands of messages
24 | storybookBaseConfig.stats = config.stats
25 | storybookBaseConfig.devServer = config.devServer
26 |
27 | // Append our loaders to the file specific rules
28 | storybookBaseConfig.module.rules.push(...config.module.rules)
29 |
30 | // As well as our set of plugins
31 | storybookBaseConfig.plugins.push(...config.plugins)
32 |
33 | return storybookBaseConfig
34 | }
35 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/server/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { fetchData, prepareResponse, renderApplication } from "edge-core"
3 | import { getLoadableState } from 'loadable-components/server'
4 |
5 | import Application from "../Application"
6 | import State from "../State"
7 |
8 | // eslint-disable-next-line no-console
9 | console.log(`[APP] Build: ${process.env.NODE_ENV}-${process.env.BUILD_TARGET}`)
10 |
11 | /* eslint-disable no-console, max-statements */
12 | export default ({ clientStats }) => async (request, response) => {
13 | // Response Preparation:
14 | // This step parses some client information like language and user agent.
15 | const parsed = prepareResponse(request)
16 |
17 | // Fetch Data:
18 | // Now we are ready to fetch required data by waiting for async requests.
19 | try {
20 | await fetchData(Application)
21 | } catch (error) {
22 | console.error("Unable to fetch data:", error)
23 | }
24 |
25 | // Render Application:
26 | // When all required data is available we can safely render the result.
27 | try {
28 | renderApplication({
29 | Application,
30 | clientStats,
31 | request,
32 | response
33 | })
34 | } catch(error) {
35 | console.error("Unable to render application:", error)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/edge-webpack/__tests__/project/__snapshots__/project.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Executes correctly: dirlist 1`] = `
4 | Array [
5 | "file-1UZ6YEQK.svg",
6 | "index.fxFXOoXR.js",
7 | "index.html",
8 | ]
9 | `;
10 |
11 | exports[`Executes correctly: htmlfile 1`] = `
12 | "
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | "
21 | `;
22 |
23 | exports[`Executes correctly: logofile 1`] = `""`;
24 |
--------------------------------------------------------------------------------
/packages/edge-express/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-express",
3 | "description": "Edge Express is a centralized Express-based HTTP server with sophisticated built-in security.",
4 | "version": "1.0.0-alpha.10",
5 | "author": {
6 | "name": "Sebastian Software",
7 | "email": "s.werner@sebastian-software.de",
8 | "url": "https://www.sebastian-software.de"
9 | },
10 | "main": "lib/index.cjs.js",
11 | "module": "lib/index.esm.js",
12 | "license": "Apache-2.0",
13 | "scripts": {
14 | "prepack": "npm run build",
15 | "build": "rimraf lib && prepublish",
16 | "test": "echo"
17 | },
18 | "files": [
19 | "bin/",
20 | "docs/",
21 | "lib/"
22 | ],
23 | "engines": {
24 | "node": ">=6.0.0",
25 | "yarn": ">=1.0.0",
26 | "npm": ">=4.0.0"
27 | },
28 | "dependencies": {
29 | "app-root-dir": "^1.0.2",
30 | "body-parser": "^1.18.3",
31 | "chalk": "^2.4.1",
32 | "compression": "^1.7.3",
33 | "cookie-parser": "^1.4.3",
34 | "cosmiconfig": "^5.0.6",
35 | "express": "^4.16.3",
36 | "express-locale": "^1.0.5",
37 | "helmet": "^3.13.0",
38 | "hpp": "^0.2.2",
39 | "jsome": "^2.5.0",
40 | "pretty-error": "^2.1.1",
41 | "uuid": "^3.3.2"
42 | },
43 | "devDependencies": {
44 | "jest": "23.6.0",
45 | "prepublish": "2.2.0",
46 | "rimraf": "*"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/createKernel.js:
--------------------------------------------------------------------------------
1 | import { createApolloClient } from "./ApolloClient"
2 | import { createReduxStore } from "./State"
3 | import getBrowserLocale from "../client/getBrowserLocale"
4 |
5 | /* global window */
6 | const defaultState = process.env.TARGET === "web" ? window.APP_STATE : null
7 |
8 | export default function createKernel(State, { state = defaultState, edge, request, supportedLocales } = {}) {
9 | // Use given edge instance when not already defined on state
10 | if (process.env.TARGET === "node" && edge != null) {
11 | if (!state.edge) {
12 | state.edge = edge
13 | }
14 | }
15 |
16 | if (process.env.TARGET === "web" && state.edge.intl == null) {
17 | console.warn("Fallback to client side locale information!")
18 | state.edge.intl = getBrowserLocale(supportedLocales || [ "en-US" ])
19 | }
20 |
21 | const apolloConfig = State.getConfig(state, "apollo")
22 | let apollo = null
23 | if (apolloConfig) {
24 | apollo = createApolloClient(apolloConfig)
25 | }
26 |
27 | const store = createReduxStore({
28 | reducers: State.getReducers(),
29 | enhancers: State.getEnhancers(),
30 | middlewares: State.getMiddlewares(),
31 | state
32 | })
33 |
34 | const intl = state.edge.intl
35 |
36 | // Kernel "Instance"
37 | return {
38 | intl,
39 | apollo,
40 | store
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/wrapApplication.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 |
3 | import { Provider } from "react-redux"
4 | import { ApolloProvider } from "react-apollo"
5 | import { IntlProvider } from "react-intl"
6 |
7 | /**
8 | * Wraps the application class with different providers for offering the
9 | * following features:
10 | *
11 | * - Apollo GraphQL
12 | * - Redux
13 | * - React Intl
14 | *
15 | * This might be extended with new features during development.
16 | *
17 | * @param {React.Component} Application The React root application component.
18 | * @param {Kernel} kernel Kernel instance which holds the data oriented runtime state.
19 | * @returns {React.Component} Returns the wrapped application component.
20 | */
21 | export default function wrapApplication(Application, kernel) {
22 | let Wrapped = Application
23 |
24 | if (kernel.apollo) {
25 | Wrapped = (
26 |
27 | {Wrapped}
28 |
29 | )
30 | }
31 |
32 | if (kernel.store) {
33 | Wrapped = (
34 |
35 | {Wrapped}
36 |
37 | )
38 | }
39 |
40 | if (kernel.intl) {
41 | Wrapped = (
42 |
43 | {Wrapped}
44 |
45 | )
46 | }
47 |
48 | return Wrapped
49 | }
50 |
--------------------------------------------------------------------------------
/packages/edge-core/src/server/renderApplication.js:
--------------------------------------------------------------------------------
1 | import { renderToString } from "react-dom/server"
2 | import flushChunks from "webpack-flush-chunks"
3 |
4 | import renderPage from "./renderPage"
5 |
6 | /* eslint-disable max-params, no-console */
7 | export default function renderApplication({
8 | Application,
9 | clientStats,
10 | kernel,
11 | request,
12 | response
13 | }) {
14 | console.log("[EDGE] Rendering application...")
15 | let html = ""
16 | try {
17 | html = renderToString(Application)
18 | } catch (err) {
19 | console.error("Unable to render server side React:", err)
20 | }
21 |
22 | const { js, styles } = flushChunks(clientStats)
23 |
24 | // TODO: Support SRI integrity checksums as added by SRI Webpack Plugin
25 | // https://www.npmjs.com/package/webpack-subresource-integrity#without-htmlwebpackplugin
26 |
27 | console.log("HTML:",html)
28 |
29 | // Render full HTML page using external helper
30 | console.log("Rendering Page...")
31 | const renderedPage = renderPage({
32 | html,
33 | styles: styles.toString(),
34 | scripts: js.toString()
35 | })
36 |
37 | // Make sure that the actual dynamically rendered page is never being cached
38 | response.setHeader("Cache-Control", "no-cache")
39 |
40 | // Send actual content
41 | console.log("[EDGE] Sending Page...")
42 | return response.status(200).send(renderedPage)
43 | }
44 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/core.js:
--------------------------------------------------------------------------------
1 | import postcss from "postcss"
2 | import loadConfig from "postcss-load-config"
3 |
4 | let plugins = null
5 | let options = null
6 |
7 | beforeAll(async function() {
8 | const config = await loadConfig({ map: false })
9 |
10 | plugins = config.plugins
11 | options = config.options
12 | })
13 |
14 | // We add some super basic formatting to our CSS to make snapshots better readable
15 | // and inspectable in case of any regressions later on.
16 | function format(cssString) {
17 | return cssString
18 | .replace(/;/g, ";\n")
19 | .replace(/}/g, "\n}\n\n")
20 | .replace(/{/g, "{\n")
21 | .replace(/}\n\n\n}/g, "}\n}\n\n")
22 | .replace(/\n\n\n\n/g, "\n\n")
23 | .trim()
24 | }
25 |
26 | export async function compile(input) {
27 | const allOptions = {
28 | ...options,
29 | from: "__tests__/main.css",
30 | to: "__tests__/dist/main.css"
31 | }
32 |
33 | const result = await postcss(plugins)
34 | .process(input, allOptions)
35 |
36 | expect(format(result.css)).toMatchSnapshot()
37 | }
38 |
39 | export async function compileSameFolder(input) {
40 | const allOptions = {
41 | ...options,
42 | from: "__tests__/fixtures/main.css",
43 | to: "__tests__/fixtures/main.out.css"
44 | }
45 |
46 | const result = await postcss(plugins)
47 | .process(input, allOptions)
48 |
49 | expect(format(result.css)).toMatchSnapshot()
50 | }
51 |
--------------------------------------------------------------------------------
/packages/edge-style/src/Intl.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-max-type, comment-empty-line-before */
2 |
3 | /**
4 | * According to Wikipedia:
5 | * http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks
6 | */
7 |
8 | :lang(cy) q {
9 | quotes: "\2018" "\2019" "\201C" "\201D" "\2018" "\2019" "\201C" "\201D";
10 | /* ‘ ’ “ ” ‘ ’ “ ” */
11 | }
12 |
13 | :lang(af) q,
14 | :lang(zh) q,
15 | :lang(en) q,
16 | :lang(en-us) q,
17 | :lang(eo) q,
18 | :lang(id) q,
19 | :lang(ga) q,
20 | :lang(ko) q,
21 | :lang(pt-br) q,
22 | :lang(th) q,
23 | :lang(tr) q {
24 | quotes: "\201C" "\201D" "\2018" "\2019" "\201C" "\201D" "\2018" "\2019";
25 | /* “ ” ‘ ’ “ ” ‘ ’ */
26 | }
27 |
28 | :lang(sq) q,
29 | :lang(bs) q {
30 | quotes: "\201E" "\201C" "\2018" "\2019" "\201E" "\201C" "\2018" "\2019";
31 | /* „ “ ‘ ’ „ “ ‘ ’ */
32 | }
33 |
34 | :lang(ar) q {
35 | quotes: "\201D" "\201C";
36 | /* ” “ */
37 | }
38 |
39 | :lang(cs) q,
40 | :lang(de) q,
41 | :lang(sk) q,
42 | :lang(sl) q,
43 | :lang(sb) q,
44 | :lang(is) q {
45 | quotes: "\201E" "\201C" "\201A" "\2018" "\201E" "\201C" "\201A" "\2018";
46 | /* „ “ ‚ ‘ „ “ ‚ ‘ */
47 | }
48 |
49 | q::before {
50 | content: open-quote;
51 | }
52 |
53 | q::after {
54 | content: close-quote;
55 | }
56 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/effects.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Easings 1`] = `
4 | ".snake{
5 | transition:all 600ms cubic-bezier(.47,0,.745,.715)
6 | }"
7 | `;
8 |
9 | exports[`Magic Animations 1`] = `
10 | "@keyframes magic{
11 | 0%{
12 | opacity:1;
13 | transform-origin:100% 200%;
14 | transform:scale(1,1) rotate(0deg)
15 | }
16 |
17 | to{
18 | opacity:0;
19 | transform-origin:200% 500%;
20 | transform:scale(0,0) rotate(270deg)
21 | }
22 | }
23 |
24 | .animation{
25 | animation-name:magic
26 | }"
27 | `;
28 |
29 | exports[`Pleeease Filters 1`] = `
30 | ".box{
31 | filter:url('data:image/svg+xml;
32 | charset=utf-8,#filter');
33 | -webkit-filter:drop-shadow(16px 16px 20px #00f);
34 | filter:drop-shadow(16px 16px 20px #00f)
35 | }"
36 | `;
37 |
38 | exports[`Transform Shortcut 1`] = `
39 | ".transform{
40 | transform:scale3d(2,1,1) translate3d(10px,20px,0)
41 | }"
42 | `;
43 |
44 | exports[`Will Change Compat 1`] = `
45 | ".scaled{
46 | -webkit-backface-visibility:hidden;
47 | backface-visibility:hidden;
48 | will-change:width
49 | }"
50 | `;
51 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/HtmlHead.js:
--------------------------------------------------------------------------------
1 | import Helmet from "react-helmet"
2 | import React from "react"
3 |
4 | /* eslint-disable import/no-webpack-loader-syntax */
5 |
6 | import AppleTouchIcon from "./apple-touch-icon.png"
7 | import ClassicFavicon from "./favicon.ico"
8 | import FavIcon16 from "./favicon-16x16.png"
9 | import FavIcon32 from "./favicon-32x32.png"
10 | import Manifest from "./manifest.webmanifest"
11 | import SafariPinned from "./safari-pinned-tab.svg"
12 |
13 | export default function HtmlHead() {
14 | return (
15 | /* eslint-disable no-inline-comments */
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | {/* http://httpwg.org/http-extensions/client-hints.html */}
33 |
34 |
35 |
39 |
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/packages/edge-core/readme.md:
--------------------------------------------------------------------------------
1 | # Edge Core
[![Sponsored by][sponsor-img]][sponsor] [![Version][npm-version-img]][npm] [![Downloads][npm-downloads-img]][npm] [![Build Status Unix][travis-img]][travis] [![Build Status Windows][appveyor-img]][appveyor] [![Dependencies][deps-img]][deps]
2 |
3 | [sponsor-img]: https://img.shields.io/badge/Sponsored%20by-Sebastian%20Software-692446.svg
4 | [sponsor]: https://www.sebastian-software.de
5 | [deps]: https://david-dm.org/sebastian-software/edge-core
6 | [deps-img]: https://david-dm.org/sebastian-software/edge-core.svg
7 | [npm]: https://www.npmjs.com/package/edge-core
8 | [npm-downloads-img]: https://img.shields.io/npm/dm/edge-core.svg
9 | [npm-version-img]: https://img.shields.io/npm/v/edge-core.svg
10 | [travis-img]: https://img.shields.io/travis/sebastian-software/edge-core/master.svg?branch=master&label=unix%20build
11 | [appveyor-img]: https://img.shields.io/appveyor/ci/swernerx/edge-core/master.svg?label=windows%20build
12 | [travis]: https://travis-ci.org/sebastian-software/edge-core
13 | [appveyor]: https://ci.appveyor.com/project/swernerx/edge-core/branch/master
14 |
15 | > The Edge Platform helps you focus on business logic rather than dealing with massive tooling, common patterns, complex configurations.
16 |
17 |
18 |
19 | ## License
20 |
21 | [Apache License Version 2.0, January 2004](license)
22 |
23 |
24 | ## Copyright
25 |
26 |
27 |
28 | Copyright 2017-2018
[Sebastian Software GmbH](http://www.sebastian-software.de)
29 |
--------------------------------------------------------------------------------
/packages/edge-core/src/client/getBrowserLocale.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Returns the browser locale settings based on available locales and browser settings.
3 | *
4 | * @param {Array} supportedLocales List of supported locales by the application.
5 | */
6 | export default function getBrowserLocale(supportedLocales) {
7 | return process.env.TARGET === "web" ? _getBrowserLocale(supportedLocales) : null
8 | }
9 |
10 | function _getBrowserLocale(supportedLocales) {
11 | const supported = new Set(supportedLocales)
12 | const available = new Set()
13 |
14 | // Modern standard: Support by modern Chrome, Safari and Firefox
15 | const languages = navigator.languages
16 | if (languages) {
17 | for (const lang of languages) {
18 | if (supported.has(lang)) {
19 | available.add(lang)
20 | }
21 | }
22 | }
23 |
24 | // Microsoft standard
25 | const userLanguage = navigator.userLanguage
26 | if (userLanguage) {
27 | const wellFormedUserLanguage = (() => {
28 | const splitted = userLanguage.split("-")
29 | return `${splitted[0]}-${splitted[1].toUpperCase()}`
30 | })()
31 |
32 | if (supported.has(wellFormedUserLanguage)) {
33 | available.add(wellFormedUserLanguage)
34 | }
35 | }
36 |
37 | // Legacy API
38 | const language = navigator.language
39 | if (language && supported.has(language)) {
40 | available.add(language)
41 | }
42 |
43 | // Return only the first match
44 | const first = Array.from(available.values())[0]
45 | return first ? {
46 | locale: first,
47 | language: first.split("-")[0],
48 | region: first.split("-")[1] || first.split("-")[0].toUpperCase()
49 | } : null
50 | }
51 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/jest-preset.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs, filenames/match-regex */
2 | module.exports = {
3 | transform: {
4 | "^.+\\.(js|jsx|mjs)$": require.resolve("./transform/babel.js"),
5 | "^.+\\.(css|sss|scss|sass)$": require.resolve("./transform/css.js"),
6 | "^.+\\.(graphql|gql)$": require.resolve("./transform/graphql.js"),
7 | "^(?!.*\\.(js|jsx|mjs|css|sss|scss|sass|json|graphql|gql)$)": require.resolve(
8 | "./transform/file.js"
9 | )
10 | },
11 |
12 | transformIgnorePatterns: [
13 | "node_modules/.+\\.(js|jsx|mjs)$",
14 | "^.+\\.module\\.css$"
15 | ],
16 |
17 | moduleNameMapper: {
18 | "^.+\\.module\\.css$": "identity-obj-proxy"
19 | },
20 |
21 | setupFiles: [
22 | require.resolve("./setup.js")
23 | ],
24 |
25 | collectCoverageFrom: [
26 | "src/**/*.js"
27 | ],
28 |
29 | coverageDirectory: "docs/coverage",
30 |
31 | coveragePathIgnorePatterns: [
32 | // NPM packages
33 | "/node_modules/",
34 |
35 | // Publish Export Entries
36 | "src/index.js",
37 | "src/client.js",
38 | "src/server.js",
39 | "src/binary.js",
40 | "src/dev.js",
41 |
42 | // Webpack Entry Points
43 | "/client/",
44 | "/server/",
45 |
46 | // Application Glue Code
47 | "src/App.js",
48 | "src/Main.js",
49 | "src/State.js",
50 | "src/Init.js",
51 |
52 | // Views aka Route Entry Points
53 | "/views/",
54 |
55 | // Storybook Stories
56 | ".story.js",
57 |
58 | // Jest Tests
59 | ".test.js"
60 | ],
61 |
62 | coverageReporters: [
63 | "lcov",
64 | "json-summary",
65 | "json",
66 | "text"
67 | ]
68 | }
69 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/fonts/source-sans-pro/SourceSansPro.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | src:
3 | url("./SourceSansPro-ExtraLight.otf.woff2") format("woff2"),
4 | url("./SourceSansPro-ExtraLight.otf.woff") format("woff");
5 |
6 | font-family: Source Sans Pro;
7 | font-weight: 200;
8 | font-style: normal;
9 | }
10 |
11 | @font-face {
12 | src:
13 | url("./SourceSansPro-Light.otf.woff2") format("woff2"),
14 | url("./SourceSansPro-Light.otf.woff") format("woff");
15 |
16 | font-family: Source Sans Pro;
17 | font-weight: 300;
18 | font-style: normal;
19 | }
20 |
21 | @font-face {
22 | src:
23 | url("./SourceSansPro-Regular.otf.woff2") format("woff2"),
24 | url("./SourceSansPro-Regular.otf.woff") format("woff");
25 |
26 | font-family: Source Sans Pro;
27 |
28 | /* 400 = normal by CSS standards */
29 | font-weight: 400;
30 | font-style: normal;
31 | }
32 |
33 | @font-face {
34 | src:
35 | url("./SourceSansPro-Semibold.otf.woff2") format("woff2"),
36 | url("./SourceSansPro-Semibold.otf.woff") format("woff");
37 |
38 | font-family: Source Sans Pro;
39 | font-weight: 500;
40 | font-style: normal;
41 | }
42 |
43 | @font-face {
44 | src:
45 | url("./SourceSansPro-Bold.otf.woff2") format("woff2"),
46 | url("./SourceSansPro-Bold.otf.woff") format("woff");
47 |
48 | font-family: Source Sans Pro;
49 |
50 | /* 700 = bold by CSS standards */
51 | font-weight: 700;
52 | font-style: normal;
53 | }
54 |
55 | @font-face {
56 | src:
57 | url("./SourceSansPro-Black.otf.woff2") format("woff2"),
58 | url("./SourceSansPro-Black.otf.woff") format("woff");
59 |
60 | font-family: Source Sans Pro;
61 | font-weight: 800;
62 | font-style: normal;
63 | }
64 |
--------------------------------------------------------------------------------
/packages/edge-storybook/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-storybook",
3 | "version": "1.0.0-alpha.32",
4 | "description": "Central configuration for Storybook. For usage in component collections and applications.",
5 | "main": "lib/config.js",
6 | "scripts": {
7 | "test": "echo",
8 | "build": "rimraf lib && cpy src/babelrc --rename=.babelrc lib/ && babel --out-dir lib src",
9 | "prepack": "npm run build"
10 | },
11 | "files": [
12 | "lib/"
13 | ],
14 | "keywords": [],
15 | "author": {
16 | "name": "Sebastian Software",
17 | "email": "s.werner@sebastian-software.de",
18 | "url": "https://www.sebastian-software.de"
19 | },
20 | "license": "Apache-2.0",
21 | "dependencies": {
22 | "@storybook/addon-actions": "^4.0.0-alpha.4",
23 | "@storybook/addon-jest": "^3.4.11",
24 | "@storybook/addon-links": "^4.0.0-alpha.4",
25 | "@storybook/addon-storyshots": "^4.0.0-alpha.4",
26 | "@storybook/addon-storysource": "^3.4.11",
27 | "@storybook/addon-viewport": "^4.0.0-alpha.4",
28 | "@storybook/react": "^4.0.0-alpha.4",
29 | "edge-style": "^1.0.0-alpha.14",
30 | "edge-webpack": "^0.0.2-alpha.17",
31 | "global": "^4.3.2",
32 | "js-cookie": "^2.2.0",
33 | "react-intl": "^2.6.0",
34 | "universal-dotenv": "^1.9.1"
35 | },
36 | "peerDependencies": {
37 | "react": ">=16.4.0",
38 | "react-dom": ">=16.4.0"
39 | },
40 | "devDependencies": {
41 | "@babel/cli": "^7.1.0",
42 | "@babel/core": "^7.1.0",
43 | "babel-core": "^7.0.0-bridge.0",
44 | "babel-loader": "^8.0.2",
45 | "babel-preset-edge": "^4.13.1",
46 | "cpy-cli": "^2.0.0",
47 | "react": "^16.5.2",
48 | "react-dom": "^16.5.2",
49 | "rimraf": "^2.6.2"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/packages/edge-useragent/test/parser.qa.js:
--------------------------------------------------------------------------------
1 | import { parse } from "../src"
2 | import should from "should"
3 | import yaml from "yamlparser"
4 | import fs from "fs"
5 |
6 | // run over the testcases, some might fail, some might not. This is just qu
7 | // test to see if we can parse without errors, and with a reasonable amount
8 | // of errors.
9 | ;["static.custom.yaml", "firefoxes.yaml", "pgts.yaml"].forEach(filename => {
10 | let testcases = fs
11 | .readFileSync(`${__dirname}/fixtures/${filename}`)
12 | .toString()
13 | const parsedyaml = yaml.eval(testcases)
14 |
15 | testcases = parsedyaml.test_cases
16 | testcases.forEach(test => {
17 | // we are unable to parse these tests atm because invalid JSON is used to
18 | // store the useragents
19 | if (typeof test.user_agent_string !== "string") return
20 |
21 | // these tests suck as the test files are broken, enable this to have about
22 | // 40 more failing tests
23 | if (test.family.match(/googlebot|avant/i)) return
24 |
25 | // attempt to parse the shizzle js based stuff
26 | let js_ua
27 | if (test.js_ua) {
28 | js_ua = Function(`return ${test.js_ua}`)().js_user_agent_string
29 | }
30 |
31 | exports[`${filename}: ${test.user_agent_string}`] = () => {
32 | const agent = parse(test.user_agent_string, js_ua)
33 |
34 | agent.family.should.equal(test.family)
35 | // we need to test if v1 is a string, because the yamlparser transforms
36 | // empty v1: statements to {}
37 | agent.major.should.equal(typeof test.major == "string" ? test.major : "0")
38 | agent.minor.should.equal(typeof test.minor == "string" ? test.minor : "0")
39 | agent.patch.should.equal(typeof test.patch == "string" ? test.patch : "0")
40 | }
41 | })
42 | })
43 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/ApolloClient.js:
--------------------------------------------------------------------------------
1 | import { ApolloClient } from "apollo-client"
2 | import { createHttpLink } from "apollo-link-http"
3 | import { InMemoryCache } from "apollo-cache-inmemory"
4 | import { setContext } from "apollo-link-context"
5 |
6 | if (process.env.NODE_ENV === "test") {
7 | global.fetch = require("jest-fetch-mock")
8 | }
9 |
10 | export function createApolloClient(config = {}) {
11 | const {
12 | uri = null,
13 | getAuthHeader = null,
14 | trustNetwork = true,
15 | clientOptions = {},
16 | linkOptions = {}
17 | } = config
18 |
19 | if (uri == null) {
20 | return null
21 | }
22 |
23 | const finalLinkOptions = {
24 | // Based on user given options
25 | ...linkOptions,
26 |
27 | // Use pre-defined URI, the only non optional parameter if Apollo should be enabled.
28 | uri,
29 |
30 | // Fetch Credentials:
31 | // - omit: Never send cookies.
32 | // - same-origin: Send user credentials (cookies, basic http auth, etc..) if the URL is on the same origin as the calling script.
33 | // - include: Always send user credentials (cookies, basic http auth, etc..), even for cross-origin calls.
34 | // See also: https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
35 | credentials: trustNetwork ? "include" : "same-origin"
36 | }
37 |
38 | const httpLink = createHttpLink(finalLinkOptions)
39 |
40 | const middlewareLink = setContext(() => ({
41 | headers: {
42 | authorization: getAuthHeader ? getAuthHeader() : null
43 | }
44 | }))
45 |
46 | // use with apollo-client
47 | const link = middlewareLink.concat(httpLink)
48 | const cache = new InMemoryCache()
49 |
50 | return new ApolloClient({
51 | link,
52 | cache,
53 | ...clientOptions
54 | })
55 | }
56 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Counter/Counter.js:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types"
2 | import React from "react"
3 | import { connect } from "react-redux"
4 |
5 | import {
6 | decrementCounter,
7 | incrementCounter,
8 | loadCounter
9 | } from "../../modules/Counter"
10 | import Styles from "./Counter.css"
11 |
12 | class Counter extends React.Component {
13 | componentDidMount() {
14 | const { counter, load } = this.props
15 |
16 | // Load only client-side
17 | // Use a fallback e.g. when data not available trigger load
18 | return counter == null ? load() : null
19 | }
20 |
21 | fetchData() {
22 | const { counter, load } = this.props
23 |
24 | // Pre-fetch data on the server
25 | return counter == null ? load() : null
26 | }
27 |
28 | render() {
29 | const { counter, handleDecrement, handleIncrement } = this.props
30 | return (
31 |
32 |
Counter
33 |
Value: {counter}
34 |
35 |
36 |
37 | )
38 | }
39 | }
40 |
41 | Counter.propTypes = {
42 | counter: PropTypes.number,
43 | handleIncrement: PropTypes.func,
44 | handleDecrement: PropTypes.func,
45 | load: PropTypes.func
46 | }
47 |
48 | function mapStateToProps(state, ownProps) {
49 | return {
50 | counter: state.counter.value
51 | }
52 | }
53 |
54 | function mapDispatchToProps(dispatch) {
55 | return {
56 | handleIncrement: () => dispatch(incrementCounter()),
57 | handleDecrement: () => dispatch(decrementCounter()),
58 | load: () => dispatch(loadCounter())
59 | }
60 | }
61 |
62 | export default connect(
63 | mapStateToProps,
64 | mapDispatchToProps
65 | )(Counter)
66 |
--------------------------------------------------------------------------------
/packages/edge-webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-webpack",
3 | "version": "0.0.2-alpha.17",
4 | "description": "Centralized Webpack configuration for Edge-based projects.",
5 | "main": "lib/index.cjs.js",
6 | "module": "lib/index.esm.js",
7 | "scripts": {
8 | "test": "jest",
9 | "build": "rimraf lib && preppy",
10 | "prepack": "npm run build"
11 | },
12 | "files": [
13 | "lib/"
14 | ],
15 | "author": {
16 | "name": "Sebastian Software",
17 | "email": "s.werner@sebastian-software.de",
18 | "url": "https://www.sebastian-software.de"
19 | },
20 | "license": "Apache-2.0",
21 | "dependencies": {
22 | "app-manifest-loader": "^2.2.1",
23 | "app-root-dir": "^1.0.2",
24 | "asset-hash": "^2.2.4",
25 | "babel-loader": "^8.0.2",
26 | "cache-loader": "^1.2.2",
27 | "css-loader": "^1.0.0",
28 | "error-overlay-webpack-plugin": "^0.1.5",
29 | "extract-css-chunks-webpack-plugin": "^3.1.1",
30 | "file-loader": "^2.0.0",
31 | "friendly-errors-webpack-plugin": "^1.7.0",
32 | "graphql-tag": "^2.9.2",
33 | "json-loader": "^0.5.7",
34 | "optimize-css-assets-webpack-plugin": "^5.0.1",
35 | "postcss-loader": "^3.0.0",
36 | "source-map-loader": "^0.2.4",
37 | "thread-loader": "^1.2.0",
38 | "uglifyjs-webpack-plugin": "^2.0.1",
39 | "universal-dotenv": "^1.9.1",
40 | "webpack": "^4.19.1",
41 | "webpack-subresource-integrity": "^1.1.0-rc.6",
42 | "yaml-loader": "^0.5.0"
43 | },
44 | "devDependencies": {
45 | "@babel/core": "^7.1.0",
46 | "babel-core": "^7.0.0-0",
47 | "babel-jest": "^23.6.0",
48 | "babel-preset-edge": "^4.13.1",
49 | "jest": "^23.6.0",
50 | "jest-cli": "^23.6.0",
51 | "jest-preset-edge": "^0.2.1-alpha.18",
52 | "preppy": "^4.4.0",
53 | "rimraf": "^2.6.2"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/edge-express/src/createExpressServer.js:
--------------------------------------------------------------------------------
1 | import express from "express"
2 |
3 | import addSecurityMiddleware from "./addSecurityMiddleware"
4 | import addCoreMiddleware from "./addCoreMiddleware"
5 | import addErrorMiddleware from "./addErrorMiddleware"
6 | import addFallbackHandler from "./addFallbackHandler"
7 |
8 | const defaultLocale = {
9 | default: "en-US",
10 | supported: [ "en-US" ]
11 | }
12 |
13 | const defaultStatic = {
14 | public: "/static/",
15 | path: "build/client"
16 | }
17 |
18 | export default function createExpressServer({
19 | localeConfig = defaultLocale,
20 | staticConfig = defaultStatic,
21 | afterSecurity = [],
22 | beforeFallback = []
23 | }) {
24 | // Create our express based server.
25 | const server = express()
26 |
27 | addErrorMiddleware(server)
28 | addSecurityMiddleware(server)
29 |
30 | // Allow for some early additions for middleware
31 | if (afterSecurity.length > 0) {
32 | afterSecurity.forEach((middleware) => {
33 | if (middleware instanceof Array) {
34 | server.use(...middleware)
35 | } else {
36 | server.use(middleware)
37 | }
38 | })
39 | }
40 |
41 | addCoreMiddleware(server, { locale: localeConfig })
42 |
43 | // Configure static serving of our webpack bundled client files.
44 | if (staticConfig) {
45 | server.use(staticConfig.public, express.static(staticConfig.path))
46 | }
47 |
48 | // Allow for some late additions for middleware
49 | if (beforeFallback.length > 0) {
50 | beforeFallback.forEach((middleware) => {
51 | if (middleware instanceof Array) {
52 | server.use(...middleware)
53 | } else {
54 | server.use(middleware)
55 | }
56 | })
57 | }
58 |
59 | // For all things which did not went well.
60 | addFallbackHandler(server)
61 |
62 | return server
63 | }
64 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/readme.md:
--------------------------------------------------------------------------------
1 | # Jest Preset Edge - Advanced Frontend Focussed Jest Configuration
2 |
3 | ## Features
4 |
5 | - Supports CSS Modules using `identity-obj-proxy`.
6 | - Mocks all asset file requirements for e.g. images, fonts, graphql files, ...
7 | - Includes a mock for the native `fetch()` method.
8 | - Polyfills `requestAnimationFrame()` which is required by React v16.
9 | - Configures Date constructors to return a static data which is very helpful for snapshot testing.
10 | - Integrates a mock for HTML5 canvas so that API calls does not throw inside NodeJS (via JSDOM).
11 |
12 | ## Excludes for Coverage
13 |
14 | - Excludes typical *Edge Platform* based application glue code files e.g. `Application.js`, `State.js` and `Init.js`.
15 | - Excludes *Webpack* and generic bundling/package entry points.
16 | - Excludes *Storybook* stories following the `.story.js` naming convention.
17 | - Excludes *Jest* tests following the `.test.js` naming convention or being placed inside a `__tests__` folder.
18 |
19 | ## Usage
20 |
21 | Install via NPM:
22 |
23 | ```
24 | npm install --save-dev jest-preset-edge
25 | ```
26 |
27 | Define the preset inside your own configuration. [Official docs](https://facebook.github.io/jest/docs/en/configuration.html#preset-string):
28 |
29 | ```js
30 | module.exports = {
31 | "preset": "jest-preset-edge"
32 | }
33 | ```
34 |
35 | This works in a `jest.config.js` or in the `package.json` file under the `jest` key.
36 |
37 |
38 |
39 | ## License
40 |
41 | [Apache License Version 2.0, January 2004](license)
42 |
43 |
44 | ## Copyright
45 |
46 |
47 |
48 | Copyright 2017-2018
[Sebastian Software GmbH](http://www.sebastian-software.de)
49 |
--------------------------------------------------------------------------------
/packages/edge-useragent/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-useragent",
3 | "version": "4.0.0-alpha.10",
4 | "description": "High performance user agent string parser for modern environments. Part of the Edge Platform.",
5 | "main": "lib/index.cjs.js",
6 | "module": "lib/index.esm.js",
7 | "keywords": [
8 | "agent",
9 | "browser",
10 | "browserscope",
11 | "os",
12 | "parse",
13 | "parser",
14 | "ua",
15 | "ua-parse",
16 | "ua-parser",
17 | "user agent",
18 | "user",
19 | "user-agent",
20 | "useragent",
21 | "version"
22 | ],
23 | "engines": {
24 | "node": ">=6.0.0",
25 | "yarn": ">=1.0.0",
26 | "npm": ">=4.0.0"
27 | },
28 | "files": [
29 | "bin/",
30 | "docs/",
31 | "lib/"
32 | ],
33 | "author": {
34 | "name": "Sebastian Software",
35 | "email": "s.werner@sebastian-software.de",
36 | "url": "https://www.sebastian-software.de"
37 | },
38 | "license": "Apache-2.0",
39 | "dependencies": {
40 | "@babel/runtime": "^7.0.0",
41 | "lru-cache": "4.1.3",
42 | "tmp": "0.0.x"
43 | },
44 | "devDependencies": {
45 | "@babel/node": "^7.0.0",
46 | "@babel/register": "^7.0.0",
47 | "babel-preset-edge": "4.13.1",
48 | "core-js": "^2.5.7",
49 | "cross-env": "^5.2.0",
50 | "eslint": "5.6.0",
51 | "mocha": "5.2.0",
52 | "preppy": "^4.4.0",
53 | "request": "2.88.0",
54 | "rimraf": "*",
55 | "semver": "5.5.x",
56 | "should": "*",
57 | "yamlparser": "0.0.x"
58 | },
59 | "scripts": {
60 | "lint": "eslint src/",
61 | "test": "cross-env NODE_ENV=test mocha test/*.test.js",
62 | "qa": "cross-env NODE_ENV=test mocha --ui exports test/*.qa.js",
63 | "update": "cross-env NODE_ENV=node babel-node ./bin/update.js && cross-env NODE_ENV=node babel-node ./bin/testfiles.js",
64 | "build": "rimraf lib && preppy",
65 | "prepack": "npm run build"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/packages/edge-core/src/server/renderPage.js:
--------------------------------------------------------------------------------
1 | import serialize from "serialize-javascript"
2 | import Helmet from "react-helmet"
3 |
4 | /**
5 | * Generates a full HTML page containing the render output of the given react element.
6 | *
7 | * @param config {Object} Configuration.
8 | * @param config.state {Object} [{}] The initial state for the redux store which will be used by the
9 | * client to mount the redux store into the desired state.
10 | * @param config.html {string} The rendered HTML content.
11 | * @param config.styles {string} [""] Styles to inject into the page.
12 | * @param config.scripts {string} [""] Scripts to inject into the page.
13 | * @returns The full HTML page in the form of a React element.
14 | */
15 | export default function renderPage({ html, styles, scripts }) {
16 | if (typeof html !== "string" || html.length === 0) {
17 | throw new Error("[EDGE]: RenderPage: Invalid html string!")
18 | }
19 |
20 | if (typeof styles !== "string" || styles.length === 0) {
21 | throw new Error("[EDGE]: RenderPage: Invalid styles string!")
22 | }
23 |
24 | if (typeof scripts !== "string" || scripts.length === 0) {
25 | throw new Error("[EDGE]: RenderPage: Invalid scripts string!")
26 | }
27 |
28 | const helmet = Helmet.renderStatic()
29 | // const inlineCode = `APP_STATE=${serialize(state, { isJSON: true })};`
30 | // const nonceHtml = edge.nonce ? `nonce="${edge.nonce}"` : ""
31 |
32 | const inlineCode = ""
33 | const nonceHtml = ""
34 |
35 | return `
36 |
37 |
38 |
39 | ${helmet.title.toString()}
40 | ${helmet.meta.toString()}
41 | ${helmet.link.toString()}
42 | ${styles}
43 | ${helmet.style.toString()}
44 |
45 |
46 | ${html}
47 |
48 | ${scripts}
49 | ${helmet.script.toString()}
50 |
51 | `
52 | }
53 |
--------------------------------------------------------------------------------
/packages/edge-builder/src/commands/build.js:
--------------------------------------------------------------------------------
1 | import webpack from "webpack"
2 | import { remove } from "fs-extra"
3 | import { promisify } from "bluebird"
4 | import formatWebpackMessages from "react-dev-utils/formatWebpackMessages"
5 | import { notify } from "edge-common"
6 |
7 | import builder from "../builder"
8 |
9 | const removePromise = promisify(remove)
10 |
11 | /* eslint-disable no-console, max-params */
12 | function getWebpackHandler(target, resolve, reject) {
13 | return (fatalError, stats) => {
14 | if (fatalError) {
15 | notify(`Fatal error during compiling ${target}: ${fatalError}`, "error")
16 | return reject()
17 | }
18 |
19 | const rawMessages = stats.toJson({})
20 | const messages = formatWebpackMessages(rawMessages)
21 |
22 | const isSuccessful = !messages.errors.length && !messages.warnings.length
23 | if (isSuccessful) {
24 | notify(`Compiled ${target} successfully!`, "info")
25 | }
26 |
27 | // If errors exist, only show errors.
28 | if (messages.errors.length) {
29 | notify(`Failed to compile ${target}!`, "error")
30 | console.log(messages.errors.join("\n\n"))
31 | return reject()
32 | }
33 |
34 | return resolve()
35 | }
36 | }
37 |
38 | export function buildClient(config = {}) {
39 | const webpackConfig = builder("client", "production", config)
40 |
41 | return new Promise((resolve, reject) => {
42 | webpack(webpackConfig, getWebpackHandler("client", resolve, reject))
43 | })
44 | }
45 |
46 | export function buildServer(config = {}) {
47 | const webpackConfig = builder("server", "production", config)
48 |
49 | return new Promise((resolve, reject) => {
50 | webpack(webpackConfig, getWebpackHandler("server", resolve, reject))
51 | })
52 | }
53 |
54 | export function cleanServer(config = {}) {
55 | return removePromise(config.output.server)
56 | }
57 |
58 | export function cleanClient(config = {}) {
59 | return removePromise(config.output.client)
60 | }
61 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/fixes.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Autoprefixer 1`] = `
4 | ":-webkit-full-screen a{
5 | display:flex
6 | }
7 |
8 | :-moz-full-screen a{
9 | display:flex
10 | }
11 |
12 | :-ms-fullscreen a{
13 | display:-ms-flexbox;
14 | display:flex
15 | }
16 |
17 | :fullscreen a{
18 | display:-ms-flexbox;
19 | display:flex
20 | }"
21 | `;
22 |
23 | exports[`Flexbox Fix 1`] = `
24 | ".elem{
25 | -ms-flex:1 1;
26 | flex:1 1
27 | }"
28 | `;
29 |
30 | exports[`Font Variant 1`] = `
31 | "h2{
32 | -webkit-font-feature-settings:\\"c2sc\\";
33 | font-feature-settings:\\"c2sc\\";
34 | font-variant-caps:small-caps
35 | }
36 |
37 | table{
38 | -webkit-font-feature-settings:\\"lnum\\";
39 | font-feature-settings:\\"lnum\\";
40 | font-variant-numeric:lining-nums
41 | }"
42 | `;
43 |
44 | exports[`Gradient Fix 1`] = `
45 | ".elem{
46 | background-image:linear-gradient(green,rgba(0,128,0,0))
47 | }"
48 | `;
49 |
50 | exports[`Input Style Fixes 1`] = `
51 | "input[type=range]::-webkit-slider-runnable-track{
52 | -webkit-appearance:none;
53 | height:3px
54 | }
55 |
56 | input[type=range]::-moz-range-track{
57 | -moz-appearance:none;
58 | height:3px
59 | }
60 |
61 | input[type=range]::-ms-track{
62 | height:3px
63 | }
64 |
65 | input[type=range]{
66 | -webkit-appearance:none
67 | }
68 |
69 | input[type=range]::-webkit-slider-thumb{
70 | -webkit-appearance:none;
71 | width:16px;
72 | height:8px
73 | }
74 |
75 | input[type=range]::-moz-range-thumb{
76 | -moz-appearance:none;
77 | width:16px;
78 | height:8px
79 | }
80 |
81 | input[type=range]::-ms-thumb{
82 | width:16px;
83 | height:8px
84 | }
85 |
86 | input[type=range]::-moz-focus-outer{
87 | border:0
88 | }"
89 | `;
90 |
91 | exports[`Pseudoelements 1`] = `
92 | "a:before{
93 | color:#ff4136
94 | }"
95 | `;
96 |
97 | exports[`Selector matches() 1`] = `
98 | "p.special,p:first-child{
99 | color:#ff4136
100 | }"
101 | `;
102 |
--------------------------------------------------------------------------------
/packages/jest-preset-edge/setup.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-commonjs, filenames/match-regex */
2 | /* global jest */
3 |
4 | // Make sure that environment variables are available
5 | require("universal-dotenv")
6 |
7 | // Mocking Canvas APIs in a very lean way. We don't really need some
8 | // Cairo based rendering at all in most test scenarios.
9 | require("jest-canvas-mock")
10 |
11 | // Mocking all fetch() calls. Should never depend on any actual network during test.
12 | global.fetch = require("jest-fetch-mock")
13 |
14 | // Rewrite console.log/debug to a mock. This shouldn't be required to run in tests
15 | // and makes test runner output much more calm and focused. We keep warn/error and
16 | // other not so often used methods intact.
17 | console.clear = jest.fn()
18 | console.log = jest.fn()
19 | console.debug = jest.fn()
20 |
21 | // Mock Date.now() so that all values are static
22 | require("jest-mock-now")(new Date("2018-05-17T11:25:51.054Z"))
23 |
24 | // Polyfill for RequestAnimationFrame which is required for React v16
25 | require("raf/polyfill")
26 |
27 | // Making sure that global.URL is supported by loading the Polyfill.
28 | // This is required for some libraries like the MapBox GL API.
29 | if (global.URL == null) {
30 | require("url-polyfill")
31 | }
32 |
33 | // Polyfill for not yet implemented parts of the URL API in NodeJS.
34 | // See also: https://github.com/nodejs/node/issues/16167
35 | if (URL.createObjectURL == null) {
36 | URL.createObjectURL = jest.fn()
37 | URL.revokeObjectURL = jest.fn()
38 | }
39 |
40 | // Mocking for Element Resize Detector which is used for responsive components
41 | // e.g. via React Sizeme. We have to pass the factory as otherwise only the
42 | // root function is mocked which is not enough.
43 | try {
44 | jest.mock("element-resize-detector", () => {
45 | return () => ({
46 | listenTo: jest.fn(),
47 | removeListener: jest.fn(),
48 | removeAllListeners: jest.fn(),
49 | uninstall: jest.fn()
50 | })
51 | })
52 | } catch(error) {}
53 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-boilerplate",
3 | "description": "Edge Boilerplate is a template for modern web applications. Part of the Edge Platform.",
4 | "version": "1.0.0-alpha.34",
5 | "main": "server/index.js",
6 | "author": {
7 | "name": "Sebastian Software",
8 | "email": "s.werner@sebastian-software.de",
9 | "url": "https://www.sebastian-software.de"
10 | },
11 | "bin": {
12 | "server": "bin/server"
13 | },
14 | "files": [
15 | "docs/"
16 | ],
17 | "scripts": {
18 | "dev": "node -r esm src/dev.js",
19 | "build": "prepublish && edge build",
20 | "start": "node bin/server",
21 | "clean": "rimraf bin && rimraf build && rimraf docs",
22 | "test": "jest",
23 | "docs": "npm run styleguide:build && npm run storybook:build",
24 | "storybook": "start-storybook --port 1449 --config-dir ../../node_modules/edge-storybook/lib",
25 | "storybook:build": "rimraf docs/storybook && build-storybook --output-dir docs/storybook --config-dir ../../node_modules/edge-storybook/lib"
26 | },
27 | "keywords": [
28 | "front-end",
29 | "boilerplate",
30 | "webpack",
31 | "react",
32 | "ssr",
33 | "universal",
34 | "graphql",
35 | "apollo"
36 | ],
37 | "license": "Apache-2.0",
38 | "dependencies": {
39 | "edge-common": "^1.0.0-alpha.10",
40 | "edge-express": "^1.0.0-alpha.10",
41 | "http-status-codes": "^1.3.0",
42 | "universal-dotenv": "^1.9.1",
43 | "yn": "^2.0"
44 | },
45 | "devDependencies": {
46 | "@reach/router": "^1.1.1",
47 | "@storybook/react": "^4.0.0-alpha.3",
48 | "cookiesjs": "^2.0.0",
49 | "edge-builder": "^1.0.0-alpha.12",
50 | "edge-core": "^1.0.0-alpha.13",
51 | "edge-postcss": "^1.0.0-alpha.14",
52 | "edge-storybook": "^1.0.0-alpha.32",
53 | "edge-style": "^1.0.0-alpha.14",
54 | "eslint": "^5.6.0",
55 | "esm": "^3.0.84",
56 | "flow": "^0.2.3",
57 | "jest": "^23.6.0",
58 | "jest-preset-edge": "^0.2.1-alpha.18",
59 | "prepublish": "2.2.0",
60 | "react": "^16.5.2",
61 | "react-dom": "^16.5.2"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/views/Localization/Localization.js:
--------------------------------------------------------------------------------
1 | import cookies from "cookiesjs"
2 | import Helmet from "react-helmet"
3 | import PropTypes from "prop-types"
4 | import React from "react"
5 | import { connect } from "react-redux"
6 | import {
7 | FormattedDate,
8 | FormattedNumber,
9 | FormattedRelative,
10 | FormattedTime
11 | } from "react-intl"
12 | import { getLocale } from "edge-core"
13 |
14 | import Styles from "./Localization.css"
15 |
16 | const time = new Date()
17 | const timeDiff = 100000
18 |
19 | function switchLocale(locale) {
20 | cookies({ locale })
21 | window.location.reload()
22 | }
23 |
24 | function Localization({ locale }) {
25 | return (
26 |
27 |
28 |
Locale: {locale}
29 |
30 | -
31 | FormattedNumber:
32 |
33 | -
34 | FormattedNumber:
35 |
36 | -
37 | FormattedDate:
38 |
39 | -
40 | FormattedTime:
41 |
42 | -
43 | FormattedRelative:
44 |
45 |
46 |
Select Locale:
47 |
64 |
65 | )
66 | }
67 |
68 | Localization.propTypes = {
69 | locale: PropTypes.string
70 | }
71 |
72 | function mapStateToProps(state, ownProps) {
73 | return {
74 | locale: getLocale(state)
75 | }
76 | }
77 |
78 | function mapDispatchToProps(dispatch) {
79 | return {}
80 | }
81 |
82 | export default connect(
83 | mapStateToProps,
84 | mapDispatchToProps
85 | )(Localization)
86 |
--------------------------------------------------------------------------------
/packages/edge-express/readme.md:
--------------------------------------------------------------------------------
1 | # Edge Express
[![Sponsored by][sponsor-img]][sponsor] [![Version][npm-version-img]][npm] [![Downloads][npm-downloads-img]][npm] [![Build Status Unix][travis-img]][travis] [![Build Status Windows][appveyor-img]][appveyor] [![Dependencies][deps-img]][deps]
2 |
3 | [sponsor-img]: https://img.shields.io/badge/Sponsored%20by-Sebastian%20Software-692446.svg
4 | [sponsor]: https://www.sebastian-software.de
5 | [deps]: https://david-dm.org/sebastian-software/edge-express
6 | [deps-img]: https://david-dm.org/sebastian-software/edge-express.svg
7 | [npm]: https://www.npmjs.com/package/edge-express
8 | [npm-downloads-img]: https://img.shields.io/npm/dm/edge-express.svg
9 | [npm-version-img]: https://img.shields.io/npm/v/edge-express.svg
10 | [travis-img]: https://img.shields.io/travis/sebastian-software/edge-express/master.svg?branch=master&label=unix%20build
11 | [appveyor-img]: https://img.shields.io/appveyor/ci/swernerx/edge-express/master.svg?label=windows%20build
12 | [travis]: https://travis-ci.org/sebastian-software/edge-express
13 | [appveyor]: https://ci.appveyor.com/project/swernerx/edge-express/branch/master
14 |
15 | Edge Express is a centralized Express-based HTTP server with sophisticated built-in security. Part of the Edge Platform.
16 |
17 | > The Edge Platform helps you focus on business logic rather than dealing with massive tooling, common patterns, complex configurations.
18 |
19 | ## Features
20 |
21 | - Express Security with Helmet and HPP.
22 | - Improved Express Error Handling.
23 | - Custom "setup" and "dynamic" middleware as needed.
24 | - Support for Body-Parser, JSON, Cookies and Static serving out-of-the-box.
25 | - Bundled for Node6 + Node8 (Different Library Outputs).
26 |
27 |
28 | ## Public API
29 |
30 | - `addCoreMiddleware()`
31 | - `addErrorMiddleware()`
32 | - `addFallbackHandler()`
33 | - `addSecurityMiddleware()`
34 | - `createExpressServer()`
35 |
36 |
37 |
38 | ## License
39 |
40 | [Apache License Version 2.0, January 2004](license)
41 |
42 |
43 | ## Copyright
44 |
45 |
46 |
47 | Copyright 2017-2018
[Sebastian Software GmbH](http://www.sebastian-software.de)
48 |
--------------------------------------------------------------------------------
/packages/edge-webpack/src/index.js:
--------------------------------------------------------------------------------
1 | import { resolve } from "path"
2 |
3 | // Basic Configuration Adapter
4 | import { IS_DEVELOPMENT, BUILD_TARGET } from "./config"
5 |
6 | // Individual Feature Modules
7 | import EnvironmentModule from "./modules/Environment"
8 | import LocalesModule from "./modules/Locales"
9 | import ExperienceModule from "./modules/Experience"
10 | import OptimizationModule from "./modules/Optimization"
11 | import RulesModule from "./modules/Rules"
12 | import StaticModule from "./modules/Static"
13 |
14 | import { Hasher } from "asset-hash"
15 |
16 | const node = BUILD_TARGET === "client" ? {
17 | fs: "empty",
18 | __filename: "mock",
19 | __dirname: "mock"
20 | } : null
21 |
22 | // For usage in otherwise pre-defined Webpack environment like Storybook
23 | export const core = (options = {}) => ({
24 | module: {
25 | rules: RulesModule.rules
26 | },
27 |
28 | node,
29 |
30 | stats: ExperienceModule.stats,
31 | serve: ExperienceModule.serve,
32 | devServer: ExperienceModule.devServer,
33 |
34 | plugins: [
35 | ...EnvironmentModule.plugins,
36 | ...LocalesModule.plugins,
37 | ...RulesModule.plugins
38 | ].filter(Boolean)
39 | })
40 |
41 | export const full = (options = {}) => ({
42 | name: EnvironmentModule.name,
43 | mode: EnvironmentModule.mode,
44 | entry: {
45 | main: [ resolve(options.root || process.env.APP_ROOT, `src/${BUILD_TARGET}/index.js`) ]
46 | },
47 |
48 | node,
49 |
50 | output: {
51 | path: resolve(options.root || process.env.APP_ROOT, "dist"),
52 | filename: IS_DEVELOPMENT ? "index.js" : "index.[hash].js",
53 | chunkFilename: IS_DEVELOPMENT ?
54 | "chunk-[name].[chunkhash].js" :
55 | "chunk-[name].[chunkhash].js",
56 | crossOriginLoading: "anonymous",
57 | hashFunction: Hasher,
58 | hashDigest: "base52"
59 | },
60 |
61 | module: {
62 | rules: RulesModule.rules
63 | },
64 |
65 | stats: ExperienceModule.stats,
66 | serve: ExperienceModule.serve,
67 | devServer: ExperienceModule.devServer,
68 |
69 | optimization: OptimizationModule.optimization,
70 |
71 | plugins: [
72 | ...EnvironmentModule.plugins,
73 | ...LocalesModule.plugins,
74 | ...ExperienceModule.plugins,
75 | ...RulesModule.plugins,
76 | ...StaticModule.plugins
77 | ].filter(Boolean)
78 | })
79 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/components/htmlhead/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/modules/Counter.js:
--------------------------------------------------------------------------------
1 | export const SET_COUNTER = "counter/SET"
2 | export const INCREMENT_COUNTER = "counter/INCREMENT"
3 | export const DECREMENT_COUNTER = "counter/DECREMENT"
4 |
5 | /**
6 | * Selector for accessing the counter value from inside the global state.
7 | *
8 | * @param {state} state Global Redux state.
9 | */
10 | export function getCounter(state) {
11 | return state.counter.value
12 | }
13 |
14 | /**
15 | * Action creator for setting the counter value.
16 | *
17 | * @param {number} value New value to set for the counter.
18 | */
19 | export function setCounter(value) {
20 | return { type: SET_COUNTER, value }
21 | }
22 |
23 | /**
24 | * Action creator for incrementing the counter value.
25 | */
26 | export function incrementCounter() {
27 | return { type: INCREMENT_COUNTER }
28 | }
29 |
30 | /**
31 | * Action creator for decrementing the counter value.
32 | */
33 | export function decrementCounter() {
34 | return { type: DECREMENT_COUNTER }
35 | }
36 |
37 | /**
38 | * This somewhat tries to emulate a asyncronous backend request.
39 | */
40 | function mockServerDelay() {
41 | /* eslint-disable no-console */
42 | console.log("Loading counter...")
43 | return new Promise((resolve, reject) => {
44 | setTimeout(() => {
45 | let value = Math.round(Math.random() * 100)
46 | console.log("Received counter:", value)
47 | resolve(value)
48 | }, 100)
49 | })
50 | }
51 |
52 | /**
53 | * Async data loading using redux-thunk.
54 | */
55 | export function loadCounter() {
56 | return (dispatch) =>
57 | mockServerDelay().then((value) => dispatch(setCounter(value)))
58 | }
59 |
60 | const initialState = { value: null }
61 |
62 | /**
63 | * Reducer for all counter relevant action types.
64 | *
65 | * @param previousState Previous state object of this reducer.
66 | * @param {string} action Action to process.
67 | */
68 | export function counterReducer(previousState = initialState, action) {
69 | switch (action.type) {
70 | case SET_COUNTER:
71 | return { ...previousState, value: action.value }
72 |
73 | case INCREMENT_COUNTER:
74 | return { ...previousState, value: previousState.value + 1 }
75 |
76 | case DECREMENT_COUNTER:
77 | return { ...previousState, value: previousState.value - 1 }
78 |
79 | default:
80 | return previousState
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/packages/edge-core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-core",
3 | "version": "1.0.0-alpha.13",
4 | "description": "Core JavaScript Infrastructure for Edge. Part of the Edge Platform.",
5 | "main": "lib/node.es5.cjs.js",
6 | "module": "lib/node.es5.esm.js",
7 | "browser": "lib/browser.es5.esm.js",
8 | "main:es2015": "lib/node.es2015.cjs.js",
9 | "module:es2015": "lib/node.es2015.esm.js",
10 | "browser:es2015": "lib/browser.es2015.esm.js",
11 | "scripts": {
12 | "size": "npm run build",
13 | "test": "jest",
14 | "build": "rimraf lib && prepublish",
15 | "prepack": "npm run build"
16 | },
17 | "engines": {
18 | "node": ">=6.0.0",
19 | "yarn": ">=0.21.3",
20 | "npm": ">=4.0.0"
21 | },
22 | "files": [
23 | "bin/",
24 | "docs/",
25 | "lib/"
26 | ],
27 | "keywords": [
28 | "react",
29 | "apollo",
30 | "graphql",
31 | "intl",
32 | "localization",
33 | "framework"
34 | ],
35 | "author": {
36 | "name": "Sebastian Software",
37 | "email": "s.werner@sebastian-software.de",
38 | "url": "https://www.sebastian-software.de"
39 | },
40 | "license": "Apache-2.0",
41 | "dependencies": {
42 | "apollo-cache-inmemory": "^1.3.0-beta.6",
43 | "apollo-client": "^2.4.2",
44 | "apollo-link-context": "^1.0.9",
45 | "apollo-link-http": "^1.5.5",
46 | "bluebird": "^3.5.2",
47 | "caniuse-lite": "^1.0.30000885",
48 | "chalk": "^2.4.1",
49 | "edge-useragent": "^4.0.0-alpha.10",
50 | "graphql": "^14.0.2",
51 | "identity-obj-proxy": "^3.0.0",
52 | "intl-locales-supported": "^1.0.0",
53 | "lean-intl": "^4.0.2",
54 | "node-fetch": "^2.2.0",
55 | "prop-types": "^15.6.2",
56 | "query-string": "^6.1.0",
57 | "raf": "^3.4.0",
58 | "react": "^16.5.2",
59 | "react-apollo": "^2.1.11",
60 | "react-dom": "^16.5.2",
61 | "react-helmet": "^5.2.0",
62 | "react-intl": "^2.6.0",
63 | "react-redux": "^5.0.7",
64 | "react-test-renderer": "^16.5.2",
65 | "react-tree-walker": "^4.3.0",
66 | "redux": "^4.0.0",
67 | "redux-immutable-state-invariant": "^2.1.0",
68 | "redux-logger": "^3.0.6",
69 | "redux-thunk": "^2.3.0",
70 | "serialize-javascript": "^1.5.0",
71 | "source-map-support": "^0.5.9",
72 | "unfetch": "^4.0.1",
73 | "webpack-flush-chunks": "^2.0.1"
74 | },
75 | "devDependencies": {
76 | "jest": "23.6.0",
77 | "jest-fetch-mock": "^1.6.6",
78 | "prepublish": "2.2.0"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/packages/edge-builder/readme.md:
--------------------------------------------------------------------------------
1 | # Edge Builder
[![Sponsored by][sponsor-img]][sponsor] [![Version][npm-version-img]][npm] [![Downloads][npm-downloads-img]][npm] [![Build Status Unix][travis-img]][travis] [![Build Status Windows][appveyor-img]][appveyor] [![Dependencies][deps-img]][deps]
2 |
3 | [sponsor-img]: https://img.shields.io/badge/Sponsored%20by-Sebastian%20Software-692446.svg
4 | [sponsor]: https://www.sebastian-software.de
5 | [deps]: https://david-dm.org/sebastian-software/edge-builder
6 | [deps-img]: https://david-dm.org/sebastian-software/edge-builder.svg
7 | [npm]: https://www.npmjs.com/package/edge-builder
8 | [npm-downloads-img]: https://img.shields.io/npm/dm/edge-builder.svg
9 | [npm-version-img]: https://img.shields.io/npm/v/edge-builder.svg
10 | [travis-img]: https://img.shields.io/travis/sebastian-software/edge-builder/master.svg?branch=master&label=unix%20build
11 | [appveyor-img]: https://img.shields.io/appveyor/ci/swernerx/edge-builder/master.svg?label=windows%20build
12 | [travis]: https://travis-ci.org/sebastian-software/edge-builder
13 | [appveyor]: https://ci.appveyor.com/project/swernerx/edge-builder/branch/master
14 |
15 | Edge Builder is a build tool for modern web applications. Part of the Edge Platform.
16 |
17 | > The Edge Platform helps you focus on business logic rather than dealing with massive tooling, common patterns, complex configurations.
18 |
19 | ## Features
20 |
21 | - Semi-Automatic Code-Splitting for both CSS and JS.
22 | - Hot Loading for Client and Server using Webpack Multi Compiler Architecture.
23 | - PostCSS powered CSS pipeline with Sass-inspired features.
24 | - CSS Modules for Component Style Isolation.
25 | - Build Caching using Webpacks Cache-Loader.
26 | - Efficient Long-Term-Caching using Hashed File Names.
27 |
28 |
29 | ## Technology
30 |
31 | - [webpack-flush-chunks](https://github.com/faceyspacey/webpack-flush-chunks)
32 | - [react-universal-component](https://github.com/faceyspacey/react-universal-component)
33 | - [extract-css-chunks-webpack-plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin)
34 |
35 |
36 |
37 | ## License
38 |
39 | [Apache License Version 2.0, January 2004](license)
40 |
41 |
42 | ## Copyright
43 |
44 |
45 |
46 | Copyright 2017-2018
[Sebastian Software GmbH](http://www.sebastian-software.de)
47 |
--------------------------------------------------------------------------------
/packages/edge-style/src/OpenType.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-max-type, declaration-colon-newline-after, max-line-length */
2 | html,
3 | body,
4 | table {
5 | font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "pnum" 1, "tnum" 0, "onum" 1, "lnum" 0, "dlig" 0; /* 2. */
6 | }
7 |
8 | /**
9 | * Turn on discretionary ligatures for larger headings
10 | */
11 |
12 | h1,
13 | h2,
14 | h3 {
15 | font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "pnum" 1, "tnum" 0, "onum" 1, "lnum" 0, "dlig" 1;
16 | }
17 |
18 | /**
19 | * 1. Change all letters to uppercase
20 | * 2. Turn on small caps for upper and lowercase letters
21 | */
22 |
23 | abbr {
24 | text-transform: uppercase; /* 1 */
25 | font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "pnum" 1, "tnum" 0, "onum" 1, "lnum" 0, "smcp" 1, "c2sc" 1; /* 2 */
26 | }
27 |
28 | time {
29 | font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "pnum" 1, "tnum" 0, "onum" 1, "lnum" 0;
30 | }
31 |
32 | /*
33 | * Turn off kerning and ligatures,
34 | * Turn on lining, tabular numerals, slashed zero
35 | */
36 |
37 | pre,
38 | kbd,
39 | samp,
40 | code {
41 | font-feature-settings: "kern" 0, "liga" 0, "calt" 1, "dlig" 0, "pnum" 0, "tnum" 1, "onum" 0, "lnum" 1, "zero" 1;
42 | }
43 |
44 | /**
45 | * Turn on proper supercript numerals
46 | */
47 |
48 | sup {
49 | font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "pnum" 1, "tnum" 0, "onum" 1, "lnum" 0, "dlig" 0, "sups" 1;
50 | }
51 |
52 | /**
53 | * Turn on proper subscript numerals
54 | */
55 |
56 | sub {
57 | font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "pnum" 1, "tnum" 0, "onum" 1, "lnum" 0, "dlig" 0, "subs" 1;
58 | }
59 |
60 | /**
61 | * Turns on lining, proportional numerals without clarified zeroes
62 | * TODO: Additional input modes https://developer.mozilla.org/en/docs/Web/HTML/Element/Input#attr-inputmode
63 | */
64 |
65 | input[type="color"],
66 | input[type="date"],
67 | input[type="datetime"],
68 | input[type="datetime-local"],
69 | input[type="number"],
70 | input[type="range"],
71 | input[type="tel"],
72 | input[type="week"] {
73 | font-feature-settings: "kern" 0, "liga" 1, "calt" 1, "pnum" 1, "tnum" 0, "onum" 0, "lnum" 1, "zero" 0;
74 | }
75 |
76 | /* Tables
77 | ========================================================================== */
78 |
79 | /**
80 | * Turns on tabular, lining numerals and slashed zero
81 | */
82 |
83 | tbody,
84 | caption {
85 | font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "pnum" 0, "tnum" 1, "onum" 0, "lnum" 1, "zero" 1;
86 | }
87 |
--------------------------------------------------------------------------------
/packages/edge-style/src/Sanitize.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable selector-max-universal, selector-max-type */
2 |
3 | /**
4 | * Add text decoration inheritance in all browsers.
5 | * Add vertical alignment inheritence in all browsers.
6 | */
7 |
8 | ::before,
9 | ::after {
10 | text-decoration: inherit;
11 | vertical-align: inherit;
12 | }
13 |
14 | /**
15 | * Set `background-repeat: no-repeat` to all elements and pseudo elements.
16 | */
17 |
18 | *,
19 | ::before,
20 | ::after {
21 | background-repeat: no-repeat;
22 | }
23 |
24 | /**
25 | * Remove the list style on navigation lists in all browsers.
26 | */
27 |
28 | nav ol,
29 | nav ul {
30 | list-style: none;
31 | }
32 |
33 | /**
34 | * Change the alignment on media elements in all browers.
35 | */
36 |
37 | audio,
38 | canvas,
39 | iframe,
40 | img,
41 | svg,
42 | video {
43 | vertical-align: middle;
44 | }
45 |
46 | /**
47 | * Change the fill color to match the text color in all browsers.
48 | */
49 |
50 | svg {
51 | fill: currentColor;
52 | }
53 |
54 | /**
55 | * Inherit color and font styling in all browsers.
56 | */
57 |
58 | button,
59 | input,
60 | optgroup,
61 | select,
62 | textarea {
63 | color: inherit;
64 | font: inherit;
65 | line-height: inherit;
66 | }
67 |
68 | /**
69 | * Restore the font weight unset by the previous rule.
70 | */
71 |
72 | optgroup {
73 | /* bold == 700 */
74 | font-weight: 700;
75 | }
76 |
77 | /**
78 | * Change the resize direction on textareas in all browsers.
79 | */
80 |
81 | textarea {
82 | resize: vertical;
83 | }
84 |
85 | /*
86 | * Remove the tapping delay on clickable elements.
87 | */
88 |
89 | a,
90 | area,
91 | button,
92 | input,
93 | label,
94 | select,
95 | summary,
96 | textarea,
97 | [tabindex] {
98 | touch-action: manipulation;
99 | }
100 |
101 | /**
102 | * 1. Inherit style issues with custom selections, per
103 | * robsterlini.co.uk/journal/opentype-and-selection-dont-mix
104 | * 2. Turn on kerning, standard ligatures, and proportional, oldstyle numerals
105 | * Turn off all other ligatures, tabular, lining numerals, and alternates
106 | * Uses same settings for tables
107 | * 3. Hard-codes fallback text selection for issue #18, color is Chrome’s
108 | * per via http://stackoverflow.com/a/16094931/864799
109 | */
110 |
111 | ::selection {
112 | background-color: #accef7; /* 3. */
113 | color: inherit; /* 1. */
114 | text-shadow: inherit; /* 2. */
115 | }
116 |
--------------------------------------------------------------------------------
/packages/edge-builder/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-builder",
3 | "description": "Edge Builder is a build tool for modern web applications. Part of the Edge Platform.",
4 | "version": "1.0.0-alpha.12",
5 | "author": {
6 | "name": "Sebastian Software",
7 | "email": "s.werner@sebastian-software.de",
8 | "url": "https://www.sebastian-software.de"
9 | },
10 | "bin": {
11 | "edge": "bin/edge"
12 | },
13 | "main": "lib/index.cjs.js",
14 | "module": "lib/index.esm.js",
15 | "license": "Apache-2.0",
16 | "scripts": {
17 | "prepack": "npm run build",
18 | "build": "rimraf bin && rimraf lib && prepublish",
19 | "test": "echo"
20 | },
21 | "engines": {
22 | "node": ">=6.0.0",
23 | "yarn": ">=1.0.0",
24 | "npm": ">=4.0.0"
25 | },
26 | "dependencies": {
27 | "app-manifest-loader": "^2.2.1",
28 | "app-root-dir": "^1.0.2",
29 | "babel-loader": "^8.0.2",
30 | "babel-minify-webpack-plugin": "^0.3.1",
31 | "babel-preset-edge": "^4.13.1",
32 | "bluebird": "^3.5.2",
33 | "builtin-modules": "^3.0.0",
34 | "cache-loader": "^1.2.2",
35 | "case-sensitive-paths-webpack-plugin": "^2.1.2",
36 | "chalk": "^2.4.1",
37 | "clipboardy": "^1.2.3",
38 | "css-loader": "^1.0.0",
39 | "edge-common": "^1.0.0-alpha.10",
40 | "extract-css-chunks-webpack-plugin": "^3.1.1",
41 | "file-loader": "^2.0.0",
42 | "fs-extra": "^7.0.0",
43 | "graphql": "^14.0.2",
44 | "graphql-tag": "^2.9.2",
45 | "html-webpack-plugin": "^3.2.0",
46 | "jsome": "^2.5.0",
47 | "json-loader": "^0.5.7",
48 | "lean-nodent-runtime": "^1.0.2",
49 | "loader-utils": "^1.1.0",
50 | "lodash": "^4.17.11",
51 | "meow": "^5.0.0",
52 | "ora": "^3.0.0",
53 | "postcss-loader": "^3.0.0",
54 | "react-dev-utils": "^5.0.2",
55 | "resolve-pkg": "^1.0.0",
56 | "source-map-loader": "^0.2.4",
57 | "stats-webpack-plugin": "^0.7.0",
58 | "uglify-es": "^3.3.10",
59 | "uglifyjs-webpack-plugin": "^2.0.1",
60 | "update-notifier": "^2.5.0",
61 | "webpack": "^4.19.1",
62 | "webpack-bundle-analyzer": "^3.0.2",
63 | "webpack-dev-middleware": "^3.3.0",
64 | "webpack-flush-chunks": "^2.0.1",
65 | "webpack-hot-middleware": "^2.24.0",
66 | "webpack-hot-server-middleware": "^0.5.0",
67 | "webpack-subresource-integrity": "^1.1.0-rc.6",
68 | "worker-loader": "^2.0.0",
69 | "yaml-loader": "^0.5.0",
70 | "yn": "^2.0.0"
71 | },
72 | "devDependencies": {
73 | "jest": "23.6.0",
74 | "prepublish": "2.2.0",
75 | "rimraf": "*"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/layout.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Flow Root 1`] = `
4 | ".selector{
5 | display:flow-root;
6 | -webkit-column-count:1;
7 | -moz-column-count:1;
8 | column-count:1
9 | }"
10 | `;
11 |
12 | exports[`Grid KISS 1`] = `
13 | ".gridTest{
14 | display:grid;
15 | -ms-flex-line-pack:justify;
16 | align-content:space-between;
17 | grid-template:\\"a a\\" 120px \\"b c \\" 1fr \\"e e\\" 60px/30% 1fr
18 | }
19 |
20 | .gridTest>header{
21 | grid-area:a;
22 | -ms-flex-item-align:start;
23 | align-self:start
24 | }
25 |
26 | .gridTest>.sidebar{
27 | grid-area:b
28 | }
29 |
30 | .gridTest>main{
31 | grid-area:c
32 | }
33 |
34 | .gridTest>footer{
35 | grid-area:e;
36 | justify-self:center;
37 | -ms-flex-item-align:end;
38 | align-self:end
39 | }
40 |
41 | @supports not (grid-template-areas:\\"test\\"){
42 | .gridTest{
43 | position:relative;
44 | display:block;
45 | width:100%;
46 | height:100%
47 | }
48 |
49 | .gridTest>*{
50 | position:absolute;
51 | box-sizing:border-box
52 | }
53 |
54 | .gridTest>header{
55 | max-height:120px;
56 | width:100%;
57 | top:0;
58 | left:0
59 | }
60 |
61 | .gridTest>.sidebar,.gridTest>main{
62 | height:calc(100% - 180px);
63 | width:30%;
64 | top:120px;
65 | left:0
66 | }
67 |
68 | .gridTest>main{
69 | width:70%;
70 | left:30%
71 | }
72 |
73 | .gridTest>footer{
74 | transform:translateX(-50%);
75 | max-height:60px;
76 | max-width:100%;
77 | bottom:0;
78 | left:50%
79 | }
80 | }
81 |
82 | @media screen and (min-width:0\\\\0){
83 | .gridTest{
84 | position:relative;
85 | display:block;
86 | width:100%;
87 | height:100%
88 | }
89 |
90 | .gridTest>*{
91 | position:absolute;
92 | box-sizing:border-box
93 | }
94 |
95 | .gridTest>header{
96 | max-height:120px;
97 | width:100%;
98 | top:0;
99 | left:0
100 | }
101 |
102 | .gridTest>.sidebar,.gridTest>main{
103 | height:calc(100% - 180px);
104 | width:30%;
105 | top:120px;
106 | left:0
107 | }
108 |
109 | .gridTest>main{
110 | width:70%;
111 | left:30%
112 | }
113 |
114 | .gridTest>footer{
115 | transform:translateX(-50%);
116 | max-height:60px;
117 | max-width:100%;
118 | bottom:0;
119 | left:50%
120 | }
121 | }"
122 | `;
123 |
124 | exports[`Lost Grid 1`] = `
125 | ".grid{
126 | width:calc(24.975% - 22.5px)
127 | }
128 |
129 | .grid:nth-child(n){
130 | float:left;
131 | margin-right:30px;
132 | clear:none
133 | }
134 |
135 | .grid:last-child{
136 | margin-right:0
137 | }
138 |
139 | .grid:nth-child(12n){
140 | margin-right:0;
141 | float:right
142 | }
143 |
144 | .grid:nth-child(12n+1){
145 | clear:both
146 | }"
147 | `;
148 |
--------------------------------------------------------------------------------
/packages/edge-builder/src/plugins/ChunkNames.js:
--------------------------------------------------------------------------------
1 | import path from "path"
2 | import { getHashDigest } from "loader-utils"
3 |
4 | const WORKING_DIR = process.cwd()
5 | const HASH_TYPE = "sha256"
6 | const DIGEST_TYPE = "base62"
7 | const DIGEST_LENGTH = 4
8 | const SCRIPT_EXTENSIONS = new Set([ ".mjs", ".js", ".jsx", ".ts", ".tsx" ])
9 | const SKIP_FOLDERS = [ "lib", "dist", "src", "build" ]
10 |
11 | function generateChunkName(request, rawRequest) {
12 | // Strip prefixed loader syntax from Webpack
13 | const splittedRequest = request.split("!")
14 | const cleanRequest = splittedRequest[splittedRequest.length - 1]
15 |
16 | // Getting relative path inside working directory
17 | let relative = path.relative(WORKING_DIR, cleanRequest)
18 |
19 | const isExternal = relative.startsWith(`node_modules${ path.sep}`)
20 | if (isExternal) {
21 | // if the module is an DelegatedModule, the rawRequest will be undefined since it does not have this property.
22 | // However, the userRequest property can supplement rawRequest in this situation
23 | relative = rawRequest || request
24 | }
25 |
26 | // Strip useless helper folder structure
27 | SKIP_FOLDERS.forEach((filter) => {
28 | relative = relative.replace(new RegExp("(^|/|\\\\)" + filter + "($|/|\\\\)"), (match, group1) => group1)
29 | })
30 |
31 | // Strip all script file extensions
32 | const fileExt = path.parse(relative).ext
33 | if (SCRIPT_EXTENSIONS.has(fileExt)) {
34 | relative = relative.replace(new RegExp(`${fileExt}$`), "")
35 | }
36 |
37 | let hash = getHashDigest(cleanRequest, HASH_TYPE, DIGEST_TYPE, DIGEST_LENGTH)
38 | let base = path.basename(relative)
39 |
40 | const result = `${base}-${hash}`
41 |
42 | return result
43 | }
44 |
45 | function getFirstModule(iterable) {
46 | for (const entry of iterable) {
47 | return entry
48 | }
49 | }
50 |
51 | export default class ChunkNames
52 | {
53 | constructor({ debug = false }) {
54 | this.debug = debug
55 | }
56 |
57 | apply(compiler)
58 | {
59 | const debug = this.debug
60 |
61 | compiler.plugin("compilation", (compilation) => {
62 | compilation.plugin("optimize", () => {
63 | compilation.chunks.forEach((chunk) => {
64 | const firstModule = getFirstModule(chunk.modulesIterable)
65 | if (firstModule) {
66 | const userRequest = firstModule.userRequest
67 | const rawRequest = firstModule.rawRequest
68 | const oldName = chunk.name
69 | if (userRequest && oldName == null) {
70 | chunk.name = generateChunkName(userRequest, rawRequest)
71 | if (debug) {
72 | console.log("Assigned ChunkName:", chunk.name)
73 | }
74 | }
75 | }
76 | })
77 | })
78 | })
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/packages/edge-postcss/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edge-postcss",
3 | "version": "1.0.0-alpha.14",
4 | "description": "Edge PostCSS is a collection of carefully chosen and configured PostCSS plugins. Part of the Edge Platform.",
5 | "main": "postcss.config.js",
6 | "scripts": {
7 | "build": "rimraf lib && prepublish",
8 | "prepack": "npm run build",
9 | "test": "jest"
10 | },
11 | "engines": {
12 | "node": ">=6.0.0",
13 | "yarn": ">=1.0.0",
14 | "npm": ">=4.0.0"
15 | },
16 | "keywords": [],
17 | "files": [
18 | "bin/",
19 | "docs/",
20 | "lib/"
21 | ],
22 | "author": {
23 | "name": "Sebastian Software",
24 | "email": "s.werner@sebastian-software.de",
25 | "url": "https://www.sebastian-software.de"
26 | },
27 | "license": "Apache-2.0",
28 | "jest": {
29 | "testPathIgnorePatterns": [
30 | "core.js"
31 | ]
32 | },
33 | "dependencies": {
34 | "app-root-dir": "^1.0.2",
35 | "autoprefixer": "^9.1.5",
36 | "lost": "^8.3.0",
37 | "pleeease-filters": "^4.0.0",
38 | "postcss": "^7.0.2",
39 | "postcss-advanced-variables": "^2.3.3",
40 | "postcss-assets": "^5.0.0",
41 | "postcss-at-warn": "^1.0.0",
42 | "postcss-better-colors": "^1.2.2",
43 | "postcss-calc": "^6.0.1",
44 | "postcss-clearfix": "^2.0.1",
45 | "postcss-color-function": "^4.0.1",
46 | "postcss-color-hex-alpha": "^5.0.2",
47 | "postcss-color-hsl": "^2.0.0",
48 | "postcss-color-hwb": "^3.0.0",
49 | "postcss-csso": "^3.0.0",
50 | "postcss-custom-media": "^7.0.2",
51 | "postcss-devtools": "^1.1.1",
52 | "postcss-discard-comments": "^4.0.0",
53 | "postcss-easing-gradients": "^3.0.1",
54 | "postcss-easings": "^2.0.0",
55 | "postcss-flexbugs-fixes": "^4.1.0",
56 | "postcss-flow-root": "0.0.3",
57 | "postcss-font-family-system-ui": "^4.1.0",
58 | "postcss-font-variant": "^4.0.0",
59 | "postcss-gradient-transparency-fix": "^3.0.0",
60 | "postcss-grid-kiss": "^2.1.0",
61 | "postcss-hexrgba": "^1.0.1",
62 | "postcss-import": "^12.0.0",
63 | "postcss-initial": "^3.0.0",
64 | "postcss-input-style": "^1.0.0",
65 | "postcss-magic-animations": "^0.3.0",
66 | "postcss-map": "^0.10.0",
67 | "postcss-media-minmax": "^4.0.0",
68 | "postcss-nested": "^4.1.0",
69 | "postcss-normalize": "^7.0.1",
70 | "postcss-pseudoelements": "^5.0.0",
71 | "postcss-responsive-type": "^1.0.0",
72 | "postcss-sassy-mixins": "^2.1.0",
73 | "postcss-selector-matches": "^4.0.0",
74 | "postcss-smart-asset": "^0.7.4",
75 | "postcss-transform-shortcut": "^2.0.1",
76 | "postcss-will-change": "^3.0.0",
77 | "postcss-zindex": "^4.0.0"
78 | },
79 | "devDependencies": {
80 | "babel-preset-edge": "4.13.1",
81 | "jest": "23.6.0",
82 | "postcss-load-config": "^2.0.0",
83 | "prepublish": "2.2.0",
84 | "rimraf": "*"
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/packages/edge-builder/src/webpack/dev.js:
--------------------------------------------------------------------------------
1 | import formatWebpackMessages from "react-dev-utils/formatWebpackMessages"
2 | import webpack from "webpack"
3 | import webpackDevMiddleware from "webpack-dev-middleware"
4 | import webpackHotMiddleware from "webpack-hot-middleware"
5 | import webpackHotServerMiddleware from "webpack-hot-server-middleware"
6 | import { notify } from "edge-common"
7 | import clipboardy from "clipboardy"
8 |
9 | import configBuilder from "../builder"
10 |
11 | export function createMiddleware(config = {}) {
12 | const clientConfig = configBuilder("client", "development", config)
13 | const serverConfig = configBuilder("server", "development", config)
14 |
15 | const multiCompiler = webpack([ clientConfig, serverConfig ])
16 | const clientCompiler = multiCompiler.compilers[0]
17 |
18 | const devMiddleware = webpackDevMiddleware(multiCompiler, {
19 | // required
20 | publicPath: config.output.public,
21 |
22 | // we have our custom error handling for webpack which offers far better DX
23 | logLevel: "silent"
24 | })
25 |
26 | const hotMiddleware = webpackHotMiddleware(clientCompiler)
27 |
28 | // keeps serverRender updated with arg: { clientStats, outputPath }
29 | const hotServerMiddleware = webpackHotServerMiddleware(multiCompiler, {
30 | serverRendererOptions: {
31 | outputPath: config.output.client
32 | }
33 | })
34 |
35 | return {
36 | middleware: [ devMiddleware, hotMiddleware, hotServerMiddleware ],
37 | multiCompiler
38 | }
39 | }
40 |
41 | export function connectWithWebpack(server, multiCompiler) {
42 | let serverIsStarted = false
43 |
44 | multiCompiler.plugin("invalid", () => {
45 | notify("Compiling...", "info")
46 | })
47 |
48 | multiCompiler.plugin("done", (stats) => {
49 | /* eslint-disable no-console */
50 | const rawMessages = stats.toJson({})
51 | const messages = formatWebpackMessages(rawMessages)
52 |
53 | const isSuccessful = !messages.errors.length && !messages.warnings.length
54 | if (isSuccessful) {
55 | notify("Compiled successfully!", "info")
56 | }
57 |
58 | // If errors exist, only show errors.
59 | if (messages.errors.length) {
60 | notify("Failed to compile!", "error")
61 | console.log(messages.errors.join("\n\n"))
62 | return
63 | }
64 |
65 | // Show warnings if no errors were found.
66 | if (messages.warnings.length) {
67 | notify("Compiled with warnings!", "warn")
68 | console.log(messages.warnings.join("\n\n"))
69 | }
70 |
71 | if (!stats.hasErrors() && !serverIsStarted) {
72 | serverIsStarted = true
73 |
74 | server.listen(process.env.SERVER_PORT, () => {
75 | notify(`Server started at port ${process.env.SERVER_PORT}`, "info")
76 |
77 | clipboardy
78 | .write(`http://localhost:${process.env.SERVER_PORT}`)
79 | .catch((error) => {
80 | // noop
81 | })
82 | })
83 | }
84 | })
85 | }
86 |
--------------------------------------------------------------------------------
/packages/edge-boilerplate/src/Application.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import loadable from "loadable-components"
3 | import { Router } from "@reach/router"
4 | import { IntlProvider } from "react-intl"
5 | import classnames from "classnames/bind"
6 |
7 | import Styles from "./Application.css"
8 | import ViewWrapper from "./components/view/ViewWrapper"
9 |
10 | import HtmlHead from "./components/htmlhead/HtmlHead"
11 | import Navigation from "./components/navigation/Navigation"
12 |
13 | const Classes = classnames.bind(Styles)
14 |
15 | /* eslint-disable no-console */
16 |
17 | function renderIntlProvider(props) {
18 | const { Component, loading, error, ownProps } = props
19 | const { children, locale } = ownProps
20 |
21 | return (
22 |
23 | {children}
24 |
25 |
26 | )
27 | }
28 |
29 | const messages = {
30 | de: loadable(() => import("./messages/de.json"), { render: renderIntlProvider }),
31 | en: loadable(() => import("./messages/en.json"), { render: renderIntlProvider }),
32 | fr: loadable(() => import("./messages/fr.json"), { render: renderIntlProvider }),
33 | es: loadable(() => import("./messages/es.json"), { render: renderIntlProvider })
34 | }
35 |
36 | function IntlWrapper({ locale, children }) {
37 | const MessagesWrapper = messages[locale]
38 | return (
39 | {children}
40 | )
41 | }
42 |
43 |
44 |
45 | const HomeView = loadable(
46 | () => import("./views/Home/Home"),
47 | { render: ViewWrapper }
48 | )
49 |
50 | const CounterView = loadable(
51 | () => import("./views/Counter/Counter"),
52 | { render: ViewWrapper }
53 | )
54 |
55 | const LocalizationView = loadable(
56 | () => import("./views/Localization/Localization"),
57 | { render: ViewWrapper }
58 | )
59 |
60 | const MissingView = loadable(
61 | () => import("./views/Missing/Missing"),
62 | { render: ViewWrapper }
63 | )
64 |
65 | export function prepare(kernel) {
66 | return Promise.all([
67 | ])
68 | }
69 |
70 | /* eslint-disable react/prefer-stateless-function */
71 | class Application extends React.Component {
72 | state = {
73 | alive: false
74 | }
75 |
76 | componentDidMount() {
77 | requestAnimationFrame(() => {
78 | this.setState({
79 | alive: true
80 | })
81 | })
82 | }
83 |
84 | render() {
85 | return (
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | )
102 | }
103 | }
104 |
105 | export default Application
106 |
--------------------------------------------------------------------------------
/packages/edge-builder/src/binary.js:
--------------------------------------------------------------------------------
1 | import meow from "meow"
2 | import chalk from "chalk"
3 | import updateNotifier from "update-notifier"
4 | import Promise from "bluebird"
5 | import clearConsole from "react-dev-utils/clearConsole"
6 |
7 | import { loadConfig, NAME, VERSION } from "edge-common"
8 | import {
9 | buildClient,
10 | buildServer,
11 | cleanClient,
12 | cleanServer
13 | } from "./commands/build"
14 |
15 | import pkg from "../package.json"
16 |
17 | const IS_INTERACTIVE = process.stdout.isTTY
18 |
19 | if (IS_INTERACTIVE) {
20 | clearConsole()
21 | }
22 |
23 | console.log(
24 | `${chalk.bold(
25 | `EDGE ${chalk.green(`v${pkg.version}`)}`
26 | )} running on ${chalk.bold.blue(NAME)}-${VERSION}`
27 | )
28 |
29 | // Parse arguments
30 | const command = meow(
31 | `
32 | Usage:
33 | $ edge
34 |
35 | Options:
36 | --config Path to configuration file.
37 | --verbose, -v Generate verbose output messages.
38 | --quiet, -q Reduce amount of output messages to warnings and errors.
39 |
40 | Commands:
41 | build Build production appliction
42 | build:client Build client part of production application
43 | build:server Build server part of production application
44 | clean Clean up all generated files
45 | `,
46 | {
47 | flags: {
48 | verbose: {
49 | alias: "v",
50 | default: false
51 | },
52 | quiet: {
53 | alias: "q",
54 | default: false
55 | }
56 | }
57 | }
58 | )
59 |
60 | const selectedTasks = command.input
61 | const flags = command.flags
62 |
63 | // Check for updates first
64 | /* eslint-disable no-magic-numbers */
65 | updateNotifier({
66 | pkg,
67 |
68 | // check every hour
69 | updateCheckInterval: 1000 * 60 * 60
70 | }).notify()
71 |
72 | // List of tasks we have available
73 | const availableTasks = [
74 | { task: "clean", commands: [ cleanClient, cleanServer ] },
75 | {
76 | task: "build",
77 | commands: [ cleanClient, cleanServer, buildClient, buildServer ]
78 | },
79 | { task: "build:client", commands: [ cleanClient, buildClient ] },
80 | { task: "build:server", commands: [ cleanServer, buildServer ] }
81 | ]
82 |
83 | // Prevent deprecation messages which should not be displayed to the end user
84 | if (!flags.verbose) {
85 | process.noDeprecation = true
86 | }
87 |
88 | /* eslint-disable no-process-exit, max-depth, no-console */
89 |
90 | function executeCommands(listOfCommands, config) {
91 | /* eslint-disable no-use-extend-native/no-use-extend-native */
92 | return Promise.each(listOfCommands, (item) => item(config))
93 | }
94 |
95 | async function executeTasks() {
96 | const { config } = await loadConfig("edge", flags)
97 |
98 | for (const taskName of selectedTasks) {
99 | for (const taskConfig of availableTasks) {
100 | if (taskConfig.task === taskName) {
101 | try {
102 | await executeCommands(taskConfig.commands, config)
103 | } catch (error) {
104 | console.error(chalk.bold.red(`Failed to execute task: ${taskName}!`))
105 | console.error(error)
106 | process.exit(1)
107 | }
108 | }
109 | }
110 | }
111 | }
112 |
113 | if (selectedTasks.length > 0) {
114 | process.nextTick(executeTasks)
115 | } else {
116 | command.showHelp()
117 | }
118 |
--------------------------------------------------------------------------------
/packages/edge-storybook/readme.md:
--------------------------------------------------------------------------------
1 | # Edge Storybook Config
2 |
3 | This project contains our configuration and the dependencies to simplify usage of Storybook inside applications and components.
4 |
5 | ## Features
6 |
7 | - Babel Preset Edge is built-in so that you are able to use all typical ES features you know from any `edge-builder`-based project.
8 | - Hot Loading to allow straight-forward development of components inside of Storybook.
9 | - Integrated action logger for testing buttons and other interactive components.
10 | - Responsive Panel with device selector for easily accessing common screen resolutions.
11 | - Support for Storyshots to combine your stories with Jest's powerful snapshot testing.
12 | - Webpack has support for CSS Modules and generic URL handling for all typical asset files.
13 | - Wrapped with our typical Intl Provider (Localization) and State Provider (Redux).
14 |
15 | ## Installation / Config
16 |
17 | Install the config using:
18 |
19 | ```
20 | npm install --save-dev edge-storybook
21 | ```
22 |
23 | Then add the following scripts to your `package.json`:
24 |
25 | ```json
26 | "storybook": "start-storybook --port 1449 --config-dir node_modules/edge-storybook/lib",
27 | "storybook:build": "build-storybook --output-dir docs/storybook --config-dir node_modules/edge-storybook/lib",
28 | ```
29 |
30 | We currently default to port `1449` in all our Storybooks, but you can tweak the value as needed.
31 |
32 | ## Create Stories
33 |
34 | Storybook is configured in a way that it automatically adds all stories which match the following pattern: `/\.story\.js$/` e.g. `Button.story.js`
35 |
36 | Stories should be placed inside the component folder for each component and developed alongside e.g.:
37 |
38 | ```
39 | src/components/button/Button.js
40 | src/components/button/Button.css
41 | src/components/button/Button.story.js
42 | src/components/button/Button.test.js
43 | ```
44 |
45 | ## Start Storybook
46 |
47 | To run Storybook run the command `npm run storybook`. When configured as listed above you should be able to see your Storybook at `localhost:1449` inside your preferred browser.
48 |
49 | This is also the ideal environment for development of plain, application-unaware components. One major benefit here is that Storybook sandboxes each demonstrated component from the other available components.
50 |
51 | ## Deploy Demo Environment
52 |
53 | After you have executed `npm run storybook:build` you got a new folder, typically `docs/storybook` which is ready to be published on any static HTML server like Nginx.
54 |
55 | ## Snapshot Testing
56 |
57 | As we configured Storybook for being integrated with Jest's so-called snapshot testing it is pretty straightforward to use this inside your project. Typically you add the following file into your components folder under the name `Stories.test.js`:
58 |
59 | ```js
60 | import initStoryshots from "@storybook/addon-storyshots"
61 |
62 | initStoryshots({
63 | configPath: "./node_modules/edge-storybook/lib"
64 | })
65 | ```
66 |
67 | It makes sense to just use shallow snapshots. That's how Jest normally behaves as well with snapshot tests. You typically do not want to include the fully resolved DOM structure into all snapshots. Testing should end at the boundaries of your components.
68 |
69 |
70 | ## License
71 |
72 | [Apache License Version 2.0, January 2004](license)
73 |
74 |
75 | ## Copyright
76 |
77 |
78 |
79 | Copyright 2017-2018
[Sebastian Software GmbH](http://www.sebastian-software.de)
80 |
--------------------------------------------------------------------------------
/packages/edge-style/readme.md:
--------------------------------------------------------------------------------
1 | # Edge Style
[![Sponsored by][sponsor-img]][sponsor] [![Version][npm-version-img]][npm] [![Downloads][npm-downloads-img]][npm] [![Build Status Unix][travis-img]][travis] [![Build Status Windows][appveyor-img]][appveyor] [![Dependencies][deps-img]][deps]
2 |
3 | [sponsor-img]: https://img.shields.io/badge/Sponsored%20by-Sebastian%20Software-692446.svg
4 | [sponsor]: https://www.sebastian-software.de
5 | [deps]: https://david-dm.org/sebastian-software/edge-style
6 | [deps-img]: https://david-dm.org/sebastian-software/edge-style.svg
7 | [npm]: https://www.npmjs.com/package/edge-style
8 | [npm-downloads-img]: https://img.shields.io/npm/dm/edge-style.svg
9 | [npm-version-img]: https://img.shields.io/npm/v/edge-style.svg
10 | [travis-img]: https://img.shields.io/travis/sebastian-software/edge-style/master.svg?branch=master&label=unix%20build
11 | [appveyor-img]: https://img.shields.io/appveyor/ci/swernerx/edge-style/master.svg?label=windows%20build
12 | [travis]: https://travis-ci.org/sebastian-software/edge-style
13 | [appveyor]: https://ci.appveyor.com/project/swernerx/edge-style/branch/master
14 |
15 | > The Edge Platform helps you focus on business logic rather than dealing with massive tooling, common patterns, complex configurations.
16 |
17 | We know the hassle of adding basic sensible styling to your Single Page Application.
18 | Interestingly there were a lot of seperate libraries and solutions but not a useful combination of all of it.
19 | Edge Style is our take on delivering same basic styling for SPAs.
20 |
21 | ## Features
22 |
23 | - **Normalize**: Based on normalize.css but using the application's customized browerslist: Why add the full normalize if you can only use what's needed?
24 | - **Reset**: Reset of all margins and paddings on block level elements: Layouting is easier when having a blank slate.
25 | - **Sanitize**: Sanitizes typical gotchas and non ideal legacy standards.
26 | - **Box Sizing**: Configures all elements and their shadow elements to use `border-box`.
27 | - **Aria**: Implements some best practises on ARIA markup.
28 | - **OpenType**: Tweaks default behavior of all native elements to use advanced OpenType features where useful.
29 | - **Intl**: Localized configuration for HTML quotes.
30 |
31 | ## Installation
32 |
33 | ```
34 | npm install --save-dev edge-style
35 | ```
36 |
37 | Edge Style requires a PostCSS-based setup where [postcss-normalize](https://github.com/jonathantneal/postcss-normalize) is enabled in the PostCSS configuration.
38 |
39 | Other than that Edge Style works effectively without any further plugins as there is e.g. no selector nesting being used inside the source files. It couldn't hurt to add [autoprefixer](https://github.com/postcss/autoprefixer) though for managing the minimum amount of prefixes required by your [browserslist](http://browserl.ist/).
40 |
41 | ## Usage
42 |
43 | Anywhere in your application code just import the full package. Ideally it should be the first thing to include on the client side. There is no need for integrating it on the server side code (SSR).
44 |
45 | ```js
46 | import "edge-style"
47 | ```
48 |
49 | ## Related
50 |
51 | - [Edge PostCSS](https://github.com/sebastian-software/edge-postcss) is our very own PostCSS plugin configuration which comes with autoprefixer and postcss-normalize built-in.
52 |
53 |
54 |
55 | ## License
56 |
57 | [Apache License Version 2.0, January 2004](license)
58 |
59 |
60 | ## Copyright
61 |
62 |
63 |
64 | Copyright 2017-2018
[Sebastian Software GmbH](http://www.sebastian-software.de)
65 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/Intl.js:
--------------------------------------------------------------------------------
1 | import areIntlLocalesSupported from "intl-locales-supported"
2 | import { addLocaleData } from "react-intl"
3 |
4 | /* global Intl */
5 |
6 | const PREFER_NATIVE = true
7 |
8 | // let intlSupportTable
9 | // if (process.env.TARGET === "node") {
10 | // intlSupportTable = require("caniuse-lite").feature(
11 | // require("caniuse-lite/data/features/internationalization.js")
12 | // )
13 | // }
14 |
15 | export function requiresIntlPolyfill(locale) {
16 | // Determine if the built-in `Intl` has the locale data we need.
17 | if (PREFER_NATIVE && global.Intl && areIntlLocalesSupported([ locale ])) {
18 | return false
19 | }
20 |
21 | // By default Node only ships with basic English locale data. You can however build a
22 | // Node binary with all locale data. We recommend doing this if you control the container
23 | // your Node app runs in, otherwise you'll want to polyfill Intl in Node.
24 | // Via: https://github.com/yahoo/react-intl/wiki#i18n-in-javascript
25 | if (PREFER_NATIVE === false && process.env.TARGET === "node")
26 | {
27 | /* eslint-disable no-console */
28 | console.warn("Your NodeJS installation does not include full ICU locale data! Fallback to polyfill!")
29 | console.warn("See also: https://github.com/nodejs/node/wiki/Intl")
30 | }
31 |
32 | return true
33 | }
34 |
35 | export function installIntlPolyfill() {
36 | const Polyfill = global.IntlPolyfill
37 | if (!Polyfill) {
38 | console.log("Can't find IntlPolyfill global!")
39 | return
40 | }
41 |
42 | // `Intl` exists, but it doesn't have the data we need, so load the
43 | // polyfill and patch the constructors we need with the polyfill's.
44 | if (global.Intl) {
45 | Intl.NumberFormat = Polyfill.NumberFormat
46 | Intl.DateTimeFormat = Polyfill.DateTimeFormat
47 | } else {
48 | global.Intl = Polyfill
49 | }
50 | }
51 |
52 | export function requiresReactIntl() {
53 | // Locale Data in Node.js:
54 | // When using React Intl in Node.js (same for the Intl.js polyfill), all locale data will be
55 | // loaded into memory. This makes it easier to write a universal/isomorphic React app with
56 | // React Intl since you won't have to worry about dynamically loading locale data on the server.
57 | // Via: https://github.com/yahoo/react-intl/wiki#locale-data-in-nodejs
58 |
59 | // As mentioned above no additional data has to be loaded for NodeJS. We are just resolving
60 | // the Promise in that case.
61 | if (process.env.TARGET === "node") {
62 | return false
63 | }
64 |
65 | return true
66 | }
67 |
68 | export function installReactIntl(response) {
69 | if (process.env.TARGET !== "node") {
70 | // It seems like React Intls data files are not correctly dealt with in recent
71 | // Webpack. There is data under the "default" key but it's not a correct ESM module.
72 | let normalizedResponse = response
73 | if (!(response instanceof Array) && response.default) {
74 | normalizedResponse = response.default
75 | }
76 |
77 | addLocaleData(normalizedResponse)
78 | }
79 | }
80 |
81 |
82 | /**
83 | * Selector for quering the current locale e.g. de-DE, en-US, ...
84 | */
85 | export function getLocale(state) {
86 | return state.edge.intl.locale
87 | }
88 |
89 |
90 | /**
91 | * Selector for quering the current language e.g. de, en, fr, es, ...
92 | */
93 | export function getLanguage(state) {
94 | return state.edge.intl.language
95 | }
96 |
97 |
98 | /**
99 | * Selector for quering the current region e.g. DE, BR, PT, ...
100 | */
101 | export function getRegion(state) {
102 | return state.edge.intl.region
103 | }
104 |
--------------------------------------------------------------------------------
/packages/edge-core/src/common/State.js:
--------------------------------------------------------------------------------
1 | import { createStore, combineReducers, applyMiddleware, compose } from "redux"
2 | import thunk from "redux-thunk"
3 |
4 | const composeEnhancers = (process.env.TARGET === "web" &&
5 | process.env.NODE_ENV === "development" &&
6 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose
7 |
8 | /**
9 | * Placeholder for a non active reducer in Redux.
10 | *
11 | * @param previousState {Object} Previous state.
12 | * @param action {string} Action which is being dispatched.
13 | */
14 | export function emptyReducer(previousState = {}, action) {
15 | return previousState
16 | }
17 |
18 |
19 | /**
20 | * Placeholder for a non active middleware in Redux.
21 | *
22 | * @param store {Object} Store object to work with.
23 | */
24 | export function emptyMiddleware(store) {
25 | return (next) => {
26 | return (action) => {
27 | return next(action)
28 | }
29 | }
30 | }
31 |
32 |
33 | /**
34 | * Placeholder for a non active enhancer in Redux.
35 | */
36 | export function emptyEnhancer(param) {
37 | return param
38 | }
39 |
40 |
41 | /**
42 | * Dummy reducer for exporting Edge Platform specific server-side data
43 | * to the client-side application.
44 | */
45 | export function edgeReducer(previousState = {}, action) {
46 | return previousState
47 | }
48 |
49 |
50 |
51 |
52 | /**
53 | * Selector for quering the nonce which must be used for injecting script tags.
54 | */
55 | export function getNonce(state) {
56 | return state.edge.nonce
57 | }
58 |
59 |
60 | /**
61 | * Bundles the given reducers into a root reducer for the application
62 | */
63 | export function createRootReducer(reducers, router = null) {
64 | const allReducers = {
65 | // Application specific reducers
66 | ...reducers,
67 |
68 | // Edge Platform Data
69 | edge: edgeReducer
70 | }
71 |
72 | // Integration point for Redux First Router
73 | if (router) {
74 | allReducers.location = router.reducer
75 | }
76 |
77 | return combineReducers(allReducers)
78 | }
79 |
80 |
81 | /**
82 | *
83 | *
84 | */
85 | export function createReduxStore(config = {}) {
86 | const {
87 | reducers = {},
88 | middlewares = [],
89 | enhancers = [],
90 | state = {},
91 | router = null
92 | } = config
93 |
94 | const rootReducer = createRootReducer(reducers, router)
95 |
96 | const rootEnhancers = composeEnhancers(
97 | applyMiddleware(
98 |
99 | // Redux middleware that spits an error on you when you try to mutate
100 | // your state either inside a dispatch or between dispatches.
101 | // https://github.com/leoasis/redux-immutable-state-invariant
102 | process.env.NODE_ENV === "development" ?
103 | require("redux-immutable-state-invariant").default() : emptyMiddleware,
104 |
105 | // Basic Promise based async handling
106 | thunk,
107 |
108 | // Redux Router First Middleware
109 | router ? router.middleware : emptyMiddleware,
110 |
111 | // Application specific middlewares
112 | ...middlewares,
113 |
114 | // Add automatic state change logging for client application
115 | // Note: Logger must be the last middleware in chain, otherwise it will log thunk and
116 | // promise, not actual actions (https://github.com/evgenyrodionov/redux-logger/issues/20).
117 | process.env.TARGET === "web" ?
118 | require("redux-logger").createLogger({ collapsed: true }) : emptyMiddleware
119 | ),
120 |
121 | // Redux First Router Enhancer
122 | router ? router.enhancer : emptyEnhancer,
123 |
124 | // Application specific enhancers
125 | ...enhancers
126 | )
127 |
128 | const store = createStore(
129 | rootReducer,
130 | state,
131 | rootEnhancers
132 | )
133 |
134 | return store
135 | }
136 |
--------------------------------------------------------------------------------
/packages/edge-postcss/__tests__/__snapshots__/extensions.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Clearfix 1`] = `
4 | ".row:after{
5 | content:'';
6 | display:block;
7 | clear:both
8 | }"
9 | `;
10 |
11 | exports[`Initial - All 1`] = `
12 | "ul{
13 | border-collapse:separate;
14 | border-spacing:0;
15 | caption-side:top;
16 | cursor:auto;
17 | direction:ltr;
18 | empty-cells:show;
19 | font-family:serif;
20 | font-size:medium;
21 | font-style:normal;
22 | -webkit-font-feature-settings:normal;
23 | font-feature-settings:normal;
24 | font-variant:normal;
25 | font-weight:400;
26 | font-stretch:normal;
27 | line-height:normal;
28 | -webkit-hyphens:none;
29 | -ms-hyphens:none;
30 | hyphens:none;
31 | letter-spacing:normal;
32 | list-style:disc outside none;
33 | -moz-tab-size:8;
34 | tab-size:8;
35 | text-align:left;
36 | -moz-text-align-last:auto;
37 | text-align-last:auto;
38 | text-indent:0;
39 | text-shadow:none;
40 | text-transform:none;
41 | visibility:visible;
42 | white-space:normal;
43 | widows:2;
44 | word-spacing:normal;
45 | all:initial
46 | }"
47 | `;
48 |
49 | exports[`Initial 1`] = `
50 | "h1{
51 | font-family:initial
52 | }"
53 | `;
54 |
55 | exports[`Normalize.css 1`] = `
56 | ".before{
57 | color:#ff4136
58 | }
59 |
60 |
61 | /*! normalize.css v9.0.1 | MIT License | github.com/csstools/normalize.css */
62 | html{
63 | line-height:1.15;
64 | -ms-text-size-adjust:100%;
65 | -webkit-text-size-adjust:100%
66 | }
67 |
68 | h1{
69 | font-size:2em;
70 | margin:.67em 0
71 | }
72 |
73 | hr{
74 | box-sizing:content-box;
75 | height:0;
76 | overflow:visible
77 | }
78 |
79 | details,main{
80 | display:block
81 | }
82 |
83 | code,kbd,pre,samp{
84 | font-family:monospace,monospace;
85 | font-size:1em
86 | }
87 |
88 | abbr[title]{
89 | -webkit-text-decoration:underline dotted;
90 | text-decoration:underline dotted
91 | }
92 |
93 | b,strong{
94 | font-weight:bolder
95 | }
96 |
97 | small{
98 | font-size:80%
99 | }
100 |
101 | svg:not(:root){
102 | overflow:hidden
103 | }
104 |
105 | button,input,select{
106 | margin:0
107 | }
108 |
109 | [type=button],[type=reset],[type=submit],button{
110 | -webkit-appearance:button
111 | }
112 |
113 | fieldset{
114 | padding:.35em .75em .625em
115 | }
116 |
117 | button,input{
118 | overflow:visible
119 | }
120 |
121 | legend{
122 | box-sizing:border-box;
123 | color:inherit;
124 | display:table;
125 | max-width:100%;
126 | white-space:normal
127 | }
128 |
129 | progress{
130 | display:inline-block;
131 | vertical-align:baseline
132 | }
133 |
134 | button,select{
135 | text-transform:none
136 | }
137 |
138 | textarea{
139 | margin:0;
140 | overflow:auto
141 | }
142 |
143 | [type=search]{
144 | -webkit-appearance:textfield;
145 | outline-offset:-2px
146 | }
147 |
148 | ::-webkit-inner-spin-button,::-webkit-outer-spin-button{
149 | height:auto
150 | }
151 |
152 | ::-webkit-input-placeholder{
153 | color:inherit;
154 | opacity:.54
155 | }
156 |
157 | ::-webkit-search-decoration{
158 | -webkit-appearance:none
159 | }
160 |
161 | ::-webkit-file-upload-button{
162 | -webkit-appearance:button;
163 | font:inherit
164 | }
165 |
166 | ::-moz-focus-inner{
167 | border-style:none;
168 | padding:0
169 | }
170 |
171 | :-moz-focusring{
172 | outline:1px dotted ButtonText
173 | }
174 |
175 | dialog{
176 | background-color:#fff;
177 | border:solid;
178 | color:#111;
179 | display:block;
180 | height:-moz-fit-content;
181 | height:-webkit-fit-content;
182 | height:fit-content;
183 | left:0;
184 | margin:auto;
185 | padding:1em;
186 | position:absolute;
187 | right:0;
188 | width:-moz-fit-content;
189 | width:-webkit-fit-content;
190 | width:fit-content
191 | }
192 |
193 | dialog:not([open]){
194 | display:none
195 | }
196 |
197 | summary{
198 | display:list-item
199 | }
200 |
201 | template{
202 | display:none
203 | }
204 |
205 | .after{
206 | color:#2ecc40
207 | }"
208 | `;
209 |
210 | exports[`Responsive Type 1`] = `
211 | "html{
212 | font-size:calc(7.60465px + 1.04651vw)
213 | }
214 |
215 | @media screen and (min-width:1280px){
216 | html{
217 | font-size:21px
218 | }
219 | }
220 |
221 | @media screen and (max-width:420px){
222 | html{
223 | font-size:12px
224 | }
225 | }"
226 | `;
227 |
228 | exports[`System UI 1`] = `
229 | "body{
230 | font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue
231 | }"
232 | `;
233 |
--------------------------------------------------------------------------------
/packages/edge-express/src/addSecurityMiddleware.js:
--------------------------------------------------------------------------------
1 | import helmet from "helmet"
2 | import parameterProtection from "hpp"
3 | import uuid from "uuid"
4 |
5 | export default function addSecurityMiddleware(server, { enableNonce = true, enableCSP = true }) {
6 | if (enableNonce) {
7 | /* eslint-disable max-params */
8 |
9 | // Attach a unique "nonce" to every response. This allows use to declare
10 | // inline scripts as being safe for execution against our content security policy.
11 | // @see https://helmetjs.github.io/docs/csp/
12 | server.use((request, response, next) => {
13 | response.locals.nonce = uuid()
14 | next()
15 | })
16 | }
17 |
18 | // Don't expose any software information to hackers.
19 | server.disable("x-powered-by")
20 |
21 | // Prevent HTTP Parameter pollution.
22 | server.use(parameterProtection())
23 |
24 | // Content Security Policy (CSP)
25 | //
26 | // If you are unfamiliar with CSPs then I highly recommend that you do some
27 | // reading on the subject:
28 | // - https://content-security-policy.com/
29 | // - https://developers.google.com/web/fundamentals/security/csp/
30 | // - https://developer.mozilla.org/en/docs/Web/Security/CSP
31 | // - https://helmetjs.github.io/docs/csp/
32 | //
33 | // If you are relying on scripts/styles/assets from other servers (internal or
34 | // external to your company) then you will need to explicitly configure the
35 | // CSP below to allow for this. For example you can see I have had to add
36 | // the polyfill.io CDN in order to allow us to use the polyfill script.
37 | // It can be a pain to manage these, but it's a really great habit to get in
38 | // to.
39 | //
40 | // You may find CSPs annoying at first, but it is a great habit to build.
41 | // The CSP configuration is an optional item for helmet, however you should
42 | // not remove it without making a serious consideration that you do not require
43 | // the added security.
44 | const cspConfig = enableCSP ? {
45 | directives: {
46 | defaultSrc: [ "'self'" ],
47 |
48 | scriptSrc:
49 | [
50 | // Allow scripts hosted from our application.
51 | "'self'",
52 |
53 | // Note: We will execution of any inline scripts that have the following
54 | // nonce identifier attached to them.
55 | // This is useful for guarding your application whilst allowing an inline
56 | // script to do data store rehydration (redux/mobx/apollo) for example.
57 | // @see https://helmetjs.github.io/docs/csp/
58 | (request, response) => `'nonce-${response.locals.nonce}'`,
59 |
60 | // Required for eval-source-maps (devtool in webpack)
61 | process.env.NODE_ENV === "development" ? "'unsafe-eval'" : ""
62 | ].filter((value) => value !== ""),
63 |
64 | styleSrc: [ "'self'", "'unsafe-inline'", "blob:" ],
65 | imgSrc: [ "'self'", "data:" ],
66 | fontSrc: [ "'self'", "data:" ],
67 |
68 | // Note: Setting this to stricter than * breaks the service worker. :(
69 | // I can't figure out how to get around this, so if you know of a safer
70 | // implementation that is kinder to service workers please let me know.
71 | // ["'self'", 'ws:'],
72 | connectSrc: [ "*" ],
73 |
74 | // objectSrc: [ "'none'" ],
75 | // mediaSrc: [ "'none'" ],
76 |
77 | childSrc: [ "'self'" ]
78 | }
79 | } : null
80 |
81 | if (enableCSP) {
82 | server.use(helmet.contentSecurityPolicy(cspConfig))
83 | }
84 |
85 | // The xssFilter middleware sets the X-XSS-Protection header to prevent
86 | // reflected XSS attacks.
87 | // @see https://helmetjs.github.io/docs/xss-filter/
88 | server.use(helmet.xssFilter())
89 |
90 | // Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
91 | // @see https://helmetjs.github.io/docs/frameguard/
92 | server.use(helmet.frameguard("deny"))
93 |
94 | // Sets the X-Download-Options to prevent Internet Explorer from executing
95 | // downloads in your site’s context.
96 | // @see https://helmetjs.github.io/docs/ienoopen/
97 | server.use(helmet.ieNoOpen())
98 |
99 | // Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
100 | // to guess (“sniff”) the MIME type, which can have security implications. It
101 | // does this by setting the X-Content-Type-Options header to nosniff.
102 | // @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
103 | server.use(helmet.noSniff())
104 | }
105 |
--------------------------------------------------------------------------------
/packages/edge-storybook/src/config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
2 | import Cookie from "js-cookie"
3 |
4 | // The "global" import fixes issues accessing globals from outside of the VM
5 | // where this script is running. This is mainly relevant for running Storyshots via Jest.
6 | /* eslint-disable no-global-assign, no-native-reassign */
7 | import global from "global"
8 | import React from "react"
9 | import { addDecorator, configure } from "@storybook/react"
10 | import { addLocaleData, IntlProvider } from "react-intl"
11 |
12 | // Core Reset Styles
13 | import "edge-style"
14 |
15 | // Testing with Storyshots:
16 | // Some components rely on intervals being executed at least once.
17 | // This is also good for test coverage as it hits areas normally not hit when
18 | // intervals are stopped before first execution.
19 | // Note: We can't use Jest's fakeTimers as these snapshots are rendered in a
20 | // different V8 VM where we do not have any access to the Jest API.
21 | if (process.env.NODE_ENV === "test") {
22 | global.setInterval = function fakeSetInterval(callback, timeout) {
23 | callback()
24 | return 0
25 | }
26 |
27 | global.clearInterval = function fakeClearInterval() {
28 | // empty
29 | }
30 | }
31 |
32 | // Activate polyfill for `require.context()` when running inside e.g. Jest/NodeJS
33 | if (process.env.NODE_ENV === "test" && require.context == null) {
34 | /* global __dirname */
35 | require("babel-plugin-require-context-hook/register")()
36 | require.context = function context(directory, useSubdirectories, regExp) {
37 | return global.__requireContext(
38 | __dirname,
39 | directory,
40 | useSubdirectories,
41 | regExp
42 | )
43 | }
44 | }
45 |
46 | // Using same cookie as in our applications which should make it possible
47 | // via some UI to switch between different locales.
48 | let locale =
49 | process.env.NODE_ENV === "test" ?
50 | process.env.APP_DEFAULT_LOCALE :
51 | Cookie.get("locale")
52 |
53 | if (locale == null) {
54 | locale = "en-US"
55 | }
56 |
57 | const language = locale.split("-")[0]
58 |
59 | // In tests we keep things static and just use the default locale
60 | const data = require(`react-intl/locale-data/${language}`)
61 | addLocaleData(data)
62 | console.log("React-Intl loaded data for", language)
63 |
64 | // Loading messages for components from application root "messages" folder
65 | // Expect that these messages are named `${language}.json` or `${locale}.json`.
66 | let messageLoader
67 | try {
68 | messageLoader = require.context(
69 | `${process.env.APP_SOURCE}/messages`,
70 | !1,
71 | /\.json$/
72 | )
73 | } catch(error) {}
74 |
75 | let messages = {}
76 |
77 | if (messageLoader) {
78 | const localeMatcher = new RegExp(`${locale}\\.json$`)
79 | const languageMatcher = new RegExp(`${language}\\.json$`)
80 |
81 | const localeSpecific = messageLoader
82 | .keys()
83 | .filter((messageFile) => localeMatcher.test(messageFile))
84 | const languageSpecific = messageLoader
85 | .keys()
86 | .filter((messageFile) => languageMatcher.test(messageFile))
87 |
88 | const localeData = localeSpecific[0] ? messageLoader(localeSpecific[0]) : {}
89 | const languageData = languageSpecific[0] ?
90 | messageLoader(languageSpecific[0]) :
91 | {}
92 |
93 | // We merge the data from locale and language specific files - if both are avaible.
94 | // Locale specific messages override language only data.
95 | messages = { ...languageData, ...localeData }
96 | }
97 |
98 | // Decorate all stories with localization support so that FormattedMessage, etc. work correctly.
99 | addDecorator((story) => {
100 | return (
101 |
106 | {story()}
107 |
108 | )
109 | })
110 |
111 | // Uses the injected ROOT from our Webpack config to find stories
112 | // relative to the application folder.
113 |
114 | // 1. Require all initializers files e.g. core CSS required for all components, i18n setup, etc.
115 | const initLoader = require.context(process.env.APP_SOURCE, false, /\bInit\.js$/)
116 | const initializers = initLoader.keys().map(initLoader)
117 |
118 | console.log("Loaded", initializers.length, "initializers.")
119 |
120 | // 2. Find and load all stories found somewhere in the application directory.
121 | const storyLoader = require.context(
122 | process.env.APP_SOURCE,
123 | true,
124 | /\.story\.js$/
125 | )
126 | const stories = storyLoader.keys().map(storyLoader)
127 | configure(() => stories, module)
128 |
129 | console.log("Added", stories.length, "stories.")
130 |
--------------------------------------------------------------------------------
/packages/edge-builder/src/plugins/VerboseProgress.js:
--------------------------------------------------------------------------------
1 | /*
2 | MIT License http://www.opensource.org/licenses/mit-license.php
3 | Author Tobias Koppers @sokra
4 | */
5 |
6 | /* eslint-disable no-magic-numbers */
7 |
8 | import ora from "ora"
9 | import { get as getRoot } from "app-root-dir"
10 | import { relative } from "path"
11 |
12 | const ROOT = getRoot()
13 |
14 | export default class VerboseProgress {
15 | constructor({ prefix }) {
16 | this.prefix = prefix
17 | }
18 |
19 | apply(compiler) {
20 | let doneModules = 0
21 | let spinner = null
22 | let lastModule = null
23 | const prefix = this.prefix ? this.prefix + " " : ""
24 |
25 | function display(message) {
26 | if (message !== "") {
27 | spinner.text = prefix + message
28 |
29 | // We somehow have to force rendering otherwise busy Webpack wouldn't let us.
30 | spinner.render()
31 | } else {
32 | spinner.succeed(prefix + "Done!")
33 | }
34 | }
35 |
36 | function moduleDone(module) {
37 | doneModules += 1
38 |
39 | let humanIndex
40 | let humanModuleId = lastModule
41 |
42 | humanIndex = humanModuleId.lastIndexOf(" ")
43 | humanModuleId = humanIndex === -1 ? humanModuleId : humanModuleId.slice(humanIndex + 1, humanModuleId.length)
44 |
45 | humanIndex = humanModuleId.lastIndexOf("!")
46 | humanModuleId = humanIndex === -1 ? humanModuleId : humanModuleId.slice(humanIndex + 1, humanModuleId.length)
47 |
48 | humanIndex = humanModuleId.indexOf("?")
49 | humanModuleId = humanIndex === -1 ? humanModuleId : humanModuleId.slice(0, humanIndex)
50 |
51 | humanModuleId = relative(ROOT, humanModuleId).replace(/^node_modules\//, "~/")
52 |
53 | if (humanModuleId.startsWith('"') && humanModuleId.endsWith('"')) {
54 | humanModuleId = humanModuleId.slice(1, -1)
55 | }
56 |
57 | // Ignore Context Logic Imports
58 | if (humanModuleId.includes("|")) {
59 | return
60 | }
61 |
62 | // Exclude hard to read directly relative modules
63 | if (humanModuleId.startsWith("..")) {
64 | return
65 | }
66 |
67 | if (/^[a-zA-Z0-9\-_/~\.]{0,50}$/.test(humanModuleId)) {
68 | display(`Building Modules ${humanModuleId}...`)
69 | }
70 | }
71 |
72 | compiler.plugin("compilation", (compilation) => {
73 | if (compilation.compiler.isChild()) {
74 | return
75 | }
76 |
77 | doneModules = 0
78 |
79 | spinner = ora({ interval: 16 })
80 | spinner.start()
81 |
82 | display(0, "compiling")
83 |
84 | compilation.plugin("build-module", (module) => {
85 | lastModule = module.identifier()
86 | })
87 |
88 | compilation.plugin("failed-module", moduleDone)
89 | compilation.plugin("succeed-module", moduleDone)
90 |
91 | const syncHooks = {
92 | "seal": "Sealing",
93 | "optimize": "Optimizing",
94 | "optimize-modules-basic": "Optimizing modules",
95 | "optimize-chunks-basic": "Optimizing chunks",
96 | "optimize-chunk-modules": "Optimizing chunk modules",
97 | "optimize-module-order": "Optimizing module order",
98 | "optimize-module-ids": "Optimizing module ids",
99 | "optimize-chunk-order": "Optimizing chunk order",
100 | "optimize-chunk-ids": "Optimizing chunk ids",
101 | "before-hash": "Hashing",
102 | "before-module-assets": "Processing module assets",
103 | "before-chunk-assets": "Processing chunk assets",
104 | "record": "Recording"
105 | }
106 |
107 | Object.keys(syncHooks).forEach((name) => {
108 | let pass = 0
109 | const message = syncHooks[name]
110 | compilation.plugin(name, () => {
111 | if (pass++ > 0) display(message + ` [pass ${pass}]`)
112 | else display(message)
113 | })
114 | })
115 |
116 | compilation.plugin("optimize-tree", (chunks, modules, callback) => {
117 | display("Optimizing tree")
118 | callback()
119 | })
120 |
121 | compilation.plugin("additional-assets", (callback) => {
122 | display("Processing assets")
123 | callback()
124 | })
125 |
126 | compilation.plugin("optimize-chunk-assets", (chunks, callback) => {
127 | display("Optimizing chunk assets")
128 | callback()
129 | })
130 |
131 | compilation.plugin("optimize-assets", (assets, callback) => {
132 | display("Optimizing assets")
133 | callback()
134 | })
135 | })
136 |
137 | compiler.plugin("emit", (compilation, callback) => {
138 | display("Emitting")
139 | callback()
140 | })
141 |
142 | compiler.plugin("done", () => {
143 | display("")
144 | })
145 | }
146 | }
147 |
--------------------------------------------------------------------------------