blog icon indicating copy to clipboard operation
blog copied to clipboard

webpack3使用说明

Open yanyue404 opened this issue 6 years ago • 0 comments

webpack 3

入门命令

随后会用webpack-dev-server替代 基本构建

webpack src/app.js dist/app.bundle.js

开发环境实时构建

webpack --watch 

生产环境中构建

webpack -p

其他

  • webpack -d – 包含资源地图
  • webpack --colors - 让编译的输出内容带有颜色

html-webpack-plugin

自动生成html文件,指定模板,添加hash,mini

$ npm install html-webpack-plugin --save-dev
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/app.js',
  output: {
    path: __dirname + '/dist',
    filename: 'app.bundle.js'
  },
  plugins: [new HtmlWebpackPlugin({
    template: './src/index.html',
    filename: 'index.html',
    minify: {
      collapseWhitespace: true,
    },
    hash: true,
  })]
};

css-loader

$ npm install --save-dev css-loader style-loader
 module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      }
    ]
  }
  • sass-loader
$ npm install sass-loader node-sass --save-dev
# 安装(中间可能要下载二进制包,要耐心等待)
import css from './app.scss';
 rules: [
      {
        test: /\.scss$/,
        use: [ 'style-loader', 'css-loader', 'sass-loader' ]
      }
  • extract-text-webpack-plugin

用 extract-text-webpack-plugin 把 CSS 分离成文件

有时候我们要把 SASS 或 CSS 处理好后,放到一个 CSS 文件中,用这个插件就可以实现。

$ npm install --save-dev extract-text-webpack-plugin

webpack-dev-server

# 先全局安装
$ npm install -g [email protected]
$ npm install [email protected] --save-dev
$ npm install webpack-cli -D

自动打开,切换端口号

module.exports = {
  entry: './src/app.js',
  ...
  devServer: {
    port: 9000,
    open: true
  },
  ...
};

然后运行命令:

$ webpack-dev-server

webpack 和 babel 配置 react 开发环境

3.在 webpack 使用 babel-loader

最后我们需要在 webpack 中使用一个 loader 来转化 react 的代码。 首先,安装。

$ npm install --save-dev babel-loader
var HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: './src/app.js',
  ...
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          //resolve-url-loader may be chained before sass-loader if necessary
          use: ['css-loader', 'sass-loader']
        })
      },
      // 这两行是处理 react 相关的内容
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
      { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }
    ]
  }
};

4. 写 react 组件

src/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hello World</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>

src/app.js

import css from './app.scss';

import React from 'react';
import ReactDOM from 'react-dom';
import Root from './Root';

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

src/Root.js

import React from 'react';

export default class Root extends React.Component {
  render() {
    return (
      <div style={{textAlign: 'center'}}>
        <h1>Hello World</h1>
      </div>);
  }
}

用 clean-webpack-plugin 来清除文件

生产环境每次执行npm run build都会在dist文件目录生成新的app.bundle.d01ae8858971a17f8ed2.js ,再多运行几次,生成的带 hash 的 app.bundle.js 文件就会很多。

这些带 hash 的 app.bundle.js 只有最新的才有用,其他的都没用,我们要在 build 之前把它们全清空:

$ npm i clean-webpack-plugin --save-dev

webpack.config.js

const path = require('path')
...
const CleanWebpackPlugin = require('clean-webpack-plugin');

let pathsToClean = [
  'dist',
]

module.exports = {
  entry: {
    "app.bundle": './src/app.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  ...
  plugins: [
    new CleanWebpackPlugin(pathsToClean),
    ...
    new ExtractTextPlugin('style.css')
  ],
  ...
};

现在运行 npm run build 试试,只有下面的文件:

dist
├── app.bundle.0e380cea371d050137cd.js
├── index.html
└── style.css

配置多个 HTML 文件

module.exports = {
  entry: {
    "app.bundle": './src/app.js',
    // 这行是新增的。
    "contact": './src/contact.js'
  },
  ...
  plugins: [
    new CleanWebpackPlugin(pathsToClean),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
      minify: {
        collapseWhitespace: true,
      },
      hash: true,
      // 这行是新增的。
      excludeChunks: ['contact']
    }),
    new HtmlWebpackPlugin({
      template: './src/contact.html',
      filename: 'contact.html',
      minify: {
        collapseWhitespace: true,
      },
      hash: true,
      // 这行是新增的。
      chunks: ['contact']
    }),
    new ExtractTextPlugin('style.css')
  ],
  ...
};

上面的 excludeChunks 指的是不包含, chunks 代表的是包含。

使用 pug (jade) 作为 HTML 的模板

pug,nodejs的html模板

npm install --save-dev pug pug-html-loader raw-loader

src/index.pug

