美文网首页
webpack 4.x + react v.16.12.0 项目

webpack 4.x + react v.16.12.0 项目

作者: 佐伊zero | 来源:发表于2019-11-29 22:51 被阅读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 (
          <div>hello world</div>
        )
      }
    }
    ReactDOM.render(<App />, document.getElementById('app'));
    
    • 在index.html中添加:
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
    </head>
    <body>
      <div id="app"></div>
    </body>
    </html>
    

    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值是用.连接起来需要使用字符串形式

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

    qrcode_for_gh_286deb5bf6c3_258.jpg

    相关文章

      网友评论

          本文标题:webpack 4.x + react v.16.12.0 项目

          本文链接:https://www.haomeiwen.com/subject/rqsnwctx.html