Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack3使用说明 #33

Open
yanyue404 opened this issue May 31, 2018 · 0 comments
Open

webpack3使用说明 #33

yanyue404 opened this issue May 31, 2018 · 0 comments

Comments

@yanyue404
Copy link
Owner

yanyue404 commented May 31, 2018

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 webpack-dev-server@2.9.1
$ npm install webpack-dev-server@2.9.1 --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 文档吧。

参考

补充

@yanyue404 yanyue404 changed the title webpack使用说明 webpack3使用说明 Jun 28, 2018
@yanyue404 yanyue404 added Css and removed tools labels May 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant