webpack基础及react项目搭建

一、webpack入门

1、为什么要使用webpack?

  随着前端工程越来越复杂,单独依靠几个文件来写业务代码已经无法保证项目的可维护性了,所以我们将不同业务逻辑拆分成不同的模块,然后去分开引入这些模块,每个模块做自己的事情,这样就能保障项目的可维护性和扩展性了,但假如有几千个模块,这就需要一个工具来帮助们管理这些模块了,可以说webpack就是帮助我们管理复杂项目的一个工具,它可以帮助我们实现代码转换、文件优化、代码分割、模块合并、自动刷新、代码效验等功能。

2、webpack是什么?

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个捆绑包。

3、webpack四个核心概念

(1)entry(入口)

 entry指定webpack从哪个模块开始构建内部依赖图、进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。我们可以通过在 webpack 配置中配置 entry 属性,来指定一个入口起点(或多个入口起点)。

module.exports = { //单入口写法
  entry: './src/index.js'
};

module.exports = { //多入口写法/对象写法
  entry: {
	  login: './src/login.js',
	  index: './src/index.js'
  }
};

(2)output(出口)

output 属性告诉 webpack 在哪里输出它所创建的 bundles文件,以及如何命名这些文件,默认值为 ./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个 output 字段,来配置这些处理过程。

  output: {     //出口
    filename: 'bundle.js', //打包后的文件名
    path: path.resolve(__dirname, 'build') //打包出的文件所放位置,路径必须是绝对路径,(__dirname:当前目录下产出一个dist目录)
    publicPath: '/' //默认'/',  指定资源文件引用的目录(如图片等),对于打包路径不会有任何影响,
  },

在编译时不知道最终输出文件的 publicPath 的情况下,publicPath 可以留空,并且在入口起点文件运行时动态设置。如果你在编译时不知道 publicPath,你可以先忽略它,并且在入口起点设置 。

__webpack_public_path__ = 'myPublicPath'
//.src/index.js

如果配置创建了多个单独的 “chunk”(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用占位符(substitutions)来确保每个文件具有唯一的名称。

 output: {    
    filename: '[name].js', //会跟随入口名字进行命名
    path: path.resolve(__dirname, 'build') 
  }

(3)loader

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块,在 webpack 的配置中 loader 有两个目标:test 属性:用于标识出应该被对应的 loader 进行转换的某个或某些文件,use 属性:表示进行转换时,应该使用哪个 loader。

module.exports = {
	module: {
	    rules: [
	      { test: /\.css$/, use: 'css-loader' },
	      { test: /\.ts$/, use: 'ts-loader' }
	    ]
	  }
  }

(4)plugins(插件)

loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。
使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。

let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports={
  plugins: [ //数组 放着所有的webpack插件
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
    }),
  ],
}

二 、webpack构建react项目

1、根目录下使用命令创建package.js文件

npm init -y //默认创建
//或
npm init //可在创建时自行定义配置

2、创建目录

创建后目录结构如下:(此处node_modules忽略,安装依赖时会自动创建)
注意:
config目录:此处我用来存放webpack配置文件。
script目录:start.js这是我用来书写项目运行所需代码,build.js项目打包所需代码。

在这里插入图片描述

(1)public/index.html: 存放html模板

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

(2)src/index.js:项目入口文件

import React from 'react';
import ReactDom from 'react-dom';

ReactDom.render(<div>这是组件</div>, document.getElementById('root'));

3、安装相关依赖

–save-dev:(简写-D)将依赖写入package.js文件devDependencies模块,为开发环境所需依赖。
–save: (简写-S)生产环境所需依赖,为产品发布后不可少的依赖,将依赖写入package.js文件devDependencies模块。

webpack: 模块打包工具.
webpack-cli : webpack脚手架
webpack-dev-server:webpack官网出的一个小型express服务器,主要特性是支持热加载。

npm install webpack webpack-cli webpack-dev-server --save-dev 

react: 安装react
react-dom:安装React Dom,这个包是用来处理virtual DOM(虚拟dom)

npm install react react-dom --save

安装babel,将es6转换成es5语法,部分浏览器可能不识别部分es6语法。

