webpack 4.x + react v.16.12.0 项目配置

从零开始搭建一个React(v16.12.0) + webpack(v4.x)的项目

默认安装了node环境。

初始化项目目录

  • 在命令行中执行
mkdir react-practice
cd react-practice
npm init -y
  • 在 react-practice下创建webpack.config.js文件
// windows系统命令
type null>webpack.config.js

构建项目目录及安装react react-dom

  webpack-practice
  |- package.json
+ |- index.html
+ |- /src
+   |- index.js
npm install -S react react-dom

安装

npm install -D webpack webpack-cli

修改package.json 中 配置 scripts

"scripts": {
  "start": "webpack --config webpack.config.js"
},

--config 后面指定的是配置文件,默认文件是 webpack.config.js,使用默认文件可以省略,如果是其他文件名必须使用--config指定文件

配置webpack

  • webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  mode: 'development',
  entry: {      
    app: "./src/index.js"
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].js'
  }
}

在 src/index.js中输入一下js代码, 执行npm start , 可以看到 根目录下生成了一个dist目录,目录下有个app.js

打包后自动生成html文件

我们需要使用一个插件 html-webpack-plugin

npm install -D html-webpack-plugin

在 webpack.config.js中添加

+ const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
+  plugins: [
+    new HtmlWebpackPlugin({
+      title: 'react-practice',
+      filename: 'index.html',
+      template: 'index.html'
+    })
+  ]
}

删除刚刚生成的dist目录,再次执行 npm start ,dist目录下比之前多了一个index.html,这个时候需要手动删除dist,我们使用一个插件
clean-webpack-plugin,每次打包前删除上一次生成的dist目录 ,在 webpack.config.js中添加

+ const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
 
 plugins: [
+     new CleanWebpackPlugin(),
      new HtmlWebpackPlugin({
        title: 'react-practice',
        filename: 'index.html',
        template: 'index.html'
      })
  ]
}

添加 对react 代码转译配置

react代码 我们需要babel转译,配置一下babel,我们使用最新的bable 7.x版本,并且(从版本7开始)都是以@babel作为冠名的,下载相关npm包

npm install -D babel-loader @babel/cli @babel/core @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime @babel/preset-env @babel/preset-react babel-plugin-import   
npm install -S @babel/polyfill core-js@3

在根目录下创建一个 .babelrc文件,添加内容:

{
  "plugins": [
    ["@babel/plugin-transform-runtime"],
    ["@babel/plugin-proposal-class-properties"]
  ],
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "corejs": "3",
        "useBuiltIns": "usage"
      }
    ],
    "@babel/preset-react"
  ]
}
  • 在webpack.config.js中添加如下配置:
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: ['babel-loader']
      }
    ]
}
}
  • 在/src/index.js中添加
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class App extends Component {
  render() {
    return (
      
hello world
) } } ReactDOM.render(, document.getElementById('app'));
  • 在index.html中添加:



  
  
  
  Document


  

babel配置完成,执行 npm start 生成了dist目录,打开dist下的index.hmtl文件
每次修改我们的文件,都要打包,这个效率不高,我们来配置下开发时,使用的配置

使用webpack-dev-server

npm install -D webpack-dev-server
  • webpack.config.js 添加配置
module.exports = {
+  devServer: {
+    contentBase: './dist'
+  }
}
  • package.json 添加scripts 命令
"scripts": {
    "start": "webpack --config webpack.config.js"
    "dev": "webpack-dev-server --watch --inline --open --config webpack.config.js"
  },

区分环境

现在将所有的配置都在webpack.config.js中配置,后面会添加很多配置,会导致这个文件很多,这个时候,我们按照不同环境配置下

  webpack-practice
+ |- /build
+   |- webpack.base.js
+   |- webpack.dev.js
+   |- webpack.prod.js

按照一个工具 webpack-merge,用于合并配置

npm install -D webpack-merge
  • webpack.base.js 添加配置
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: {      
    app: "./src/index.js"
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'js/[name].js'
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: 'react-practice',
      filename: 'index.html',
      template: 'index.html'
    })
  ]
}
  • webpack.dev.js
const merge = require('webpack-merge');
const path = require('path');
const webpackBase = require('./webpack.base');

module.exports = merge(webpackBase, {
  mode: 'development',
  devServer: {
    contentBase: path.join(__dirname, 'dist')
  }
})
  • webpack.prod.js 下载个chalk模块 npm install -D chalk
const merge = require('webpack-merge');
const webpack = require('webpack');
const chalk = require('chalk');
const webpackBase = require('./webpack.base');

const webpackProdConf = merge(webpackBase, {
  mode: 'production'
});

webpack(webpackProdConf, (err, stats) => {
  if (err) throw err;

  if (stats.hasErrors()) {
    console.log(chalk.red('build fail'))
    process.exit(1)
  }
  console.log(chalk.green('build success'))
});

删除 webpack.config.js

  • packagek.json scripts 配置
 "scripts": {
    "dev": "webpack-dev-server --watch --inline --open --config build/webpack.dev.js",
    "build": "node build/webpack.prod.js"
  },

css配置与抽离

我们在react中准备使用sass及分离到单独的文件中,我们使用mini-css-extract-plugin这个插件分离css

npm install -D mini-css-extract-plugin css-loader postcss-loader sass-loader node-sass autoprefixer

