webpack打开项目命令_webpack基础概念

安装

在使用webpack之前我们要安装webpack,安装命令如下:

# 创建webpack-demo文件夹
mkdir webpack-demo
# 生成package.json文件,对项目依赖进行管理
yarn init -y
# 安装webpack相关依赖
yarn add webpack webpack-cli -D

这里我们安装webpack-cli的原因是因为它可以让我们可以在命令行中运行webpack,否则webpack命令将无法运行

生成打包文件

接下来我们建立src目录来管理我们的源代码,并建立main.js文件,写入第一行代码:

console.log('Hello webpack!')

接下来我们在项目根目录建立webpack的配置文件webpack.config.js并进行最简单的配置:

const path = require('path');
module.exports = {
  mode: 'development',
  entry: {
    main: './src/main.js'
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'main.js'
  }
}

之后我们通过package.json文件中的script命令来为webpack添加快捷命令:

f04eacf8486ed771fa08c3a29fd00a12.png

配置好后通过命令行执行:yarn build,会发现根目录出现了dist目录,里边有我们的代码main.js

接下来我们在根目录新建index.html,通过script标签将打包后的代码引入并在浏览器中打开:

ac5e87f6de32f12ceeb52517153c1783.png

或者可以通过node命令来运行打包文件:

1dcf56b66bb80de62ab8d86ae61d732f.png

到这里我们成功打包好了我们的第一个文件,感觉还是有些小激动的。

入口和出口

在配置之前,我们先简单理解下入口和出口的概念: 入口(entry): 整个项目的起始模块,用来作为构建其内部依赖图的开始 出口(output): 告诉webpack打包后的文件所存放的目录

这里是一个打包截图:

145bf9c4ce10f7f604fbee88910eabbe.png

了解了基本概念之后,我们来看一下常用的相关配置:

entry: {
  main: './src/main.js' // 入口文件对应的源代码位置,key值为打包生成后的chunkNames
},
output: {
  path: path.resolve(__dirname, './dist'), // 打包生成文件存放的位置
  // 使用每次构建过程中,唯一的hash生成
  filename: '[name]_[hash].js', // 每个打包输出文件的名称
  // publicPath: 'https://cdn.example.com/assets/', // 会在引入的资源前加入该路径,例:将资源托管到cnd
}

在配置文件中我们使用了[name]这种符号,这是webpack中的占位符(placeholder),这里介绍下配置中使用到的,如果小伙伴们感兴趣可以自己查阅官方文档:[name]: 模块名称 [hash]: 模块标识符的hash(每次打包都会生成对应唯一的hash值)

打包模式

webpack中,我们可以通过mode选项,来分别为生成环境打包和开发环境打包使用相应的内置优化:

mode: 'development'

目前我们的配置是开发环境: development,当我们使用production的时候,webpack会将我node中的全局变量改为: process.env.NODE_ENV的值设置为production,并且也会启用代码压缩等功能,有助于帮我们减少代码体积,提升用户体验。

而当我们使用development模式时,webpack会将process.env.NODE_ENV的值设置为development,并取消代码压缩等功能,提升开发体验

使用插件

webpack中,我们可以使用各种各样的插件来自定义webpack构建过程,方便我们的开发。

这里我们介绍2个常用的pluginHtmlWebpackPlugin: 自动创建一个html文件来帮我们引入打包文件,这对我们每次打包都通过hash值来生成不同的打包文件的情况特别有用 CleanWebpackPlugin: 在打包之前删除output.path指定的位置中的文件,保证每次打包都是最新的文件

首先我们来安装这俩个插件:

yarn add --dev html-webpack-plugin clean-webpack-plugin

接下来我们再webpack中使用这2个插件:

// 引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html', // 生成html文件的文件名
    template: './index.html' // 使用的html模板
  }),
  new CleanWebpackPlugin()
]

这里我们通过为html-webpack-plugin来指定根目录下的index.html为模版,生成打包后的index.html。新生成的index.html文件与模板文件不同之处在于会自动引入打包生成的文件(包括js文件、css文件、以及之后配置的dll文件),这样即使我们使用了[hash]等占位符,插件也会自动帮我们动态引入资源,而不用我们每次手工配置。

使用HtmlWebpackPlugin指定template的原因是因为我们可以在模板文件中自己写一些我们自己的代码,比如引入一些css或者执行一段js脚本亦或者我们可以在模板文件中指定项目的根元素:

<!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="root"></div>
</body>

</html>

通过使用插件我们目前解决了如下问题:
1. 不用再手动引入打包文件 2. 不用在重新打包的时候手动去删除旧的打包文件

使用loader

