From bfd979958c36ea31b310a0ef4fedf4cbfe5bda9f Mon Sep 17 00:00:00 2001 From: Warren Seymour Date: Tue, 21 Feb 2017 14:49:15 +0000 Subject: [PATCH] feat(webpack): Implement basic webpack config builder --- .gitignore | 1 + .gitlab-ci.yml | 11 ++++ README.md | 39 +++++++++++++ package.json | 66 ++++++++++++++++++++++ webpack/config.js | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 README.md create mode 100644 package.json create mode 100644 webpack/config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..0dc3dce --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,11 @@ +stages: + - deploy + +publish: + before_script: + - npm install semantic-release-gitlab + only: + - master + script: + - $(npm bin)/semantic-release-gitlab + stage: deploy diff --git a/README.md b/README.md new file mode 100644 index 0000000..112d57b --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# BasalPlatten + +BasalPlatten ('Base Plate') is a collection of core components and utilities to help build UIs, the 'Fountainhead' way. + +Much like a 'seed' or 'boilerplate' project, it is intended to offer a 'quick-start' way of initalizing a new project. However, unlike similar projects, it is not intended to be 'forked' each time you start a new project. + +Instead, simply install BasalPlatten as an NPM module: + +```bash +$ npm install --save basalplatten +``` + +BasalPlatten assumes the following architecture and conventions: + +- React + ReactDOM + Webpack2 +- Application written in TypeScript +- Some kind of backend API emitting [HAL](https://tools.ietf.org/html/draft-kelly-json-hal-08) resources +- UI Components using [Ant Design](https://ant.design/docs/react/introduce) +- UI Routing & State Management using [UI Router React](https://ui-router.github.io/react/) + - Plus the [Reactive Extensions plugin](https://github.com/ui-router/rx) + +# Webpack2 Configuration + +Generate a Webpack2-compatible configuration using `basalplatten/webpack/config`: + +```javascript +// webpack.config.js +const {buildConfig} = require('basalplatten/webpack/config'); + +module.exports = buildConfig('myApp'); +``` + +`buildConfig` accepts a second `options` object, which will be merged in with the default options. Alternatively, you may mutate the returned configuration object before exporting it. + +Without any custom options or mutations, the webpack configuration will provide the following: + +- Hot Module Reloading (using React Hot Loader 3.0 Beta 6) +- TypeScript 2.0 (using Awesome TypeScript Loader) + - Entry point: `src/index.tsx` diff --git a/package.json b/package.json new file mode 100644 index 0000000..b217f89 --- /dev/null +++ b/package.json @@ -0,0 +1,66 @@ +{ + "name": "basalplatten", + "version": "0.0.0", + "description": "Core components for building UIs the Fountainhead way", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Warren Seymour", + "license": "MIT", + "dependencies": { + "@types/ramda": "0.0.3", + "@types/react": "^15.0.11", + "@types/react-dom": "^0.14.23", + "@types/react-hot-loader": "^3.0.1", + "@types/uri-templates": "^0.1.28", + "@types/whatwg-fetch": "0.0.33", + "antd": "^2.7.2", + "awesome-typescript-loader": "^3.0.4", + "babel-core": "^6.23.1", + "babel-plugin-import": "^1.1.1", + "babel-preset-es2015": "^6.22.0", + "callsite": "^1.0.0", + "css-loader": "^0.26.1", + "html-webpack-plugin": "^2.28.0", + "less-loader": "^2.2.3", + "ramda": "^0.23.0", + "react": "^15.4.2", + "react-dom": "^15.4.2", + "react-hot-loader": "^3.0.0-beta.6", + "rxjs": "^5.2.0", + "semantic-release-gitlab": "^3.0.2", + "style-ext-html-webpack-plugin": "^2.0.6", + "style-loader": "^0.13.1", + "typescript": "^2.1.6", + "ui-router-react": "^0.4.0", + "ui-router-rx": "^0.2.1", + "uri-templates": "^0.2.0", + "webpack": "^2.2.1", + "webpack-dev-server": "^2.4.1" + }, + "devDependencies": { + "cz-conventional-changelog": "^1.2.0" + }, + "repository": { + "type": "git", + "url": "git+https://gitlab.com/fountainhead/basalplatten.git" + }, + "keywords": [ + "react", + "boilerplate", + "typescript", + "antd", + "ant-design", + "webpack" + ], + "bugs": { + "url": "https://gitlab.com/fountainhead/basalplatten/issues" + }, + "homepage": "https://gitlab.com/fountainhead/basalplatten#README", + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } + } +} diff --git a/webpack/config.js b/webpack/config.js new file mode 100644 index 0000000..4461674 --- /dev/null +++ b/webpack/config.js @@ -0,0 +1,137 @@ +const webpack = require('webpack'); +const path = require('path'); +const callsite = require('callsite'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const StyleExtHtmlWebpackPlugin = require('style-ext-html-webpack-plugin'); +const {defaultsDeep} = require('lodash'); + +const DEFAULT_VENDORS = [ + 'react', + 'react-dom', + 'ui-router-react', + 'ui-router-core', + 'ui-router-rx', + 'moment', + 'lodash', + 'ramda' +]; + +const DEFAULT_VENDORS_DEV = [ + 'react-hot-loader/patch', + 'react-hot-loader' +]; + +module.exports = { + DEFAULT_VENDORS, + DEFAULT_VENDORS_DEV, + + buildConfig(appName, options = {}) { + var stack = callsite(); + var caller = stack[1].getFileName(); + var context = path.dirname(caller); + + return defaultsDeep(options, { + context, + + cache: true, + + entry: { + vendor: [ + ...DEFAULT_VENDORS, + ...DEFAULT_VENDORS_DEV + ], + + [appName]: [ + './src/index.tsx' + ] + }, + + output: { + path: path.join(context, 'dist'), + filename: '[name].js', + publicPath: '/' + }, + + resolve: { + extensions: ['.ts', '.tsx', '.js'] + }, + + plugins: [ + new webpack.NamedModulesPlugin(), + + new webpack.HotModuleReplacementPlugin(), + + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', + filename: 'vendor.bundle.js' + }), + + new webpack.SourceMapDevToolPlugin({ + exclude: 'vendor', + filename: '[name].js.map' + }), + + new HtmlWebpackPlugin({ + template: './src/index.ejs', + cache: false + }), + + new StyleExtHtmlWebpackPlugin({ + minify: true + }) + ], + + module: { + rules: [{ + // All files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'. + test: /\.tsx?$/, + use: [{ + loader: 'react-hot-loader/webpack' + }, { + loader: 'awesome-typescript-loader', + options: { + useBabel: true, + useCache: true, + babelOptions: { + presets: ['es2015'], + plugins: [ + ['import', { + 'libraryName': 'antd', + 'libraryDirectory': 'lib', + 'style': 'css' + }] + ] + } + } + }] + }, { + test: /\.css$/, + use: [ + 'style-loader', + 'css-loader' + ] + }, { + test: /^(?!.*\.inline).*\.less$/, + use: [ + 'style-loader', + 'css-loader', + 'less-loader' + ] + }, { + test: /\.inline\.less$/, + loader: StyleExtHtmlWebpackPlugin.inline('less-loader') + }] + }, + + devServer: { + historyApiFallback: true, + hot: true, + host: "0.0.0.0", + port: 8081, + proxy: { + '/api': 'http://localhost:8080' + } + } + }); + } +};