diff --git a/package.json b/package.json index 58d2a23..a1ff3b1 100644 --- a/package.json +++ b/package.json @@ -40,9 +40,11 @@ "less-loader": "^4.0.3", "node-sass": "^4.5.2", "postcss-loader": "^1.3.3", + "react-hot-loader": "^3.0.0-beta.6", "sass-loader": "^6.0.3", "style-loader": "^0.16.1", "url-loader": "^0.5.8", - "webpack": "^2.3.3" + "webpack": "^2.3.3", + "webpack-dev-server": "^2.4.2" } } diff --git a/server.js b/server.js index 7b11c41..844e0a7 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,25 @@ const Koa = require('koa') const send = require('koa-send') const Router = require('koa-router') +const webpack = require('webpack') +const WebpackDevServer = require('webpack-dev-server') +const config = require('./webpack.dev.config') + +const DEVPORT = 3001 + +new WebpackDevServer(webpack(config), { + publicPath: config.output.publicPath, + hot: true, + quiet: false, + noInfo: true, + stats: { + colors: true + } +}).listen(DEVPORT, 'localhost', function (err, result) { + if (err) { + return console.log(err) + } +}) const app = new Koa() const router = new Router() @@ -9,10 +28,6 @@ router.get('/', async function (ctx) { await send(ctx, 'demo/index.html') }) -router.get('/app.js', async function (ctx) { - await send(ctx, 'build/app.js') -}) - // 线上会使用压缩版本的React,而在开发的时候,我们需要使用react-with-addons来查看错误信息 // 所以这里把React和ReactDOM代理到本地未压缩的文件 router.get('**/react.min.js', async function (ctx) { @@ -22,6 +37,10 @@ router.get('**/react-dom.min.js', async function (ctx) { await send(ctx, 'demo/react-dom.js') }) +router.get('**/*.js(on)?', async function (ctx) { + ctx.redirect(`http://localhost:${DEVPORT}/${ctx.path}`) +}) + app.use(router.routes()) app.listen(3000, function () { diff --git a/src/App.js b/src/App.js new file mode 100644 index 0000000..cfebdfa --- /dev/null +++ b/src/App.js @@ -0,0 +1,19 @@ +import React, { Component } from 'react' + +import '_/styles/index.scss' + +class App extends Component { + constructor(props) { + super(props) + + this.state = {} + } + + render() { + return ( +
Hello world 125.
+ ) + } +} + +export default App diff --git a/src/index.js b/src/index.js index 3951382..28579cb 100644 --- a/src/index.js +++ b/src/index.js @@ -1,20 +1,7 @@ -import React, { Component } from 'react' +import React from 'react' import ReactDOM from 'react-dom' - -import '_/styles/index.scss' - -class App extends Component { - constructor(props) { - super(props) - - this.state = {} - } - - render() { - return ( -
Hello world.
- ) - } -} +import App from './App' ReactDOM.render(, document.getElementById('root')) + +module.hot && module.hot.accept() diff --git a/webpack.dev.config.js b/webpack.dev.config.js new file mode 100644 index 0000000..401d221 --- /dev/null +++ b/webpack.dev.config.js @@ -0,0 +1,113 @@ +const path = require('path') +const webpack = require('webpack') +const autoprefixer = require('autoprefixer') + +module.exports = { + devtool: 'cheap-module-source-map', + entry: { + // 需要编译的入口文件,增加了react-hot-loader的配置 + app: [ + 'react-hot-loader/patch', + 'webpack-dev-server/client?http://localhost:3001', + 'webpack/hot/only-dev-server', + './src/index.js', + ], + }, + output: { + // 输出文件名称规则,这里会生成 'app.js' + filename: '[name].js', + publicPath: '/', + }, + + // 引用但不打包的文件 + externals: { react: 'React', 'react-dom': 'ReactDOM' }, + + plugins: [ + new webpack.HotModuleReplacementPlugin(), + ], + + resolve: { + // 给src目录一个路径,避免出现'../../'这样的引入 + alias: { _: path.resolve(__dirname, 'src') }, + }, + + module: { + rules: [ + { + test: /\.jsx?$/, + use: { + loader: 'babel-loader', + + // 可以在这里配置babelrc,也可以在项目根目录加.babelrc文件 + options: { + + // false是不使用.babelrc文件 + babelrc: false, + + // webpack2 需要设置modules 为false + presets: [ + ['es2015', { modules: false }], + 'react', + ], + + // babel的插件 + plugins: [ + 'react-hot-loader/babel', + 'react-require', + 'transform-object-rest-spread', + ], + }, + }, + }, + + // 这是sass的配置,less配置和sass一样,把sass-loader换成less-loader即可 + // webpack2 使用use来配置loader,并且不支持字符串形式的参数了,必须使用options + // loader的加载顺序是从后向前的,这里是 sass -> postcss -> css -> style + { + test: /\.scss$/, + use: [ + { loader: 'style-loader' }, + + { + loader: 'css-loader', + + // 开启了CSS Module功能,避免类名冲突问题 + options: { + modules: true, + localIdentName: '[name]-[local]', + }, + }, + + { + loader: 'postcss-loader', + options: { + plugins() { + return [ + autoprefixer, + ] + }, + }, + }, + + { + loader: 'sass-loader', + }, + ], + }, + + // 当图片文件大于10KB时,复制文件到指定目录,小于10KB转为base64编码 + { + test: /\.(png|jpg|jpeg|gif)$/, + use: [ + { + loader: 'url-loader', + options: { + limit: 10000, + name: './images/[name].[ext]', + }, + }, + ], + }, + ], + }, +}