1
0
mirror of https://github.com/mgerb/react-starter synced 2026-01-09 16:42:48 +00:00

upgrade to webpack 4 - complete overhaul

This commit is contained in:
2018-03-19 22:19:48 -05:00
parent f4b5cd04a5
commit 85d8a4d76b
22 changed files with 11134 additions and 5818 deletions

View File

@@ -1,3 +1,3 @@
{ {
"presets": ["env", "react", "stage-0"] "presets": ["env", "react"]
} }

View File

@@ -1,17 +1,22 @@
# Starter project for React # Starter project for React
A simplified starter project for react/typescript.
- [Typescript](https://www.typescriptlang.org/) - [Typescript](https://www.typescriptlang.org/)
- [React 16](https://reactjs.org/) - [React 16](https://reactjs.org/)
- [React Router 4](https://reacttraining.com/react-router/) - [React Router 4](https://reacttraining.com/react-router/)
- [Webpack 3](https://webpack.js.org/) - [Webpack 4](https://webpack.js.org/)
- [Yarn](https://yarnpkg.com/lang/en/docs/install/) - [open-color](https://yeun.github.io/open-color/)
## Commands ## Commands
- yarn install - npm install
- yarn start - npm start
http://localhost:8080 http://localhost:8080
## Note ### TODO:
There is currently a bug with yarn not updating package.json when upgrading packages. Fix extract-text-webpack-plugin. Currently getting an error due to the webpack 4 upgrade.
[See more here](https://github.com/yarnpkg/yarn/issues/2042#issuecomment-269601927). Everything still seems fine though.
I added the `update-latest` script in package.json for a temporary fix.
```
Entrypoint undefined = extract-text-webpack-plugin-output-filename
```

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import Wrapper from './Wrapper'; import { Routes } from './routes';
ReactDOM.render(<Wrapper />, document.getElementById('app')); ReactDOM.render(<Routes />, document.getElementById('app'));

View File

@@ -1,41 +0,0 @@
@import '../../scss/variables';
.Navbar__nav {
height: 40px;
border-bottom: 1px solid $light1;
display: flex;
background-color: $gray--lighter;
}
.Navbar__header {
display: flex;
height: 50px;
align-items: center;
justify-content: space-between;
padding-left: 10px;
padding-right: 10px;
background-color: $background;
}
.Navbar__item {
color: $fontPrimary;
text-decoration: none;
width: 100px;
transition: all 0.1s linear;
text-align: center;
line-height: 40px;
&:hover {
color: $fontSecondary;
border-bottom: 2px solid $blue;
}
& + .Navbar__item {
border-left: 1px solid $gray;
}
}
.Navbar__item--active {
color: $fontSecondary;
border-bottom: 2px solid $blue;
}

1
app/components/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './nav-bar/nav-bar';

View File

@@ -0,0 +1,38 @@
@import '~open-color/open-color.scss';
.nav-bar__nav {
height: 40px;
border-bottom: 1px solid $oc-gray-2;
display: flex;
background-color: $oc-gray-7;
}
.nav-bar__header {
color: $oc-gray-2;
display: flex;
height: 50px;
align-items: center;
justify-content: space-between;
padding-left: 10px;
padding-right: 10px;
background-color: $oc-gray-8;
}
.nav-bar__item {
color: $oc-gray-2;
text-decoration: none;
width: 100px;
transition: all 0.1s linear;
text-align: center;
line-height: 40px;
&:hover {
color: $oc-gray-3;
border-bottom: 2px solid $oc-indigo-5;
}
}
.nav-bar__item--active {
color: $oc-gray-3;
border-bottom: 2px solid $oc-indigo-5;
}

View File

@@ -1,21 +1,21 @@
import React from 'react'; import React from 'react';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import './Navbar.scss'; import './nav-bar.scss';
interface Props {} interface Props {}
interface State {} interface State {}
export default class Navbar extends React.Component<Props, State> { export class NavBar extends React.Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
} }
render() { public render(): JSX.Element {
return ( return (
<div className="Navbar"> <div>
<div className="Navbar__header"> <div className="nav-bar__header">
<span>React Starter</span> <span>React Starter</span>
<a href="https://github.com/mgerb/react-webpack2-seed"> <a href="https://github.com/mgerb/react-webpack2-seed">
GitHub GitHub
@@ -23,20 +23,20 @@ export default class Navbar extends React.Component<Props, State> {
</a> </a>
</div> </div>
<div className="Navbar__nav"> <div className="nav-bar__nav">
<NavLink <NavLink
to="/" to="/"
className="Navbar__item" className="nav-bar__item"
exact exact
activeClassName="Navbar__item--active" activeClassName="nav-bar__item--active"
> >
Home Home
</NavLink> </NavLink>
<NavLink <NavLink
to="/new" to="/new"
className="Navbar__item" className="nav-bar__item"
exact exact
activeClassName="Navbar__item--active" activeClassName="nav-bar__item--active"
> >
New New
</NavLink> </NavLink>

View File

@@ -1,3 +1,3 @@
.Home { .home {
padding: 10px; padding: 10px;
} }

View File

@@ -1,18 +1,18 @@
import React from 'react'; import React from 'react';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
import './Home.scss'; import './home.scss';
interface Props extends RouteComponentProps<any> {} interface Props extends RouteComponentProps<any> {}
interface State {} interface State {}
export default class Home extends React.Component<Props, State> { export class Home extends React.Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
} }
render() { public render(): JSX.Element {
return <div className="Home">test 123</div>; return <div className="Home">test 123456</div>;
} }
} }

2
app/pages/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './home/home';
export * from './not-found/not-found';

View File

@@ -1,4 +1,4 @@
.NotFound { .not-found {
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
padding-top: 200px; padding-top: 200px;

View File

@@ -1,18 +1,18 @@
import React from 'react'; import React from 'react';
import { RouteComponentProps } from 'react-router-dom'; import { RouteComponentProps } from 'react-router-dom';
import './NotFound.scss'; import './not-found.scss';
interface Props extends RouteComponentProps<any> {} interface Props extends RouteComponentProps<any> {}
interface State {} interface State {}
export default class NotFound extends React.Component<Props, State> { export class NotFound extends React.Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
} }
public render(): any { public render(): JSX.Element {
return <div className="NotFound">404 Not Found</div>; return <div className="not-found">404 Not Found</div>;
} }
} }

View File

@@ -1,9 +1,8 @@
import React from 'react'; import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Navbar from './components/Navbar/Navbar'; import { NavBar } from './components';
import Home from './pages/Home/Home'; import { Home, NotFound } from './pages';
import NotFound from './pages/NotFound/NotFound';
// styling // styling
import './scss/index.scss'; import './scss/index.scss';
@@ -12,16 +11,16 @@ interface Props {}
interface State {} interface State {}
export default class Wrapper extends React.Component<Props, State> { export class Routes extends React.Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
} }
public render() { public render(): JSX.Element {
return ( return (
<BrowserRouter> <BrowserRouter>
<div> <div>
<Navbar /> <NavBar />
<Switch> <Switch>
<Route exact path="/" component={Home} /> <Route exact path="/" component={Home} />
<Route component={NotFound} /> <Route component={NotFound} />

View File

@@ -1,4 +1,5 @@
@import '~font-awesome/css/font-awesome.css'; @import '~font-awesome/css/font-awesome.css';
@import '~normalize.css/normalize.css'; @import '~normalize.css/normalize.css';
@import './variables.scss'; @import '~open-color/open-color.scss';
@import './style.scss'; @import './style.scss';

View File

@@ -3,8 +3,8 @@ html {
} }
body { body {
color: $fontPrimary; color: $oc-gray-8;
background-color: $white; background-color: $oc-gray-0;
} }
.fa { .fa {
@@ -14,10 +14,10 @@ body {
a { a {
text-decoration: none; text-decoration: none;
color: $fontPrimary; color: $oc-indigo-5;
transition: all 0.1s linear; transition: all 0.1s linear;
&:hover { &:hover {
color: $blue; color: $oc-indigo-4;
} }
} }

View File

@@ -1,15 +0,0 @@
$dark-blue: #1d2938;
$gray: #293341;
$gray--lighter: #3A4553;
$blue: #258de5;
$blue--lighter: saturate(lighten($blue, 10%), 100%);
$green: #39ce83;
$red: #e95779;
$white: #fff;
$light1: #e9eef2;
$background: $dark-blue;
$foreground: #53718a;
$fontPrimary: lighten($gray, 50%);
$fontSecondary: lighten($gray, 60%);

View File

@@ -2,6 +2,7 @@
<head> <head>
<link href="https://fonts.googleapis.com/css?family=Roboto:100" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Roboto:100" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
</head> </head>
<body> <body>

11010
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,44 +6,40 @@
"build": "webpack -p --progress --colors", "build": "webpack -p --progress --colors",
"dev": "webpack --progress --colors --watch", "dev": "webpack --progress --colors --watch",
"c9": "webpack-dev-server --host 0.0.0.0 --port 8080 --inline --history-api-fallback", "c9": "webpack-dev-server --host 0.0.0.0 --port 8080 --inline --history-api-fallback",
"lint": "tslint --project .",
"start": "webpack-dev-server --inline --history-api-fallback", "start": "webpack-dev-server --inline --history-api-fallback",
"update-latest": "rm -rf node_modules && rm yarn.lock && ncu --upgrade --upgradeAll && yarn install" "update-latest": "rm -rf node_modules && rm yarn.lock && ncu --upgrade --upgradeAll && yarn install"
}, },
"author": "Mitchell Gerber", "author": "Mitchell Gerber",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/react": "^16.0.34", "@types/react": "^16.0.40",
"@types/react-dom": "^16.0.3", "@types/react-dom": "^16.0.4",
"@types/react-router-dom": "^4.2.3", "@types/react-router-dom": "^4.2.5",
"autoprefixer": "^7.2.4", "babel-loader": "^7.1.4",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1", "clean-webpack-plugin": "^0.1.19",
"clean-webpack-plugin": "^0.1.17", "css-loader": "^0.28.11",
"css-loader": "^0.28.7", "extract-text-webpack-plugin": "^4.0.0-beta.0",
"extract-text-webpack-plugin": "3.0.2", "file-loader": "^1.1.11",
"file-loader": "^1.1.6",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"html-webpack-plugin": "^2.30.1", "html-webpack-plugin": "^3.0.7",
"node-sass": "^4.7.2", "node-sass": "^4.7.2",
"normalize.css": "^7.0.0", "normalize.css": "^8.0.0",
"postcss-loader": "^2.0.9", "open-color": "^1.6.3",
"prettier": "^1.9.2", "postcss-loader": "^2.1.2",
"react": "^16.2.0", "react": "^16.2.0",
"react-dom": "^16.2.0", "react-dom": "^16.2.0",
"react-router-dom": "^4.2.2", "react-router-dom": "^4.2.2",
"resolve-url-loader": "^2.2.1", "sass-loader": "^6.0.7",
"sass-loader": "^6.0.6", "style-loader": "^0.20.3",
"style-loader": "^0.19.1", "ts-loader": "^4.1.0",
"ts-loader": "^3.2.0", "tslint": "^5.9.1",
"tslint": "^5.8.0", "tslint-config-airbnb": "^5.8.0",
"tslint-config-airbnb": "^5.4.2", "typescript": "^2.7.2",
"typescript": "^2.6.2", "webpack": "^4.1.1",
"url-loader": "^0.6.2", "webpack-cli": "^2.0.12",
"webpack": "3.10.0", "webpack-dev-server": "^3.1.1"
"webpack-dev-server": "2.9.7"
} }
} }

View File

@@ -1,6 +1,10 @@
{ {
"extends": "tslint-config-airbnb", "extends": "tslint-config-airbnb",
"rules": { "rules": {
"import-name": false "import-name": false,
"ter-arrow-parens": [true, "as-needed"],
"align": [true, "parameters", "statements"],
"typedef": [true, "call-signature", "parameter", "member-variable-declaration"],
"member-access": [true]
} }
} }

View File

@@ -7,7 +7,6 @@ const webpack = require('webpack');
module.exports = { module.exports = {
entry: { entry: {
app: './app/app.tsx', app: './app/app.tsx',
vendor: ['react', 'react-dom'],
}, },
output: { output: {
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
@@ -47,12 +46,18 @@ module.exports = {
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: 'static/[name].[hash].[ext]', name: 'static/[name].[hash].[ext]',
} },
}, },
], ],
}, },
], ],
}, },
optimization: {
occurrenceOrder: true,
splitChunks: {
chunks: 'all',
},
},
plugins: [ plugins: [
new CleanWebpackPlugin(['dist'], { new CleanWebpackPlugin(['dist'], {
verbose: true, verbose: true,
@@ -60,16 +65,12 @@ module.exports = {
new ExtractTextPlugin({ new ExtractTextPlugin({
filename: '[name].[hash].css', filename: '[name].[hash].css',
disable: false, disable: false,
allChunks: true allChunks: true,
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: 'index.html', filename: 'index.html',
template: './index.html', template: './index.html',
}), }),
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor', 'manifest'],
minChunks: 'Infinity',
}),
new webpack.HotModuleReplacementPlugin(), new webpack.HotModuleReplacementPlugin(),
], ],
}; };

5686
yarn.lock

File diff suppressed because it is too large Load Diff