Webpack4之开发环境搭建

上次体验了 Webpack4 的零配置,现在进行 Webpack4 开发环境搭建。

目录
  1. 本地安装依赖
  2. 创建配置文件
  3. 配置入口和输出
  4. 配置插件html-webpack-plugin
  5. 配置 Loader
    1. 解析 CSS
    2. 解析 ES6 语法的js文件
    3. 解析图片文件
    4. 其他 Loader
  6. 配置webpack-dev-server
  7. webpack 常用插件
  8. 补充 2018.6.30
  9. 总结

上次体验了 Webpack4 的零配置,现在进行 Webpack4 开发环境搭建。

本地安装依赖#

npm install webpack webpack-cli --save-dev

创建配置文件#

touch webpack.config.js

为了方便调试,在package.json中编写脚本命令

{
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  }
}

配置好后就可以根据开发环境和生产环境,使用npm run devnpm run build命令打包文件。

配置入口和输出#

// webpack.config.js
const path = require("path");
const config = {
  // 入口
  entry: "./src/main.js", // 入口文件
  // 输出
  output: {
    path: path.join(__dirname, "/dist"), // 输出路径
    filename: "js/[name]-[chunkhash:8].js", // 输出文件的名字
    // publicPath: './', html引用的路径前面会加上'./'
  },
};

测试:在index.js输入代码,运行npm run dev命令, 看下是否打包成功。 可以把打包后的文件引用到html文件中去看看效果。不过每次都要手动引用,会发现很麻烦。

<script src="./dist/js/main-xxxxxxxx.js"></script>

下面需要使用html-webpack-plugin插件,自动生成html文件。

配置插件html-webpack-plugin#

npm install html-webpack-plugin --save-dev // 本地安装
// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const config = {
  // ...
  plugins: [new HtmlWebpackPlugin()],
};

运行npm run dev试试,是否发现在 dist 文件夹下面生成了一个index.html文件,

生成的 html 还自动引用了打包后的 js 文件呢!这个插件还可以配置很多参数,看下面代码:

// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const config = {
  plugins: [
    new HtmlWebpackPlugin({
      template: "index.html", // 参照模板
      filename: "index.html", // 输入名称
      inject: true, // 静态文件是否注入和注入的位置('head','body')
      title: "webpack-demo", // 自定义标题
      date: new Date(), // 自定义时间
      // minify: {      // 压缩html
      //   collapseWhitespace: true,  // 去掉不必要的空格
      //   removeComments: true,      // 去掉注释
      //   removeAttributeQuotes: true  // 去掉属性值的引号
      // }
    }),
  ],
};

自定义标题和时间,需要在模板里配置相应的模板语言才能实现,这里以ejs模板语言为例

<!-- index.html -->
<head>
  <meta charset="UTF-8" />
  <title><%= HtmlWebpackPlugin.options.title %></title>
</head>
<body>
  <%= HtmlWebpackPlugin.options.date %>
</body>

也可以自定义js注入

// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const config = {
  plugins: [
    new HtmlWebpackPlugin({
      // ...
      inject: false,
    }),
  ],
};

ejs

<body>
  <script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
</body>

ps:上面的属性HtmlWebpackPlugin.files.chunks.main.entry是怎么得来的呢?

其实可以遍历HtmlWebpackPlugin这个插件,可查询到一系列参数和属性,

这对于配置和学习,非常有帮助,代码如下:

<body>
  <% for (key in HtmlWebpackPlugin.options) { %> <%= key %>: <%=
  JSON.stringify(HtmlWebpackPlugin.options[key]) %> <% } %> <% for (key in
  HtmlWebpackPlugin.files) { %> <%= key %>: <%=
  JSON.stringify(HtmlWebpackPlugin.files[key]) %> <% } %>
</body>

配置 Loader#

Webpack 默认只能解析js文件(ES5), 解析其他的文件比如.cssES6.vue.styl等文件需要配置相应的 Loader。

解析 CSS#

npm install css-loader style-loader --save-dev  # 下载解析的 Loader
// webpack.config.js
const config = {
  module: {
    // 规则
    rules: [
      {
        test: /\.css$/, // 正则表达式匹配
        use: ["style-loader", "css-loader"], // 相关loader
      },
    ],
  },
};

说明:css-loader是解析css文件的,style-loader是把css文件注入到html中的。

如果需要在打包后的 CSS 里一些 CSS3 属性前自动加上一些兼容性的前缀的话,还需要下载postcss-loaderautoprefixer这两个库。

npm install postcss-loader autoprefixer --save-dev  # 下载相关依赖
// webpack.config.js
// ...
{
  test: /\.css$/,
  use: [
    'style-loader',
    'css-loader',
    {
      loader: 'postcss-loader',
      options: {                       // 选项参数配置
        ident: 'postcss',
        plugins: [
          require('autoprefixer')({
            browsers: ['last 5 version']
          })
        ]
      }
    }
  ]
}
// ...

注意postcss-loader位置放在最后面,表示最先使用这个 Loader 来解析css文件。

如果你是用了 CSS 的预处理器,比如LessSass/ScssStylus,需要下载对应的 Loader。

比如我比较喜欢使用的是Stylus预处理器,需要安装下面的依赖

npm install stylus-loader stylus --save-dev  # 下载相关依赖

注意:stylusstylus-loaderLoader 的依赖,需要一起下载

// webpack.config.js
// ...
{
  test: /\.styl$/,
  use: [
    'style-loader',
    'css-loader',
    {
      loader: 'postcss-loader',
      options: {
        ident: 'postcss',
        plugins: [
          require('autoprefixer')({
            browsers: ['last 5 version']
          })
        ]
      }
    },
    'stylus-loader'
  ]
}
// ...

