react+webpack4搭建前端项目(一)

前言

react+webpack4搭建前端项目分为三个章节。链接如下。目的是实现从零搭建一个react后台管理系统
1、react+webpack4搭建前端项目(一)基础项目搭建
2、react+webpack4搭建前端项目(二)react全家桶的使用
3、react+webpack4搭建前端项目(三)打包优化
webpack配置的讲解
4、react+webpack4.x搭建前端项目(四)配置抽取和区分环境
5、react+webpack4.x搭建前端项目(五)多页面配置
6、react+webpack4.x多模块打包配置

这是第一章,基本项目搭建

本篇主要讲述一步步搭建react项目雏形(不使用create-react-appumi等),包括配置基本webpack,再到react+webpack配置整合,到完成项目的启动和打包(不包含react相关技术栈的使用和webpack的打包优化)。这些东西我还会在之后更新新的文章来详细讲解react相关技术栈(全家桶react+react-router+axios+antd+mobx)的使用以及webpack打包优化

本文适合人群:react,webpack有一定基础

技术栈

  • react框架:
    react+react-router+axios+antd+mobx 后边在写项目中会使用,本文不涉及
  • 打包构建
    webpack4.x

废话不多说,前方高能,正式开始喽

初始化项目

webpack安装(webpack小试牛刀)
  1. 创建package.json,执行npm init一路按enter键就搞定了

  2. 安装webpack基本包(本文采用webpack4.x,注意了啊,各位同学)

      npm install --D webpack webpack-dev-server webpack-cli
    

    webpack4.x 必须安装webapck-cli,这是一个注意事项

新建src/index.js,添加代码如下

console.log("hello world")

package.json执行脚本添加"build":"webpack"

在终端执行npm run build,可以看到在根目录生成了dist/main.js的打包文件,这是webpack4.x打包默认找src/index.js打包入口,如下图:

QQ截图20190810105541.png
QQ截图20190810105621.png

上边已经说明webpack在本项目中可以成功构建打包js文件了,其它用法请查看官方文档!

下边开始正式配置webpack啦~

一步步从最基本的配置出发,到创建不同环境webpack配置文件来区分不同环境,在到详细配置不同环境的webpack;最后配置react的开发和打包环境

webpack的基础配置

1、项目根目录创建build目录,创建webpack.config.js

基本配置

const path = require("path");

function resolve(dir) {
    return path.resolve(__dirname, dir)
}

module.exports = {
    // 指定构建环境  
    mode:"development",
    // 入口
    entry: {
        app: "./src/index" 
    },
    // 出口
    output: {
        path : resolve("../dist"),
        filename: "js/[name].[hash].js",
        publicPath: "/" // 打包后的资源的访问路径前缀
    },
    // 模块
    module:{

    },
    // 插件
    plugins:[

    ],
    // 开发环境本地启动的服务配置
    devServer: {

    }
}

上边每一项配置都有注释,有什么不懂的基本配置可以看官方文档

2、编写,配置html模板,实现html模板的打包,安装插件

npm install -D html-webpack-plugin

在根目录创建index.html模板,代码很简单

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>mydemo</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

3、在webpack.config.js的plugins添加

new HtmlWebpackPlugin({
    filename: resolve('./../dist/index.html'), // html模板的生成路径
    template: 'index.html',//html模板
    inject: true, // true:默认值,script标签位于html文件的 body 底部
    hash: true, // 在打包的资源插入html会加上hash
    //  html 文件进行压缩
    minify: {
        removeComments: true,               //去注释
        collapseWhitespace: true,           //压缩空格
        removeAttributeQuotes: true         //去除属性 标签的 引号  例如 <p id="test" /> 输出 <p id=test/>
    }
})

4、修改package.json的build命令为指定配置文件构建打包"build": "webpack --config build/webpack.config.js",然后再次执行npm run build,这时候已经可以把html模板和打包后的资源插入到html模板,最后打包进dist目录

QQ截图20190810113953.png
抽取webpack配置文件

为了区分开发环境和生产环境,下面我们一步一步抽取wenpack公共配置
分别创建 utils.js ,webpack.base.config.js , webpack.dev.config.js , webpack.prod.config.js

在抽取webpack配置过程中,需要使用webpack-merge插件,安装方式

npm install -D webpack-merge

这个插件是用来合并webpack配置的,可以对不同文件的webpack配置合并成一个完整的webpack配置。具体用法请看下面

utils.js是webpack配置用的工具方法

const path = require("path")

exports.resolve = function (dir) {
    return path.resolve(__dirname, dir)
}

webpack.base.config.js 是webpack在不同环境的公共配置

const utils = require("./utils")

module.exports = {
    // 入口
    entry: {
        app: "./src/index" 
    },
    // 出口
    output: {
        path : utils.resolve("../dist"),
        filename: "js/[name].[hash].js",
        publicPath: "/" // 打包后的资源的访问路径前缀
    },
    // 模块
    module:{

    },
}