下面是对webpack官网中loader介绍的一步分摘抄:

loader用于对模块的源代码进行转换
特性(这里只列出了部分): loader支持链式传递,链中每个loader会将转换应用在已处理过的资源上。一组链式的loader将按照相反的顺序执行。链中的第一个loader将其结果(也就是转换后的资源)传递给下一个loader,依次类推 loader可以通过 options对象配置 * 插件可以为 loader带来更多特性

我个人觉得其实loader就是让webpack可以识别各种资源,然后将资源加工处理成浏览器可以识别的、兼容性更好的、性能更好的代码。

接下来我们学习如何通过loader来让webpack处理各种资源。

项目中使用css

要想使用css文件,我们首先需要安装style-loadercss-loader`:

yarn add style-loader css-loader -D

webpack.config.js进行配置:

module: {
  rules: [
    {
      test: /.css$/,
      use: ['style-loader', 'css-loader']
    }
  ]
}

但是日常的项目中,有很多css属性需要添加浏览器供应商前缀来确保兼容性, 我们可以使用postcss-loader结合autoprefixer来实现:

yarn add postcss-loader autoprefixer -D

我们需要为css文件添加postcss-loader,之后在根目录新建postcss.config.js配置autoprefixer:

// webpack.config.js
rules: [
  {
    test: /.css$/,
    use: [
      'style-loader',
      'css-loader',
      'postcss-loader'
    ]
  }
]

// postcss.config.js
module.exports = {
  plugins: [
    // autoprefixer: parse CSS and add vendor prefixes to CSS rule using values from can I use
    // 解析CSS并使用Can I use 中的值 将供应商前缀添加到css规则中
    require('autoprefixer')
  ]
};

平常我们也会用到css预处理器来方便开发,这里我们以sass为例:

yarn add sass-loader node-sass -D

webpack中添加如下配置:

{
  test: /.scss$/,
  use: [
    'style-loader',
    'css-loader',
    'postcss-loader',
    'sass-loader'
  ]
}

这里要特别注意loader的顺序问题(反向:从下到上,从右到左): 首先通过sass-loaderscss文件中的语法解析为css语法 之后通过postcss-loader为对应的css属性添加浏览器供应商前缀 然后使用css-loader根据import语法将所有的css文件整合到一起 最后将css-loader整合的css文件通过style标签插入到html中,实现样式的更改

如果顺序书写错误,会导致程序无法正常运行

最终效果如下:

76a8787469a073597770833abe9fc705.png

学习了上面的知识以后,我们再了解几个css-loader的常用配置:

{
  test: /.scss$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        // 开启css模块化
        modules: true,
        // 在css-loader前应用的loader的数量:确保在使用import语法前先经过sass-loader和postcss-loader的处理
        importLoaders: 2
      }
    },
    'postcss-loader',
    'sass-loader'
  ]
}

项目中使用图片和字体图标

要想在项目中使用图片和字体图标,我们需要使用到file-loader:

yarn add file-loader -D

需要在webpack.config.js中添加如下配置:

{
  test: /.(png|svg|jpg|gif)$/,
  use: ['file-loader']
}

配置成功后webpack会将我们引入的资源转换为路径字符串,webpack会通过字符串帮我们找到文件的位置。

接下来我们尝试一下file-loader的几个配置项:

{
  test: /.(png|svg|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'file-loader',
      options: {
        // placeholders:
        //    [ext]: 资源扩展名
        //    [name]: 资源的基本名称
        //    [hash]: 内容hash值
        //    [path]: 资源相对于context的路径
        // 默认值: [hash].[ext]
        name: '[name]_[hash:8].[ext]',
        // 打包文件存放到出口目录下的images文件中
        outputPath: 'images/'
      }
    }
  ]
}

打包文件如下:

1e4902140f5177ad3757cfb653832871.png

这里也可以使用url-loader来处理静态资源,url-loader的工作方式和file-loader相同,但是它会在文件小于限制大小(单位byte)的时候,返回base64字符串,当大于限制大小时会返回和file-loader一样的地址字符串。

这在处理一些小文件的时候不用再进行资源请求,可以提高性能

{
  test: /.(png|svg|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        // placeholders:
        //    [ext]: 资源扩展名,默认file.extname
        //    [name]: 资源的基本名称,默认file.basename
        //    [hash]: 内容hash值,默认md5
        //    [path]: 资源相对于context的路径,默认值file.dirname
        // 默认值: [hash].[ext]
        name: '[name]_[hash:8].[ext]',
        // 打包文件存放到出口目录下的images文件中
        outputPath: 'images/',
        limit: 8192, // 单位byte,文件小于8kb时返回base64文件,大于这个限制会返回地址
      }
    }
  ]
}

我们可以看一下打包区别:

35b39042c978e2ff03fa717822f962f3.png

source map配置

当我们使用webpack进行代码打包以后,如果代码出现错误,会很难追踪到错误和警告在源代码中的原始位置。为了更容易地追踪错误和警告,JavaScript提供了SourceMap功能,可以将编译后的代码映射回原始源代码。

webpack中配置如下:

// 此选项控制是否生成,以及如何生成source map
devtool: 'none',

可选项如下:

0b1cf64964eaf278935870b587ca97d2.png

这里简单介绍下各配置项中单词的一些含义,方便理解:cheap: 不会生成列映射,只会映射行数 eval: 每个模块都使用eval执行,并且都有//@sourceURL module:会处理来自loadersource map inline: source map转换为DataUrl后添加到bundle

日常的开发中我们会进行如下配置: 开发环境: cheap-module-eval-source-map 生产环境: cheap-module-source-map(生产环境使用source map,方便定位错误)

区分不同环境的配置文件

在开发环境和生产环境中,我们要用到的webpack配置是不同的,这里我们在根目录下分别新建webpack.dev.jswebpack.prod.js来分别存放开发环境和生产环境所需要的配置,通过原有的webpack.config.js来存放公共的配置文件。

接下来我们使用webpack-merge来进行配置文件的合并工作:

yarn add webpack-merge -D

为了方便统一管理,我们根目录下新建config文件夹,然后将配置文件放到里边,现在的配置文件是这样的:

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const absPath = (dir) => path.resolve(__dirname, dir)
module.exports = {
  entry: {
    main: absPath('../src/main.js') // 入口文件对应的源代码位置,key值为打包生成后的chunkNames
  },
  output: {
    path: absPath('../dist'), // 打包生成文件存放的位置
    // 使用每次构建过程中,唯一的hash生成
    filename: '[name]_[hash].js', // 每个打包输出文件的名称
    // publicPath: 'https://cdn.example.com/assets/', // 会在引入的资源前加入该路径,例:将资源托管到cnd
  },
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
        ]
      },
      {
        test: /.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              // 开启css模块化
              modules: true,
              // 在css-loader前应用的loader的数量:确保在使用import语法前先经过sass-loader和postcss-loader的处理
              importLoaders: 2
            }
          },
          'postcss-loader',
          'sass-loader'
        ]
      },
      {
        test: /.(png|svg|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              // placeholders:
              //    [ext]: 资源扩展名,默认file.extname
              //    [name]: 资源的基本名称,默认file.basename
              //    [hash]: 内容hash值,默认md5
              //    [path]: 资源相对于context的路径,默认值file.dirname
              // 默认值: [hash].[ext]
              name: '[name]_[hash:8].[ext]',
              // 打包文件存放到出口目录下的images文件中
              outputPath: 'images/',
              limit: 8192, // 单位byte,文件小于8kb时返回base64文件,大于这个限制会返回地址
            }
          }
        ]
      }
    ]
  },
  plugins: [
    // 自动引入打包后的文件到html中:
    //    对于每次打包都会重新通过hash值来生成文件名的情况特别适用
    //    也可以通过template来生成一个我们自己定义的html模板,然后帮我们把打包后生成的文件引入
    new HtmlWebpackPlugin({
      filename: 'index.html', // 生成html文件的文件名
      template: absPath('../index.html') // 使用的html模板
    })
  ]
};
// webpack.dev.js
const merge = require('webpack-merge');
const baseConfig = require('./webpack.config')
module.exports = merge(baseConfig, {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map'
})
// webpack.prod.js
const merge = require('webpack-merge');
const baseConfig = require('./webpack.config')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = merge(baseConfig, {
  mode: 'production',
  devtool: 'cheap-module-source-map',
  plugins: [
    new CleanWebpackPlugin()
  ]
})

然后我们在package.json中分别为开发环境和生产环境添加打包快捷命令:

"scripts": {
  "build": "webpack --config ./config/webpack.prod.js",
  "start": "webpack --config ./config/webpack.dev.js"
},

现在目录结构是这样的:

03a24f4d03125fc522e11247a3a22959.png

接下来我们就可以直接使用yarn buildyarn start命令来分别为开发环境和生产环境进行打包了

webpackDevServer方便开发和调试

现在我们在每次修改代码后,都需要再次重新打包文件,并在浏览器中打开生成的html文件。而且由于是本地打开html文件,诸如请求代理、局域网内预览等功能便无法使用。

webpack-dev-server为我们提供了一个简单的web服务器,能够实时重新加载(live reloading)修改后的代码,并且也提供了如proxy等功能来支持我们跨域请求接口,极大的方便了开发。

yarn add webpack-dev-server -D

之后我们在开发环境的webpack配置中添加如下配置:

devServer: {
  // 告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要
  contentBase: absPath('../dist'),
  // 是否在启动服务时自动打开浏览器
  open: true,
  // 端口在没有设置的时候默认为8080
  port: 3000
}

当然,这样更改之后我们要通过webpack-dev-server来执行开发时的配置文件:

// "start": "webpack --config ./config/webpack.dev.js"
"start": "webpack-dev-server --config ./config/webpack.dev.js"

执行yarn start:

5cd476f4f17ef0433c627f9064bbe479.png

实现代码的热模块更新

当我们在开发过程中修改一些代码的时候,我们可能只是想让我们当前修改的内容生效,而不是造成整个页面的刷新,导致我们每次修改都要重新之前的步骤来验证我们的代码。

webpack中我们通过如下配置来实现模块热替换的功能(hot module replacement),当然这个功能只在开发环境开启:

// webpack.dev.js
devServer: {
  // 告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要
  contentBase: absPath('../dist'),
  // 是否在启动服务时自动打开浏览器
  open: true,
  // 端口在没有设置的时候默认为8080
  port: 3000,
  // 启用webpack的模块热替换特性
  hot: true
},
plugins: [
  new webpack.NamedModulesPlugin(),
  new webpack.HotModuleReplacementPlugin()
]

和之前配置的区别有2个:devServer添加配置项: hot: true 新增2个webpack的插件: webpack.NameModulesPluginwebpack.HotModuleReplacementPlugin

然后这样只能实现css文件的热更新,对于js的热更新,我们还需要添加一下代码:

// accept接收2个参数: 1. dependencies: 一个字符串或字符串数组  2. callback: 模块更新后触发的函数
if (module.hot) {
  module.hot.accept('./utils/printSomething', () => {
    console.log('update module');
  })
}

页面中的效果如下:

2c405b136c7ead9f20e1e99a4ace1771.png

大家可能会发现我们在写css和类似于vuereact框架代码的时候,并没有自己手写module.hot.accept方法,这是框架和cssloader已经帮我们进行了自动处理,我们只需要关注代码的书写即可。

使用babel转义es6语法

在日常工作中,我们会使用很多es6里的新语法,这些语法在我们目前使用的chrome新版浏览其中一般都可以很好的支持,但是在一些国产浏览器或者低版本浏览器中可能会出现兼容性问题。

这里我们需要通过babel-loader来进行语法的转义:

yarn add babel-loader @babel/core @babel/preset-env -D

webpack中进行配置:

// webpack.config.js 中添加一个loader配置项
{
  test: /.js$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true
    }
  }
},

项目根目录建立.babelrc文件,并加入如下代码:

{
  "presets": [
    "@babel/preset-env"
  ]
}

文档地址

这样配置之后,项目中的Promisemap等语法依旧不会进行转换,这里我们使用@babel/polyfill来转换这些语法:

yarn add @babel/polyfill -D

.babelrc进行如下配置:

{
  "presets": [
    [
      "@babel/env",
      {
        // 为低版本引入babel/polyfill
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1",
        },
        // 使用useBuiltIns要指定corejs
        "corejs": "2",
        // 只对项目中用到的`esnext`语法进行polyfill处理
        "useBuiltIns": "usage",
      }
    ]
  ]
}

这样配置之后就可以通过babel来转换esnext的一些语法,并且可以兼容低版本和国产浏览器。由于使用到了useBuiltIns:usage,只会对我们使用到的新语法进行转换,减少了polyfill的体积

配置react开发环境

在学习完以上内容以后,我们需要搭建一个支持react框架语法的webpack配置。

首先我们安装相应的依赖:

yarn add react react-dom
yarn add @babel/preset-react @babel/plugin-proposal-class-properties -D

.babelrc中配置如下:

{
  "presets": [
    [
      "@babel/env",
      {
        // 为低版本引入babel/polyfill
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1",
        },
        // 使用useBuiltIns要指定corejs
        "corejs": "2",
        // 只对项目中用到的`esnext`语法进行polyfill处理
        "useBuiltIns": "usage",
      }
    ],
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/plugin-proposal-class-properties"
  ]
}

之后我们在入口文件main.js中写入如下代码:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'

class App extends Component {
  state = {
    number: 10
  }
  render() {
    return (
      <div>
        hello Webapck React
        <h2>{this.state.number}</h2>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))

执行yarn start命令:

e8658281556644cc1ad07511f864b382.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值