注意stylus-loader位置放在最后面,表示最先使用这个 Loader 来解析css文件。

解析 ES6 语法的js文件#

npm install babel-loader babel-core babel-preset-env --save-dev  下载loader和相关依赖
// webpack.config.js
{
  test: /\.js$/,
  include: /src/,  // 只解析src目录
  // exclude: /dist/,  // 解析不包含dist目录
  use: {
    loader: "babel-loader",
    options: {
      "presets": ["env"]
    }
  },
},

解析图片文件#

npm install url-loader file-loader --save-dev  # 下载相关依赖
// webpack.config.js
{
  test: /\.(git|png|jpe?g|svg)$/,
  loader: 'url-loader',
  options: {
    limit: 10000
  }
}

说明:limit: 10000表示解析的文件小于 10000 字节时使用base64格式转码,而大于 10000 字节时使用file-loaderLoader 解析。

其他 Loader#

// webpack.config.js
{
  test: /\.html$/,
  loader: 'html-loader'
}
{
  test: /\.vue$/,
  loader: 'vue-loader'
}

其他的 Loader,匹配相应的格式,在下载相应的 Loader 解析就行了。

使用 Vue 框架的话,需要使用vue-loader来解析.vue文件,当然你也可以使用官方提供的脚手架vue-cli来搭建项目。

配置webpack-dev-server#

webpack-dev-server可以开启一个本地服务器,方便我们开发。

安装webpack-dev-server

npm install webpack-dev-server --save-dev  # 本地安装

编写脚本命令

{
  "scripts": {
    "server": "webpack-dev-server"
  }
}

配置webpack.config.js文件

// webpack.config.js
config.devServer = {
  contentBase: path.resolve(__dirname + "/dist"), // 加载页面目录
  inline: true, // 内联模式
  hot: true, // 是否显示热模块替换记录,console会显示logger
  host: "0.0.0.0", // 地址
  port: 9000, // 端口
};

webpack-dev-server有一个非常强大的功能 HMR,叫热模块替换,也叫热更替。就是你修改了文件(比如 css 样式,js 代码)后,不用去刷新页面,HMR 会自动更新修改的模块,在网页直接显示出来,非常方便快捷,提高开发效率。

需要配置热模块替换插件,热模块替换才会生效。

// webpack.config.js
const webpack = require("webpack");
const config = {
  // ...
  plugins: [
    // ...
    new webpack.HotModuleReplacementPlugin(),
  ],
};

注意:每次修改 Webpack 的配置文件后,都需要重新执行编译命令。

我们开发时经常需要去后台取数据,但是有时候后端没弄好,我们可以自己去 mock 数据,webpack-dev-server也可以提供这个功能,它可以启动一个服务器模拟后端数据。

我们先去创建一段 json 数据,比如:

{
  "name": "hale",
  "gender": "male",
  "lang": ["javascript", "python"]
}

然后配置服务:

const data = require("./data.json"); // 先导入 json 数据
config.devServer = {
  before(app) {
    app.get("/api/data", function (req, res) {
      res.json({
        errno: 0, // 自定义一个状态码,方便后面取数据时判断是否成功
        data: data, // 赋值
      });
    });
  },
  // ...
};

npm run server再次启动devServer时,在浏览器地址栏输入127.0.0.1:9000/api/data,可以查看到 json 数据已经显示出来,后面直接通过访问这个 URL 就可以获取数据了。

webpack 常用插件#

Webpack 除了上面列举的插件外,还有一些插件也非常好用,下面列举几个:

// webpack.config.js
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const config = {
  // ...
  plugins: [
    // ...
    new webpack.NamedModulesPlugin(), // 显示热更新模块的名称
    new webpack.NoErrorsPlugin(), // 不显示错误插件
    new ExtractTextPlugin({
      // 抽离css样式,还需要在loader下配置,请参考相关文档
      filename: "css/[name]-[contenthash].css", // 重命名
      allChunks: true,
    }),
    new OptimizeCSSPlugin(), // 压缩分离出来的css
    new CopyWebpackPlugin([
      {
        // 拷贝文件
        from: path.join(__dirname, "./static"),
        to: path.join(__dirname, "./dist/static"),
        ignore: [".*"],
      },
    ]),
  ],
};

上面列举了几个常用的插件,这些插件都需要安装后才能使用。有的插件需要下载最新版才能在 Webpack4 中正常使用,插件的参数需要根据实际开发来配置,请查看插件的文档。另外一些未例举的插件在 Webpack4 有改动或者删除了,请查看插件的迁移文档。

补充 [2018.6.30]#

1.mode设置为development时,会将process.env.NODE_ENV的值设为development,并且提供了一些开发环境的默认配置,比如启用NamedChunksPluginNamedModulesPlugin插件等。

2.model设置为production时,会将process.env.NODE_ENV的值设为production,并且提供了一些生产环境的默认配置,比如启用NoEmitOnErrorsPlugin插件等。

  1. 提取 CSS 文件的插件extract-text-webpack-plugin在 Webpack4 中被弃用,需要使用mini-css-extract-plugin库。

  2. 提取公共代码的插件CommonsChunkPlugin在 Webpack4 中被弃用,改为配置optimization.splitChunksoptimization.runtimeChunk属性。

总结#

Webpack 是目前最流行的前端工程化工具之一,本文讲的都是一些入门的粗浅知识,以后还会补充一些高级内容。

可参考我搭建的 Vue 开发环境,比文中要详细很多,并且区分开发环境和生产环境,另外还有eslint等配置。

如需了解vue-cli2的关于 Webpack3 的配置,请查看vue-cli2-webpack-comment,有较详细的注释(个人理解)。

最后,如果需要更加深入学习了解 Webpack,请查看官方文档,建议查看英文文档,里面有最新的内容。