注意我们没有下载style-loader,style-loader的作用是将css通过style标签内联到html中,我们是将css抽离到单独文件所以不需要,
npm下载node-sass如果出现下载不下来,使用cnpm。

  • 在 webpack.base.js 增加配置如下:
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  entry: {      
    app: "./src/index.js"
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'js/[name].js'
  },
  module: {
    rules: [
      ...
+     {
+       test: /\.(css|scss)$/,
+       use: [
+         {
+           loader: MiniCssExtractPlugin.loader,
+           options: {
+             publicPath:'../',
+             hmr: process.env.NODE_ENV === 'development'
+           }
+         },
+         'css-loader',
+         'postcss-loader',
+         'sass-loader'
+       ]
+     }
    ]
  },
  plugins: [
    ...
+   new MiniCssExtractPlugin({
+     filename: 'css/[name][contenthash].css',
+     chunkFilename: 'css/[id][contenthash].css',
+     ignoreOrder: false
+   })
  ],
}

css新的属性我们还有自动添加前缀,我们使用postcss,在根目录下创建一个postcss.config.js添加如下配置:

module.exports = {
  plugins:[
      require("autoprefixer")
  ]
}

这个时候就可以使用scss,编写css样式,引入我们的jsx中啦。。。

加载图片

这里我们需要用到连个loader,url-loader file-loader.我们使用url-loader配置,有个limit选项可以设置一个图片大小,大于这个值,url-loader会自动交给file-loader处理,下面下载一下

npm install --save-dev file-loader url-loader
  • 在 webpack.base.js中配置下
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: {      
    app: "./src/index.js"
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'js/[name].js'
  },
  module: {
    rules: [
      ...
+     {
+       test: /\.(png|jpg|gif)$/,
+       use: [
+         {
+           loader: 'url-loader',
+           options: {
+             limit: 5000,
+             name: 'images/[hash].[ext]'
+           }
+         }
+       ]
+     }
    ]
  }
  ...
}

代码抽离

前置知识:
webpack在打包后的代码,大概分为三类:

  1. 我们自己编写的业务代码
  2. 第三方库代码,如:react vue 等。
  3. webpack管理各个模块交互的代码
    现在我们打包后所有的代码都在一个js文件中,下面我们配置下,将这三部分代码分离出来
...

module.exports = {
  ...
+ optimization: {
+   splitChunks: {
+     chunks: "async",
+     minSize: 30000,
+     minChunks: 1,
+     maxAsyncRequests: 5,
+     maxInitialRequests: 3,
+     automaticNameDelimiter: '~',
+     name: true,
+     cacheGroups: {
+       commons: {
+           test: /[\\/]node_modules[\\/]/,
+           name: 'vendors',
+           chunks: 'all'
+       }
+     }
+   },
+   runtimeChunk: {
+     name: 'manifest'
+   }
+ }
}

备注: 在webpack4.x版本之前使用的都是CommonsChunkPlugin插件对代码进行分割,webpack4把CommonsChunkPlugin移除了。使用的SplitChunksPlugin对代码分割

配置开发跨域配置

在本地开发过程中,和后台交互的时候,在不同的ip地址,就会出现跨域的情况。我们配置下devServer,实现前端代理。

  • 在 webpack.dev.js 添加
const merge = require('webpack-merge');
const path = require('path');
const webpackBase = require('./webpack.base');

module.exports = merge(webpackBase, {
  mode: 'development',
  devServer: {
    ...
+   proxy: {
+     '/api': {
+       target: 'http://10.25.11.20:8080', // 后台接口地址
+       ws: true,
+       changeOrigin: true,
+       pathRewrite: {
+         '^/api': ''
+       }
+     }
+   }
  }
})

ouput输出配置补充

我们在配置output.filename output.chunkFilename的时候,使用的是[name].js 在dist目录下可以看到每次打包后的文件名都是一样的,当我们前端静态资源放到服务器上,因为文件名不变,可能会导致客户请求访问的是缓存的js 文件,这个时候可能要手动清理浏览器缓存,我们其实可以通过配置 output保证每次更新文件名

  • 在webpack.base.js中添加
  ...
  output: {
    path: path.resolve(__dirname, '../dist'),
  -  filename: "js/[name].js",
  -  chunkFilename: "js/[name].js"
  +  filename: "js/[name][chunkhash].js",
  +  chunkFilename: "js/[name][chunkhash].js"
  },
  ...

解释下,为什么使用chunkhash,这个值是通过文件进行hash计算得到的20位字符串,如果文件不变这个值就是唯一的,文件修改了会生成一个新的hash,这个时候就可以保证每次文件修改会生成新的文件。

webpack一些常用的插件配置补充

  • 比如我们在项目中想用一些工具库比如 jquery,d3等,在项目中不想每个文件夹都import,想使用一个全局的,我们需要用到ProvidePlugin,配置如下:
const path = require("path");
+ const webpack = require('webpack');
...

module.exports = {
  ...
  plugins: [
    ...
+   new webpack.ProvidePlugin({
+     $: 'jquery',
+     jQuery: 'jquery',
+     d3: 'd3'
+   })
  ],
}
  • DefinePlugin
    DefinePlugin 允许创建一个在编译时可以配置的全局常量,就是在webpack中配置的变量,可以在我们的项目代码中可以访问。
...
  plugins: [
    ...
+   new webpack.DefinePlugin({
+     str: JSON.stringify("5fa3b9"),
+     str1: "'http://10.23.4.5'",
+     add: "1+1",
+     'myObj.a': {a: 1, b:2}
+   })
  ]

注意:如果传递的变量值是字符串,需要使用JSON.stringify(),如配置所示,因为字符串被当做代码片段处理,如果key值是用.连接起来需要使用字符串形式

关注公众号,获取更多精彩内容

webpack 4.x + react v.16.12.0 项目配置_第1张图片
qrcode_for_gh_286deb5bf6c3_258.jpg

你可能感兴趣的:(webpack 4.x + react v.16.12.0 项目配置)