doctype html
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) bar(1 + 5)
  body
    h1 Pug - node template engine
    #root
    #container.col
      if youAreUsingPug
        p You are amazing
      else
        p Get on it!
      p.
        Pug is a terse and simple templating language with a
        strong focus on performance and powerful features.

webpack.config.js


module.exports = {
  ...
  plugins: [
    ...
    new HtmlWebpackPlugin({
      template: './src/index.pug',
      ...
    }),
    ...
  ],
  module: {
    rules: [
      ...
      { test: /\.pug$/, loader: ['raw-loader', 'pug-html-loader'] }
    ]
  }
};

我们来试试 pug 的 include 功能,就是可以包含子模板。

...
  body
    include includes/header.pug
    ...

src/includes/header.pug

  h1 from header pug file

目录结构是这样的:

src
├── Root.js
├── app.js
├── app.scss
├── contact.html
├── contact.js
├── includes
│   └── header.pug
└── index.pug

如何使用模块热替换 HMR 来处理 CSS

1.启用 HMR

webpack.config.js

  devServer: {
    port: 9000,
    open: true,
  }

改成下面这样:

 devServer: {
    port: 9000,
    open: true,
    hot: true
  }

webpack.config.js

...
const webpack = require('webpack');

...

module.exports = {
  entry: {
    "app.bundle": './src/app.js',
    "contact": './src/contact.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  devServer: {
    port: 9000,
    open: true,
    hot: true
  },
  plugins: [
    new CleanWebpackPlugin(pathsToClean),
    ...
    // 这两行是新增的
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  ...
};

报错!!!文件名还不能用 chunkhash 了,它说要用 hash 来代替 chunkhash。

chunkhash是每个文件都使用不同的hash值

filename: '[name].[chunkhash].js'

hash指每个文件使用相同的hash值

filename: '[name].[hash].js'

2.处理 extract-text-webpack-plugin

现在你试一下改变 src/app.scss 的内容,你会发现页面不动了,你无论怎么改,页面都不会改变,也不会刷新。

之前我们是用 extract-text-webpack-plugin 这个插件来处理 CSS 的,在用 HMR 的时候要先把它关闭一下。

用一个参数 disable: true 就可以关闭掉。

webpack.config.js

new ExtractTextPlugin("style.css")

变成

new ExtractTextPlugin({
  filename: 'style.css',
  disable: true
}),

然后把处理 scss 文件的 loader 部分变成类似下面这样:

...
  test: /\.scss$/,
  use: ExtractTextPlugin.extract({
    fallback: 'style-loader',
    //resolve-url-loader may be chained before sass-loader if necessary
    use: ['css-loader', 'sass-loader']
  })
...

变成

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

再试试,能够生效。

为什么要关闭呢这个插件呢?

其实想想也能知道,在开发环境下,用不用 extract-text-webpack-plugin 这个插件,意义不大,你把 css 变不变成一个文件,关系不大,开发环境只要能调效,效果能够看到就可以,但是生产环境需要这个插件,我们总不能开发环境不使用这个插件,也导致生产环境也不使用吧?

那如何解决这个问题呢?也就是说让生产环境使用这个插件,而开发环境不使用.

生产环境 vs 开发环境

要让生产环境使用 extract-text-webpack-plugin 这个插件,而开发环境不使用,如何做到呢?

其实原理很简单,只要能区分出哪个是开发环境,哪个是生产环境就可以,只要判断是生产环境的时候就用,不是的话...

1. 增加环境变量

首先来看一下之前的开发环境和生产环境分别使用的编译命令:

webpack.config.js

"scripts": {
  "dev": "webpack-dev-server",
  "prod": "webpack -p"
},

分别是开发环境使用的 npm run dev 命令和生产环境使用的 npm run prod 命令。

我们把它改成下面这样:

"scripts": {
  "dev": "webpack-dev-server",
  "prod": "NODE_ENV=production webpack -p"
},

开发环境的部分不变,生产环境的加了一个环境变量:

NODE_ENV=production

很简单,NODE_ENV 是变量名,而 production 是 NODE_ENV 是这个变量的值,这些都不是固定的,你可以改成你想要的任意内容,只要能引用到就行了。

那么我们如何来使用这个变量呢?

2.使用环境变量

要引用我们之前创建的环境变量,也蛮简单的。

在 webpack.config.js 文件中:

var isProd = process.env.NODE_ENV === 'production'; // true or false

process.env.NODE_ENV 就能得到之前设置的变量,如果运行的是 npm run prod,那么 process.env.NODE_ENV为true

上一节,我们有类似下面这样的两段关于 extract-text-webpack-plugin 这个插件的代码。

new ExtractTextPlugin({
  filename: 'style.css',
  disable: false
}),

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

我们把 webpack.config.js 中的代码更改如下:

...
// 线上线下切换 css-loder
var isProd = process.env.NODE_ENV === 'production'; // true or false
var cssDev = ['style-loader', 'css-loader', 'sass-loader'];
var cssProd = ExtractTextPlugin.extract({
  fallback: 'style-loader',
  //resolve-url-loader may be chained before sass-loader if necessary
  use: ['css-loader', 'sass-loader']
})

var cssConfig = isProd ? cssProd : cssDev;

module.exports = {
  ...
  plugins: [
    ...
    new ExtractTextPlugin({
      filename: 'style.css',
      disable: !isProd
    }),
    ...
  ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: cssConfig
      },
      ...
    ]
  }
};


