diff --git a/README.md b/README.md index 2965834..9acd1a8 100644 --- a/README.md +++ b/README.md @@ -1 +1,21 @@ -# Hello World +This package allows rendering of React components into plain HTML to use it in emails. Each directory in `emails` dir corresponds to separate email template. Each email component will receive payload, passed from command line: + +``` +node cli --type= --payload= +``` + +Try `php example.php` for demo. + +# Email component structure + +* `index.js` — required. This file should export the main component, wich will receive payload. +* `fixtures.js` — an optional file exports hash `{featureId: payload, featureId2: payload}`. Use this to create data samples for testing in dev mode. +* `styles.js` — an optional file, that will hold style objects for email components to allow style inlining. +* `messages.intl.json` — an optional file, that exports hash with `{messageId: defaultMessage}` for `react-intl`. + +# Available npm scripts + +* `npm start` — starts app in dev mode. +* `npm run i18n` — collects translations and places in `src/i18n`. +* `npm run build` — builds app for usage in `cli.js`. +* `npm run eslint` — lints source files. diff --git a/package.json b/package.json index dff6a5c..9c8995e 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,9 @@ "homepage": "https://gitlab.com/elyby/email-renderer#README", "scripts": { "start": "rm -rf dist/ && webpack-dev-server --progress --colors", - "up": "npm update", - "test": "karma start ./karma.conf.js", "lint": "eslint ./src", "i18n": "cd ./scripts && ../node_modules/.bin/babel-node i18n-collect.js", - "build": "rm -rf dist/ && NODE_ENV=production webpack --progress --colors", - "render": "" + "build": "rm -rf dist/ && NODE_ENV=production webpack --progress --colors" }, "dependencies": { "babel-polyfill": "^6.3.14", @@ -45,27 +42,13 @@ "babel-preset-react-hmre": "^1.0.1", "babel-preset-stage-0": "^6.3.13", "babel-runtime": "^6.0.0", - "bundle-loader": "^0.5.4", - "css-loader": "^0.23.0", "eslint": "^3.1.1", "eslint-plugin-react": "^6.0.0", - "exports-loader": "^0.6.3", "extract-text-webpack-plugin": "^1.0.0", "file-loader": "^0.9.0", - "html-loader": "^0.4.3", "html-webpack-plugin": "^2.0.0", - "imports-loader": "^0.6.5", "json-loader": "^0.5.4", - "loader-utils": "^0.2.15", - "node-sass": "^3.4.2", - "postcss-import": "^8.1.2", - "postcss-loader": "^0.9.0", - "postcss-scss": "^0.1.8", - "postcss-url": "SleepWalker/postcss-url#switch-to-async-api", - "raw-loader": "^0.5.1", - "sass-loader": "^4.0.0", "scripts": "file:scripts", - "style-loader": "^0.13.0", "url-loader": "^0.5.7", "webpack": "^1.12.9", "webpack-dev-server": "^1.14.0", diff --git a/src/emails/activation/Activation.jsx b/src/emails/activation/Activation.jsx index 2f3a430..68583b9 100644 --- a/src/emails/activation/Activation.jsx +++ b/src/emails/activation/Activation.jsx @@ -2,6 +2,8 @@ export default function Activation() { return (
Activated! +
+
); } diff --git a/webpack-utils/cssUrl.js b/webpack-utils/cssUrl.js deleted file mode 100644 index 2362705..0000000 --- a/webpack-utils/cssUrl.js +++ /dev/null @@ -1,36 +0,0 @@ -// при использовании sass-loader теряется контекст в импортированных модулях -// из-за чего css-loader не может правильно обработать относительные url -// -// препроцессим урлы перед тем, как пропускать их через sass-loader -// урлы, начинающиеся с / будут оставлены как есть - -const cssUrl = require('postcss-url'); -const loaderUtils = require('loader-utils'); - -// /#.+$/ - strip #hash part of svg font url -const urlToRequest = (url) => loaderUtils.urlToRequest(url.replace(/\??#.+$/, ''), true); -const urlPostfix = (url) => { - var idx = url.indexOf('?#'); - - if (idx < 0) { - idx = url.indexOf('#'); - } - - return idx >= 0 ? url.slice(idx) : ''; -}; - -module.exports = function(loader) { - return cssUrl({ - url: (url, decl, from, dirname, to, options, result) => - new Promise((resolve, reject) => - loaderUtils.isUrlRequest(url) ? loader.loadModule(urlToRequest(url), (err, source) => - err ? reject(err) : resolve( - loader.exec(` - var __webpack_public_path__ = '${loader.options.output.publicPath}'; - ${source} - `) + urlPostfix(url) - ) - ) : resolve(url) - ) - }); -}; diff --git a/webpack.config.js b/webpack.config.js index 4588843..cc250a1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,11 +3,7 @@ const path = require('path'); const webpack = require('webpack'); -const loaderUtils = require('loader-utils'); -const ExtractTextPlugin = require('extract-text-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const cssUrl = require('webpack-utils/cssUrl'); -const cssImport = require('postcss-import'); const rootPath = path.resolve('./src'); @@ -15,36 +11,7 @@ const isProduction = process.env.NODE_ENV === 'production'; process.env.NODE_ENV = isProduction ? 'production' : 'development'; -const CSS_CLASS_TEMPLATE = isProduction ? '[hash:base64:5]' : '[path][name]-[local]'; - -const fileCache = {}; - - -const cssLoaderQuery = { - modules: true, - importLoaders: 2, - url: false, - localIdentName: CSS_CLASS_TEMPLATE, - - /** - * cssnano options - */ - sourcemap: !isProduction, - autoprefixer: { - add: true, - remove: true, - browsers: ['last 2 versions'] - }, - safe: true, - // отключаем минификацию цветов, что бы она не ломала такие выражения: - // composes: black from './buttons.scss'; - colormin: false, - discardComments: { - removeAll: true - } -}; - -var webpackConfig = { +const webpackConfig = { entry: { app: path.join(__dirname, 'src') }, @@ -66,20 +33,12 @@ var webpackConfig = { devServer: { host: 'localhost', port: 8080, - // proxy: { - // '/api*': { - // headers: { - // host: config.apiHost.replace(/https?:|\//g, '') - // }, - // target: config.apiHost - // } - // }, hot: true, inline: true, historyApiFallback: true }, - devtool: 'eval', + devtool: isProduction ? 'eval' : false, plugins: [ new webpack.DefinePlugin({ @@ -102,11 +61,6 @@ var webpackConfig = { module: { loaders: [ - { - test: /\.scss$/, - extractInProduction: true, - loader: 'style!css?' + JSON.stringify(cssLoaderQuery) + '!sass!postcss?syntax=postcss-scss' - }, { test: /\.jsx?$/, exclude: /node_modules/, @@ -114,35 +68,19 @@ var webpackConfig = { }, { test: /\.(png|gif|jpg|svg)$/, - loader: 'file', + loader: 'url', query: { name: 'assets/[name].[ext]?[hash]' } }, - { - test: /\.(woff|woff2|ttf)$/, - loader: 'file', - query: { - name: 'assets/fonts/[name].[ext]?[hash]' - } - - }, { test: /\.json$/, exclude: /(intl|font)\.json/, loader: 'json' }, - { - test: /\.html$/, - loader: 'html' - }, { test: /\.intl\.json$/, loader: 'babel!intl!json' - }, - { - test: /\.font\.(js|json)$/, - loader: 'raw!fontgen' } ] }, @@ -151,68 +89,9 @@ var webpackConfig = { alias: { intl: path.resolve('webpack-utils/intl-loader') } - }, - - postcss() { - return [ - cssImport({ - path: rootPath, - addDependencyTo: webpack, - - resolve: ((defaultResolve) => - (url, basedir, importOptions) => - defaultResolve(loaderUtils.urlToRequest(url), basedir, importOptions) - )(require('postcss-import/lib/resolve-id')), - - load: ((defaultLoad) => - (filename, importOptions) => { - if (/\.font.(js|json)$/.test(filename)) { - if (!fileCache[filename] || !isProduction) { - // do not execute loader on the same file twice - // this is an overcome for a bug with ExtractTextPlugin, for isProduction === true - // when @imported files may be processed mutiple times - fileCache[filename] = new Promise((resolve, reject) => - this.loadModule(filename, (err, source) => - err ? reject(err) : resolve(this.exec(source)) - ) - ); - } - - return fileCache[filename]; - } - - return defaultLoad(filename, importOptions); - } - )(require('postcss-import/lib/load-content')) - }), - - cssUrl(this) - ]; } }; -if (isProduction) { - webpackConfig.module.loaders.forEach((loader) => { - if (loader.extractInProduction) { - // remove style-loader from chain and pass through ExtractTextPlugin - const parts = loader.loader.split('!'); - - loader.loader = ExtractTextPlugin.extract( - parts[0], // style-loader - parts.slice(1) // css-loader and rest - .join('!') - .replace(/[&?]sourcemap/, '') - ); - } - }); - - webpackConfig.plugins.push(new ExtractTextPlugin('styles.css', { - allChunks: true - })); - - webpackConfig.devtool = false; -} - if (!isProduction) { webpackConfig.plugins.push( new webpack.HotModuleReplacementPlugin(),