@babel/core 与 babel-core的区别:官方7.0 之后,包名升级为 @babel/core,个人理解、babel-core表示7.0以下版本,所有babel7.0版本以上相关统一前缀为@babel/。

@babel/core:babel 核心包,编译器,提供转换的API。
@babel/preset-react:Babel可以转换JSX语法
@babel/plugin-proposal-class-properties:解析类的属性
@babel/plugin-proposal-decorators:解析装饰器
@babel/plugin-transform-runtime:将 helper 和 polyfill 都改为从一个统一的地方引入,并且引入的对象和全局变量是完全隔离的,可以提高代码重用性,缩小编译后的代码体积
@babel/preset-env:对es2015, es2016. es2017的支持

npm install @babel/core @babel/preset-react @babel/preset-env --save--dev 
npm install @babel/plugin-transform-runtime @babel/plugin-proposal-decorators --save--dev 
npm install  @babel/plugin-proposal-class-properties --save--dev 

4、配置webpack文件

webpack-dev-server有两种启动方式:webpack命令启动、node.jsAPI启动。这里首先介绍直接使用webpack命令启动。
打开config目录下webpack.config.js文件
注意:需要安装所用到的loader和plugin

npm i babel-loader style-loader css-loader html-webpack-plugin mini-css-extract-plugin --save-dev

如果需要使用ip地址打开需要安装address模块

npm i address --save-dev

写入以下内容,这里

const path = require('path'); //内置模块,可以将相对路径解析成绝对路径
const HtmlWebpackPlugin = require('html-webpack-plugin'); //生成html文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //抽离样式插件link引入
const address = require('address');

const srcRoot = path.resolve(__dirname, '../src');
module.exports = {
  entry: srcRoot + '/index.js', //入口文件
  output: {
    path: path.resolve(__dirname, '../build'), //打包出的文件所放位置,路径必须是绝对路径,(__dirname:以当前目录下产出一个build目录)
    filename: 'index.js',
  },
  devServer: {  
    port: 8182,
    contentBase: path.join(__dirname, '../build'),
    host: address.ip(),  //这里我使用了ip地址打开,不配置的话默认localhost
    compress: true,
  },
  module: {
    //多个loader需要[],loader还可以写成对象{loader:""},执行顺序从右向左执行,从下到上执行   //
    rules: [
      {
        test: /\.js/,
        exclude: /node_modules/, //不包含node_modules目录下的js文件
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.css/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },

  plugins: [
    new HtmlWebpackPlugin({
      title: 'react-app',
      template: path.resolve(__dirname, '../public/index.html'), //本地模板文件的位置
      filename: 'index.html',
      minify: false,
      inject: true, // 1、true或者body:所有JavaScript资源插入到body元素的底部;head: 所有JavaScript资源插入到head元素中;false:所有静态资源css和JavaScript都不会注入到模板文件中
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: 'css/[name].css',
    }),
  ],
};

5、配置babelrc文件

根目录下新建.babelrc文件,写入配置。
在这里插入图片描述

{
  "presets": ["@babel/preset-react", "@babel/preset-env"],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators", //支持装饰器插件
      {
        "legacy": true //使用旧式(第一阶段)的装饰器语法和行为
      }
    ],
    [
      "@babel/plugin-proposal-class-properties", //编译类
      {
        "loose": true //将编译类属性以使用赋值表达式而不是Object.defineProperty
      }
    ],
    ["@babel/plugin-transform-runtime"]
  ]
}

到此处就已经可以启动我们的项目了,这里使用命令执行
注意 :这里我的webpack.config文件放在了根目录下的config目录下,所以需要添加:–config ./config/webpack.config.js,不写的话一般默认是根目录

webpack-dev-server --open --mode development --config ./config/webpack.config.js --watch

可以将命令写入package.js文件中配置自定义命令
在这里插入图片描述
控制台输入启动命令:npm run start

如果出现webpack-cli/bin/config-yargs报错,可能是webpack-cli版本不兼容的问题,可以尝试更换webpack-cli的版本。
例如安装指定版本:

npm i webpack-cli@3.3.12 --save-dev

此处用的版本号如下:
在这里插入图片描述
在这里插入图片描述

6、配置less

经常我们在项目中一般使用less或sass来替代css文件,这里只介绍less配置方法
安装相关loader:

npm i less postcss-loader less-loader --save-dev

在webpack.config.js文件中配置以下代码:

      {
        test: /\.less$/,
        exclude: /node_modules/,
        include: [/src/],
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2,
              modules: {
                localIdentName: '[path]_[local]_[hash:base64:6]', //给css类名添加哈希值,避免组件中命名重复而导致样式混合
              },
            },
          },
          'postcss-loader', //考虑浏览器的兼容性,添加浏览器前缀
          {
            loader: 'less-loader',
          },
        ],
      }

在这里插入图片描述
在这里插入图片描述

(一)使用Node.js启动服务

(1)去掉webpack.config.js文件中devServer模块。
在这里插入图片描述
(2)打开script目录下的start.js文件,写入:

const WebpackServer = require('webpack-dev-server');
const baseConfig = require('../config/webpack.config');
const webpack = require('webpack');
const address = require('address'); //用来获取当前计算机的IP,MAC和DNS服务器。
const compiler = webpack(baseConfig);

let port = 8081;

const devServer = new WebpackServer(compiler, {
  host: address.ip(),
  compress: true, //启用 gzip 压缩。
  index: 'index.html', //启动索引html文件,默认index.html
  hot: true, //是否启用热替换
  clientLogLevel: 'none', //启用内联模式(inline mode),会在控制台打印消息,用none阻止。
  inline: true, //dev-server 的两种不同模式之间切换:true内联模式(inline mode)、 false: iframe 模式,默认true。
  open: true, //自动打开浏览器
});
devServer.listen(port);

(3)在package.js文件中修改
在这里插入图片描述
控制台执行npm run start命令,可以看到使用node命令服务启动成功。

1、监听端口号占用情况并动态修改端口号

在项目实际开发中,如果端口号写死,一旦当前端口号被占用,将无法启动服务,需要手动修改配置文件端口号,为了开发方便,我们可以在配置文件中通过引入net模块来检测端口占用情况,从而实现动态修改端口。
修改script目录下的start.js文件并安装net、chalk模块(chalk模块可忽略,引入这个模块可以支持日志颜色的修改,利于我们更快找到日志)

npm i net chalk --save-dev

start.js文件内容:


const WebpackServer = require('webpack-dev-server');
const baseConfig = require('../config/webpack.config');
const webpack = require('webpack');
const chalk = require('chalk'); //支持日志颜色修改
const net = require('net');
const address = require('address'); //用来获取当前计算机的IP,MAC和DNS服务器。
const compiler = webpack(baseConfig);

let port = 8081;

function listenPort() {
  const server = net.createServer().listen(port);

  server.on('listening', () => {
    server.close();
    startDevServer();
  });
  server.on('error', (e) => {
    if (e.code === 'EADDRINUSE') {
      ++port;
      console.log(chalk.yellow('端口号被占用,修改端口号为' + port));
      listenPort();
    }
  });
}

function startDevServer() {
  const devServer = new WebpackServer(compiler, {
    host: address.ip(),
    compress: true, //启用 gzip 压缩。
    index: 'index.html', //启动索引html文件,默认index.html
    hot: true, //是否启用热替换
    clientLogLevel: 'none', //启用内联模式(inline mode),会在控制台打印消息,用none阻止。
    inline: true, //dev-server 的两种不同模式之间切换:true内联模式(inline mode)、 false: iframe 模式,默认true。
    open: true, //自动打开浏览器
  });
  devServer.listen(port);
}

listenPort();

当端口号被占用时:
在这里插入图片描述

2、Node.js调用webpack打包

打开script目录下的build.js文件,
安装依赖:(不需要ora模块时,可忽略,此模块主要用来显示当前加载状态,出现编译中图标)

npm i ora --save-dev
const webpack = require('webpack');
const chalk = require('chalk'); //支持日志颜色修改
const baseConfig = require('../config/webpack.config');
const ora = require('ora');

const spinner = ora('building>>>>').start();

const compiler = webpack({
  ...baseConfig,
  mode: 'production'
});
compiler.run((err, stats) => {
  if (err || stats.hasErrors()) {
    console.log(chalk.red('build fail:' + stats.hasErrors()));
    return;
  }
  spinner.stop();
  console.log(chalk.green('build success'));
});

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值