只要能区别出不同的环境,使用不同的配置内容就可以了。

现在就可以放心地使用 npm run dev 和 npm run prod 命令了,再也不用临时关掉一些插件了。

3.window平台使用

windows平台:不能直接使用NODE_ENV, 步骤如下:

1.npm install cross-env --save-dev

2.命令改为 "prod": "cross-env NODE_ENV=production webpack -p"

如何打包图片

src/app.scss

body {
  background: url('./images/logo.png') 0 0 no-repeat;
  ...
}

然后 npm run dev,你会发现类似下面的错误: 只要找到适合的 loader 来处理扩展名为 png 的图片文件即可。

1.file-loader

file-loader

安装

$ npm install --save-dev file-loader

2. file-loader 的参数

其实,file-loader 是可以带参数的,例如下面这样:

test: /\.(gif|png|jpe?g|svg)$/i,
use: [
  {
    loader: 'file-loader',
    options: {
      name: '[name].[ext]',
      outputPath: 'images/'
    }
  },

/\.(gif|png|jpe?g|svg)$/i 表示可以处理好多图片的格式,毕竟不只是 png 才是图片,别的扩展名的文件也可能是图片嘛。

[name] 代表文件名,[ext] 代表文件扩展名,outputPath 是输出的路径。

3.解析 html 代码里面 img 的标签

忘了一个重要的地方,之前我们是在 CSS 里引用图片作为背景的,但是,我们经常是在 html 直接使用 src 标签

例如下面这样:

<img src="./images/money-bag.svg" alt="" height=50>

src/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <img src="./images/money-bag.svg" alt="" height=50>
</body>
</html>

然而结果是这样的:404了,文件找不到,没有成功。

其实缺少了一个在 html 代码里处理 img 标签的 loader。

这个 loader 是 html-loader

官方对它的定义是这样的:

Exports HTML as string. HTML is minimized when the compiler demands.

大概意思是说,把 html 变成导出成字符串的过程中,还能进行压缩处理(minimized)。

现在我们来加上这个 loader。

先安装。

$ npm install --save-dev html-loader
...
{
  test: /\.(gif|png|jpe?g|svg)$/i,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: '[name].[ext]',
        outputPath: 'images/'
      }
    },
  ]
},
// 下面几行才是 html-loader 的配置内容
{
  test: /\.html$/,
  use: [ {
    loader: 'html-loader',
    options: {
      minimize: true
    }
  }],
}
...

再试试发现就可以了。

4. 压缩图片

有时候图片太大,我们输出到生产环境的时候,希望可以让图片文件的体积小点,webpack 也可以轻易办到,就是自动压缩图片,然后生产环境拿到的图片就会很小。

还是用一个插件,这个插件叫 image-webpack-loader

这个插件主要是来压缩图片文件的。

安装。

$  npm install image-webpack-loader --save-dev

webpack.config.js

{
  test: /\.(gif|png|jpe?g|svg)$/i,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: '[name].[ext]',
        outputPath: 'images/'
      }
    },
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
},
{
  test: /\.html$/,
  use: [ {
    loader: 'html-loader',
    options: {
      minimize: true
    }
  }],
}

源文件的图片大小情况是这样的:

$ ls -lh src/images
total 256
-rw-r--r--@ 1 hfpp2012  staff   112K Nov  3 23:10 logo.png
-rw-r--r--@ 1 hfpp2012  staff    11K Dec  4 16:32 money-bag.svg

而压缩后(npm run prod):

$ ls -lh dist/images
total 96
-rw-r--r--  1 hfpp2012  staff    33K Dec  4 21:34 logo.png
-rw-r--r--  1 hfpp2012  staff   8.5K Dec  4 21:34 money-bag.svg

由上面的对比可知,压缩后体积减少了一些。

当然这个插件,肯定还有更多的用法,具体查看 readme 文档吧。

参考

  • https://www.rails365.net/playlists/webpack-3-ling-ji-chu-ru-men-shi-pin-jiao-cheng
  • https://github.com/ruanyf/webpack-demos
  • https://github.com/meishadevs/webpack-demos/blob/master/README.md

补充

  • https://www.jianshu.com/p/c0bec50ec385

yanyue404 avatar May 31 '18 11:05 yanyue404