webpack.dev.config.js 是项目开发环境的配置

const webpackMerge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.config")
const utils = require("./utils")
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = webpackMerge(baseWebpackConfig,{
    // 指定构建环境  
    mode:"development",
    // 插件
    plugins:[
        new HtmlWebpackPlugin({
            filename: utils.resolve('./../dist/index.html'), // html模板的生成路径
            template: 'index.html',//html模板
            inject: true, // true:默认值,script标签位于html文件的 body 底部
        })
    ],
    // 开发环境本地启动的服务配置
    devServer: {

    }
});

webpack.prod.config.js 是项目生产环境环境的配置

const webpackMerge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.config")
const utils = require("./utils")
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = webpackMerge(baseWebpackConfig,{
    // 指定构建环境  
    mode:"production",
    // 插件
    plugins:[
        new HtmlWebpackPlugin({
            filename: utils.resolve('./../dist/index.html'), // html模板的生成路径
            template: 'index.html',//html模板
            inject: true, // true:默认值,script标签位于html文件的 body 底部
            hash: true, // 在打包的资源插入html会加上hash
            //  html 文件进行压缩
            minify: {
                removeComments: true,               //去注释
                collapseWhitespace: true,           //压缩空格
                removeAttributeQuotes: true         //去除属性引用
            }
        })
    ],
})

在修改package.json的build命令:

"build": "webpack --config build/webpack.prod.config.js"

然后再次执行npm run build,一切正常!

配置生产环境webpack.dev.config.js其实上面步骤已经完成,但还比较简单,后边会结合react的打包进行整合

配置开发环境webpack.dev.config.js

开发环境需要我们使用webpack-dev-server插件,上边已经安装过

1、添加package.json命令,用webpack-dev-server启动服务

"dev": "webpack-dev-server",

执行npm run dev,现在已经可以正常启动一个服务了,默认端口8080,服务的根目录是项目的根目录

QQ截图20190810161241.png

但是这种方式没有指定配置文件启动,所以还需改成指定配置文件启动

 "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.config.js",

在次执行npm run dev,你会看到配置的资源和html模板已经被webpack构建

QQ截图20190810162214.png

这时候浏览器打开http://localhost:8080,看到src/index.js的内容执行了

QQ截图20190810133343.png

2、丰富webpack-dev-server配置,在webpack.dev.config.js的devServer属性下添加开发环境启
动服务的配置

    // 开发环境本地启动的服务配置
    devServer: {
        historyApiFallback: true, // 当找不到路径的时候,默认加载index.html文件
        hot: true,
        contentBase: false, // 告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要
        compress: true, // 一切服务都启用gzip 压缩:
        port: "8081", // 指定段靠谱
        publicPath: "/", // 访问资源加前缀
        proxy: {
            // 接口请求代理
        },

    }

执行npm run dev,启动服务,这时候配置文件已经把服务端口改为8081,输入http://localhost:8081,修改src/index.js,此时可以看到浏览器会热更新,到此开发环境的配置基本完成,如果需要了解更多请查看文档

webpack-dev-server详细配置

引入react框架

安装react
npm install -S react react-dom

修改src/index.js文件,使用react,react-domreactspa页面插入到html模板idapp的盒子当中,重新运行项目npm run dev,不出意外你惊讶的发现报错了。这是此时webpack还不能编译构建react的代码,那么接下来我们进行支持react的打包构建

支持react的打包构建(配置webpack)

我们都知道,要想把react的代码使用webpack编译构建成浏览器可以运行的代码,需要使用babel等工具进行"翻译一下"

1、安装,配置babel(babel7.x)

npm install -D @babel/core @babel/preset-env @babel/preset-react 
npm install -D @babel/plugin-transform-runtime @babel/runtime @babel/runtime-corejs2
  • @babel/core babelbabel的核心库
  • @babel/preset-env 把es6,es7语法转换成es5。bebel7以上的版本只用这一个预设包就可以实现语法的转换,已经废弃了preset-stage-0,preset-stage-1,preset-stage-2等这些包。但是这个包还不能转换es6,es7的一些新特性比如Array.includes(),这就需要我们使用@babel/plugin-transform-runtime
  • @babel/preset-react 把react语法转换为es5
  • @babel/plugin-transform-runtime 支持一些es6,es7的新语法

那么安装完了,我们需要添加babel的配置了,在项目目录创建.babelrc,配置内容如下

