react-webpack 2 - 完整配置案例
源碼
webpack 開發跨域問題解決
react16 + react-router4 + webpack開發環境搭建 1.先定義一些配置常量 /webpack/config.js
// 引入 node.js path 模組 const path = require('path'); // sass-loader 的 配置 exports.sassLoaderConfig = '?outputStyle=expanded'; // 公用檔案 exports.vendor = [ 'react', 'react-dom', 'react-redux', 'react-router', 'react-router-redux', 'redux', 'redux-thunk' ]; // css 代碼自動補全配置 exports.autoConfig = { browsers: [ 'ie >= 9', 'ie_mob >= 10', 'ff >= 30', 'chrome >= 34', 'safari >= 7', 'opera >= 23', 'ios >= 7', 'android >= 4.4', 'bb >= 10' ], cascade: true, remove: true }; // js 壓縮 配置 exports.uglifyJsConfig = { beautify: false, // 不美化輸出 compress: { warnings: false, // 不保留警告 drop_debugger: true, // 不保留調試語句 drop_console: true // 不保留控制台輸出資訊 }, mangle: { // 跳過這些,不改變命名 except: ['$super', '$', 'exports', 'require'] }, space_colon: false, comments: false // 不保留注釋 }; // 定義 檔案路徑 註:檔案在 根目錄下的 webpack 檔案夾下 const ROOT_PATH = path.resolve(__dirname, '../'); exports.defPath = { ROOT_PATH: ROOT_PATH, APP_PATH: path.resolve(ROOT_PATH, 'app'), DEV_PATH: path.resolve(ROOT_PATH, 'dev'), BUILD_PATH: path.resolve(ROOT_PATH, 'build'), TPL_PATH: path.resolve(ROOT_PATH, 'app/tpl.html'), ENTRY_PATH: path.resolve(ROOT_PATH, 'app/js/index.js'), ESLINT_PATH: path.resolve(ROOT_PATH, './.eslintrc'), REQUEST_PATH: path.resolve(ROOT_PATH, 'app/js/utils/request') }
2.定義不同環境變數下的 應用請求配置
// `npm install ip` 擷取本機 ip 用於設定管理員 const ip = require('ip').address(); module.exports = { test: 'http://xxx.xxx', development: 'http://' + ip + ':3003', production: 'http://xxx.xxx' };
定義公用的配置 /webpack/base.js
const webpack = require('webpack'); const autoprefixer = require('autoprefixer'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const config = require('./config'); // 引入配置 const API = require('./API'); const defPath = config.defPath; const APP_PATH = defPath.APP_PATH; // 源碼目錄 module.exports = function () { return { context: defPath.ROOT_PATH, // 設定跟目錄為執行環境 resolve: { // 解析模組請求的選項 modules: [ APP_PATH, 'node_modules' ], // 用於尋找模組的目錄 extensions: [ '.js', '.json', '.jsx', '.css' ] // 使用的副檔名 }, cache: true, // 啟用緩衝 module: { // 公用的載入器 rules: [ { enforce: 'pre', // 前置執行 test : /\.(js|jsx)$/, include : APP_PATH, loader : 'eslint-loader', options: { configFile: defPath.ESLINT_PATH // 指定 eslint 的設定檔路徑 } }, { test: /\.(js|jsx)$/, include: APP_PATH, loader: 'babel-loader' }, { // 嚮應用特定檔案中注入變數,應用中可以直接使用 baseUrl test: require.resolve(defPath.REQUEST_PATH), loader: 'imports-loader?baseUrl=>'+ JSON.stringify( API[ process.env.NODE_ENV || 'development' ] ) } ] }, plugins: [ // autoprefixer 是 postcss-loader 的 外掛程式,需要在這裡進行 autoprefixer 外掛程式的配置 new webpack.LoaderOptionsPlugin({ options: { context: '/', minimize: true, postcss: [autoprefixer(config.autoConfig)] } }), // 依照模板產生 html new HtmlWebpackPlugin({ template: defPath.TPL_PATH, title: 'Hello World app', filename: 'index.html', inject: 'body', minify: { removeComments: true }, cache: false }) ] } }
開發環境的 webpack 配置 /webpack.dev.config.js
const webpackMerge = require('webpack-merge'); const webpack = require('webpack'); const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin'); const ip = require('ip').address(); const baseConfig = require('./webpack/base'); const config = require('./webpack/config'); const defPath = config.defPath; const APP_PATH = defPath.APP_PATH; // 使用 `webpack-merge` 將基礎配置和新配置合并 module.exports = webpackMerge(baseConfig(), { devtool: 'cheap-module-source-map', // 增強瀏覽器調試 entry: { // 入口 app: [ // 熱載入配置 'react-hot-loader/patch', 'webpack-dev-server/client?http://' + ip + ':8090', 'webpack/hot/only-dev-server', './app/js/index.js' ], vendor: config.vendor // 公用檔案單獨打包 }, output: { // 出口 path: defPath.DEV_PATH, // 所有輸出檔案的目標路徑 // 所有輸出檔案的目標路徑 filename: 'js/bundle.js', // 輸出檔案命名 publicPath: '/', // 必須寫,且與 devServer 的 publicPath 保持一致 chunkFilename: '[name].chunk.js' // 區塊檔案命名 }, module: { rules: [ // 配置載入器 { test: /\.(scss|sass|css)$/, include: APP_PATH, // 必須匹配選項 use: [ // 2.x 版本改為 use 代替 loaders,必須加 -loader 'style-loader', 'css-loader', 'postcss-loader', 'sass-loader' + config.sassLoaderConfig ] }, { test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif|mp4|webm)(\?\S*)?$/, include: APP_PATH, loader: 'url-loader?limit=8192&name=imgs/[name].[ext]' } ] }, plugins: [ // 熱模組替換相關外掛程式 new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), // 定義環境變數 new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('development') }), /* 公用模組單獨打包,對應 入口檔案 vendor, 持久化緩衝配置 */ new webpack.optimize.CommonsChunkPlugin({ names: [ // 提取公用模組名稱 'vendor', 'manifest' // manifest 用於分離 webpack runtime ], filename: 'js/[name].js', // 公用模組檔案名稱 minChunks: Infinity // Infinity 表示僅僅建立公用組件塊,不會把任何modules打包進去。 }), new ChunkManifestPlugin({ // 將 manifest 提取到一個單獨的 JSON 檔案中 filename: 'chunk-manifest.json', manifestVariable: 'webpackManifest' // 全域變數的名稱,webpack 將利用它尋找 manifest JSON 對象 }) ], devServer: { // 開啟伺服器 contentBase: defPath.DEV_PATH, publicPath: '/', historyApiFallback: true, clientLogLevel: 'none', host: ip, port: 8090, open: true, hot: true, inline: true, compress: true, stats: { colors: true, errors: true, warnings: true, modules: false, chunks: false } } })
生產環境 webpack 配置 /webpack.prod.config.js
const webpackMerge = require('webpack-merge'); const webpack = require('webpack'); const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const WebpackMd5Hash = require('webpack-md5-hash'); const baseConfig = require('./webpack/base'); const config = require('./webpack/config'); const defPath = config.defPath; const APP_PATH = defPath.APP_PATH; module.exports = webpackMerge(baseConfig(), { entry: { app: defPath.ENTRY_PATH, vendor: config.vendor }, output: { path: defPath.BUILD_PATH, // 所有輸出檔案的目標路徑 filename: 'js/bundle.js?[chunkhash]', publicPath: 'http://xxx.xxx', // 修改成發布的地址 chunkFilename: 'chunk.js?[chunkhash]' }, module: { rules: [ { test: /\.(scss|sass|css)$/, include: APP_PATH, use: ExtractTextPlugin.extract({ // css 單獨打包,(2.x 改變很大) fallback: 'style-loader', use: 'css-loader!postcss-loader!sass-loader' + config.sassLoaderConfig }) }, { test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif|mp4|webm)(\?\S*)?$/, include: APP_PATH, loader: 'url-loader?limit=8192&name=imgs/[name].[ext]?[hash]' } ] }, plugins: [ new WebpackMd5Hash(), // 取代標準webpack chunkhash new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }), // js 壓縮 new webpack.optimize.UglifyJsPlugin(config.uglifyJsConfig), new webpack.optimize.CommonsChunkPlugin({ names: [ 'vendor', 'manifest' ], filename: 'js/[name].js?[chunkhash]', minChunks: Infinity }), new ChunkManifestPlugin({ filename: 'chunk-manifest.json', manifestVariable: 'webpackManifest' }), // css 抽取 new ExtractTextPlugin({ filename: 'css/styles.css?[contenthash]', disable: false, allChunks: true }) ] })
對應的 babel 配置 /.babelrc
{ "presets": [ ["es2015", { "modules": false }], "stage-2", "react" ], "plugins": [ "react-hot-loader/babel", "transform-object-assign", "transform-decorators-legacy" ], "env": { "development": { "plugins": [ "react-hot-loader/babel" ] } } }
重要外掛程式版本列表
{ "webpack": "^2.2.1", "webpack-dev-server": "^2.4.1", "webpack-md5-hash": "0.0.5", "webpack-merge": "^4.0.0", "chunk-manifest-webpack-plugin": "^1.0.0", "extract-text-webpack-plugin": "^2.1.0", "html-webpack-plugin": "^2.28.0", "react-hot-loader": "^3.0.0-beta.6",}