{
  "presets": [
    ["@babel/preset-env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "@babel/preset-react"
  ],
  "plugins": [
    ["@babel/plugin-transform-runtime",{
      "corejs": 2, // polyfill 需要使用@babel/runtime-corejs2
      "useBuildIns":"usage", //按需引入,即使用什么新特性打包什么新特性, 可以减小打包的体积
    }]
    
  ]
}

上边有两个地方讲解一下,在配置plugin-transform-runtime时候,需要安装依赖@babel/runtime,还添加了特殊配置"corejs": 2"useBuildIns":"usage",为什么添加这些配置呢?

  • "corejs": 2: @babel/runtime + @babel/plugin-transform-runtime 在 babel7 下只包含 helper function(即 Babel 进行处理时需要的帮助函数), 如果想实现 polyfill , 需要使用@babel/runtime-corejs2。
  • "useBuildIns":"usage": 要实现真正的按需引入,即使用什么新特性打包什么新特性,可以使用实验性的 useBuildIns:"usage"。

2、webpack4.x配置编译打包规则

安装loaders

  • babel-loader使用babel进行编译项目
npm install -D babel-loader
  • style-loader,css-loader编译css文件
npm install -D style-loader css-loader
  • url-loader file-loader引入文件路径(图片,字体)
npm install -D url-loader file-loader
  • less-loader识别less文件
npm install -D less less-loader

安装完这些包之后,我们需要在webpacl.base.config.js添加打包编译构建规则
在module下添加rules属性

rules:[
    {
        test: /\.(js|jsx)$/,//一个匹配loaders所处理的文件的拓展名的正则表达式,这里用来匹配js和jsx文件(必须)
        exclude: /node_modules/,//屏蔽不需要处理的文件(文件夹)(可选)
        loader: 'babel-loader',//loader的名称(必须)
    },
    {
        test: /\.css$/,
        use:[
            {
                loader: 'style-loader', // 创建 <style></style>
            },
            { 
                loader: 'css-loader',  // 转换css
            }
        ]
    },
    {
        test: /\.less$/,
        use: [
            {
            loader: 'style-loader', 
            },
            {
            loader: 'css-loader',
            },
            {
            loader: 'less-loader', // 编译 Less -> CSS
            },
        ],
    },
    {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
            limit: 10000, // url-loader 包含file-loader,这里不用file-loader, 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
            name: 'static/img/[name].[hash:7].[ext]'
        }
    },
    {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
            limit: 10000, // 小于10000B的图片base64的方式引入,大于10000B的图片以路径的方式导入
            name: 'static/fonts/[name].[hash:7].[ext]'
        }
    }
]

这些配置相比vue框架的配置少了对vue文件的编译构建配置。你会发现在vue项目vue-loader,vue-style-loader,vue-template-compiler这三个插件是必不可少的,这是用来处理vue文件的包

继续在webpack.base.config.js添加

resolve: {
    extensions: ['.js', '.json'], // 解析扩展。(当我们通过路导入文件,找不到改文件时,会尝试加入这些后缀继续寻找文件)
    alias: {
        '@': path.join(__dirname, '..', "src") // 在项目中使用@符号代替src路径,导入文件路径更方便
    }
}

3、编写页面,运行项目,测试打包

新建assets/img目录,把图片放在该目录下

src下新建home/index.jshome/test.csshome/test.less
home/index.js内容:

import React from 'react'
import "./test.less"
import "./test.css"
import buyImg from "@/assets/img/icon_buy_task.png"
import testImg from "@/assets/img/bg_store.png"
export default class Home extends React.Component {
    render(){
        return (
            <div className="test test2">
                <p>hello world</p>
                <img src={buyImg} alt="" />
                <img src={testImg} alt="" style={{width:360,height:60}}/>
            </div>
        )
    }
}

test.css

.test2 {
    font-size: 32px;
}

test.less

.test {
    background: rebeccapurple;
}

然后修改src/index.js入口文件

import React from 'react'
import ReactDom from 'react-dom'
import HomePage from "./home"
class App extends React.Component {
    render(){
        return (
            <div style={{color:"#333"}} className="test test2">
                <HomePage />
            </div>
        )
    }
}
ReactDom.render(<App/>,document.getElementById("app"))

这时候项目的基本雏形已经形成:

QQ截图20190812122733.png

然后我们运行和打包项目
先执行npm run dev,服务正常启动,浏览器打开http://localhost:8081
页面效果:

QQ截图20190812123014.png

最后打包执行npm run build,打包成功

QQ截图20190812123144.png

此时,比较大的图片和js的bundle都已经正常打包,那么我们怎么测试打包的代码正常呢?这里我推荐一个插件(不用把静态包部署到nginx服务器就可以运行)http-server

npm install -g http-server

全局安装http-server包,安装成功之后,cd dist目录,执行http-server命令

这时候启动了一个服务,默认开启8080端口

如下图:


QQ截图20190812123523.png

这时候打开浏览器,输入http://localhost:8081,发现页面正常访问!

就这样一个基本的项目雏形有了!

下一篇: react技术栈的使用,react+webpack4搭建前端项目(二)react全家桶的使用

扫下边的二维码可以天天领红包,以后点外卖什么的再也不用开会员了,从此省出一套房~
qrcode.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342