webpack 学习笔记

作者: _月光临海 | 来源:发表于2018-05-11 22:21 被阅读0次

本文主要分为:

  • 环境配置
  • 使用配置文件
  • CSS 处理
  • ES6 代码编辑
  • 文件压缩
  • SASS 处理
  • CSS 与 JS 分离
  • 文件处理 file-loader 与 url-loader
  • 多入口及自动清理

客位看官可直接 ctrl + f 搜索对应关键字

环境配置
  • window + r ,输入 cmd 打开命令行

  • 新建并进入 webpack-3.10.0 文件夹

    mkdir webpack-3.10.0 && cd webpack-3.10.0
    
  • 使用 sublime text3subl.exe 打开该文件夹

    subl.exe
  • webpack-3.10.0 目录下初始化操作,生成 package.json 文件

    npm init -y
    

也可以直接使用 npm init 来初始化 package.json 文件,但这样需要手动填写项目名之类的东西,加上 -y 表示使用默认配置

npm init -y
  • 新建 src 文件夹,今后将要打包的文件全部放入该文件夹下

    新建 src 文件夹
  • src 下新建 main.js 并随便敲一点代码

    main.js
  • 安装 webpack

    npm install webpack@3.10.0 --save-dev
    

这里是安装指定版本号的 webpack,不加版本号则是最新版

安装完成

安装完成后的 package.json

package.json

安装完成后的项目目录


新增了 node_modules 目录
  • 修改 package.json

    增加执行脚本语句
  • 打包

    #  命令语句        源文件        目标文件
    npm run start src/main.js dist/bundle.js
    

如果没有 dist 目录则自动新建

打包
  • 打包结果


    打包后
  • webpack-3.10.0 目录下创建 index.html 文件,引入之前打包好的 bundle.js 文件

<!DOCTYPE html>
<html>
<head>
    <title>webpack-3.10.0</title>
</head>
<body>
    <h1>Hello World!</h1>
    <script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>
打包并引入成功
  • 我们同样可以把打包的语句直接写在 package.json 中,免得每次输入很麻烦
    "start":"webpack src/main.js dist/bundle.js"
    
image.png
这样我们在命令行中直接调用 npm run start 也能实现打包的效果
  • 现在有个问题,当我们修改 main.js 文件的内容时,刷新页面并不会显示更新的改动,如果想让页面同步的话,我们还需再执行一次 npm run start 语句,每次这样未免太麻烦,可以通过以下几种方式改善:
    • 方法一:修改 package.json 中之前写好的 start 语句
    "start":"webpack src/main.js dist/bundle.js --watch",
    
    • 方法二:新定义一个 watch 命令,这种方式根据官方文档说明,由于调用的是之前自定义的 npm run start 命令,因此需要在 --watch 前额外添加 --
    # package.json
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start":"webpack src/main.js dist/bundle.js",
      "watch":"npm run start -- --watch"
    },
    
package.json
以第二种方式为例:
监听成功
此时则监听成功,修改 main.js 保存则实时会在 bundle.js 中显示,页面中刷新即可展示;ctrl + c 终止监听。 实时监听
使用配置文件
  • 为了看出效果,我们先把之前生成的 bundle.js 文件删掉。
  • webpack-3.10.0 目录下创建 webpack.config.js ,并输入如下内容
#  webpack.config.js

var webpack = require("webpack");

module.exports = {
    entry:'./src/main.js', 
    output:{
        path:'./dist',        
        filename:'bundle.js'
    }
}

此时你的项目结构应该是这样的,dist 目录下 空空如也

dist 目录下为空
  • 跑一下试试

    报错
    原因是 output 中的路径需要是绝对路径 absolute path
  • 在配置文件中引入 path 模块解决绝对路径问题

    var webpack = require("webpack");
    var path = require("path");
    
    module.exports = {
        entry:'./src/main.js',
        output:{
            path:path.resolve(__dirname,'./dist'),
            filename:'bundle.js'
        }
    }
    
  • 由于添加了配置文件,因此需要修改一下 package.json 中的启动命令 npm run start 更改为如下(因为配置文件中已经设置了路径及文件名,因此不需要命令中再指定)

    "start":"webpack",
    
  • 跑一下


    跑跑
    同样是创建了 bundle.js 文件

    效果是一样的


CSS 处理
  • src 目录下创建 main.css
    # main.css
    body{
        background: orange;
    }
    
  • 修改 main.js
    # main.js
    require('./main.css')
    
  • 使用 npm run watch 命令会报错
    缺少 loader
    缺少 loader,这里引用官网说明:

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。

  • 处理 css 需要安装一个 css-loader 的包:
    npm install css-loader --save-dev
    
安装成功
  • 安装完成后需要在配置文件中进行处理,注意 module 属性:
# webpack.config.js

var webpack = require("webpack");
var path = require("path");

module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'bundle.js'
    },
    module:{
        rules:[{
            test:/\.css$/,  //  正则匹配 .css 后缀
            use:'css-loader'
        }]
    }
}

再跑一下

修改配置文件之后
看一下是否被打包到 bundle.js
bundle.js
可以看到 main.css 的样式的确被打包到 bundle.js 中了,但为什么浏览器中没有效果?
  • 安装 style-loader
npm install style-loader --save-dev
  • 修改配置文件,注意:style-loader 需要写在前面
    修改配置文件
  • 再调用命令
    npm run watch 
    
样式已注入
将 ES6 代码编辑为所有浏览器通用的代码
  • main.js 内容改为一段 ES6 的代码
    # main.js
    let a = 11;
    const b = 22;
    
    class Foo{
    
    }
    
  • 直接调用 npm run watch 会发现 bundle.js 中的代码依旧为 ES6
    尚未安装 ES6
  • 这时需要 Babel 这个工具

Babel 的作用就是将下一代的 JavaScript 语法转换为现今浏览器兼容的语句

  • 首先安装 Babel
    npm install --save-dev babel-loader babel-core
    
  • webpack.config.js 中添加一条规则:
    { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
    
    其中,test 用于判断扩展名为 .js 的文件,exclude 表示不包括的文件。
    添加规则后,此时的 webpack.config.js 文件应该是这样的
    添加规则
  • 安装转换 ES2015 及更高版本 JavaScript 语法的 env preset
    npm install babel-preset-env --save-dev
    
  • 在根目录 webpack-3.10.0 下创建 .babelrc 文件,内容如下:
    {
      "presets": ["env"]
    }
    
创建 .babelrc
  • OK,现在执行命令 npm run watch,可以看到我们之前 main.js 中的语句在 bundle.js 中已经成功转换成通用语句了
    main.js
    bundle.js
    本节内容可直接参考 Babel 官网:https://babeljs.cn/

文件压缩
  • 文件压缩需要用 webpack 的插件来实现,比如 webpack 自带一个 BannerPlugin 插件,用于添加顶部注释,首先在 webpack.config.js 中添加如下代码:
    plugins:[
      new webpack.BannerPlugin('顶部注释插件')
    ]
    
  • 重新打包 npm run watch,成功后,bundle.js 中顶部出现注释
    添加成功
  • webpack 有个自带的插件 UglifyJsPlugin 用于压缩文件
plugins:[
  new webpack.BannerPlugin('顶部注释插件'),
  new webpack.optimize.UglifyJsPlugin()
]

重新打包后的 bundle.js

压缩后的 bundle.js
  • 然而我们在开发调试阶段是不需要压缩代码的,因此需要对开发环境和线上环境做个区分,开发环境不压缩代码,线上环境才压缩
    if(process.env.NODE_ENV === 'production'){
        module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
    }
    
    如果是线上环境,则将 UngifyJsPlugin 插件填入 webpackplugins
  • 回到命令行调用命令
    set NODE_ENV=production  // 设置为生产环境, windows 系统
    npm run watch
    
切换线上环境并打包
  • 我们可以直接在 package.json 中添加脚本命令(我尝试了几种写法,发现只有这样是有效的,不知道为什么。此外,有时这样也不好用,需要在命令行中手动制定一次 set NODE_ENV=production,之后调用 npm run production 就有效了)
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start": "webpack",
      "watch": "npm run start -- --watch",
      "production":"set NODE_ENV=production && npm run watch",
      "development":"set NODE_ENV=development && webpack --watch"
    }
    

这样在命令行中通过 npm run development 即可切换为开发环境(代码不压缩),npm run production 就是生产环境(代码压缩)

开发生产环境切换
  • webpack.config.js 简单做一下整理
var webpack = require("webpack");
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production'

module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'bundle.js'
    },
    module:{
        rules:[{
            test:/\.css$/,
            use:['style-loader','css-loader']
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        }]
    },
    plugins:[
        new webpack.BannerPlugin('顶部注释插件'),
    ]
}

if(isProduction){
    module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}

SASS 处理
  • 安装相关 loader
    npm install sass-loader node-sass webpack --save-dev
    
  • 这里我在安装 node-sass 时失败了,改为分别单独安装,node-sass 使用淘宝镜像 其他解决方案
    # 安装 sass-loader
    npm install sass-loader --save-dev
    # 安装 node-sass
    npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
    
  • 修改配置文件
    # webpack.config.js
    
      module:{
          rules:[{
              test: /\.scss$/,
              use: [
                  "style-loader", // creates style nodes from JS strings
                  "css-loader", // translates CSS into CommonJS
                  "sass-loader" // compiles Sass to CSS
              ]
          },{
              test:/\.css$/,
              use:['style-loader','css-loader']
          },{ 
              test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
          }]
      },
    
  • 修改 mian.js
    # main.js
    require('./main.scss')
    
  • 修改 main.cssmain.scss 并输入 scss 语句测试
    # main.scss
    $default:pink;
    body{
        background:$default
    }
    

重新打包,OK


sass 打包
CSS 与 JS 分离
  • 通常 webpack 建议所有文件都打包成一个单独的文件,这样可以减少网络请求。但如果有需要分类打包的话,需要使用 webpack 的一个外部插件 ExtractTextWebpackPlugin
  • 安装
    npm install --save-dev extract-text-webpack-plugin
    
  • 修改配置文件,注意注释部分
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin"); //  引入插件
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production';


module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'[name].js'
    },
    module:{
        rules:[{
            test: /\.scss$/,
            use: ExtractTextPlugin.extract({        //  使用插件
                fallback: "style-loader",           //  用哪个 loader 加载
                use: [{
                    loader:"css-loader",
                    options:{
                        minimize:isProduction       //  是否压缩 css
                    }},
                    "sass-loader"]                  //  将资源转换为 css
            })
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        }]
    },
    plugins:[
        new webpack.BannerPlugin('顶部注释插件'),
        new ExtractTextPlugin("[name].css"),        //  输出为 style.css 文件
    ]
}

if(isProduction){
    module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}

文件处理 file-loader 与 url-loader
  • 首先在 src 目录下新建 images 目录并存入两个大小不一的图片

    新建目录并存入图片
  • index.htmlmain.scss 中引入两个图片

    index.html
    main.scss
  • 安装 file-loader

    npm install --save-dev file-loader
    
  • 修改配置文件

    module:{
        rules:[{
            test: /\.scss$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: [{
                    loader:"css-loader",
                    options:{
                        minimize:isProduction
                    }},
                    "sass-loader"]
            })
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        },{
            test:/\.png|jpe?g|gif$/,    // 匹配的图片格式
            use:['file-loader']         //  使用 file-loader
        }]
    }
    
  • 执行 npm run production,图片被打包并以 hash 方式重新命名

    图片打包
    打包后的 main.css
  • 也可以让图片以原有名字和后缀保存:

    {
          test:/\.png|jpe?g|gif$/,
          use:[{
              loader:'file-loader',
              options:{
                  name:'[name].[ext]'  // 以原有名字和后缀保存
              }
          }]
    }
    
原有名字和后缀
  • 也可以创建指定目录存放文件
    options:{
      name:'images/[name].[ext]'
    }  
    
    或,注意 outputPath/ 不能少
    options:{
      name:'[name].[ext]',
      outputPath:'images/'
    }
    

    效果就是这样


    我是效果
  • 至于 url-loader ,它可以限制图片的大小,小于一定值的图片将以 DataURL 直接嵌入在页面中,减少请求数
  • 安装
    npm install --save-dev url-loader
    
  • 修改配置文件
    use:[{
        loader:'url-loader',
        options:{
            limit:20480,    // 小于该值将嵌入页面
            name:'[name].[ext]',
            outputPath:'images/'
        }
    }]
    
  • 打包后可看到只有一个图片被打包,另一个图片直接嵌在了页面中:


    只有一张图片引入
    嵌入页面

多入口及自动清理
  • 尝试改一下入口属性
    entry:{app:'./src/main.js'},
    

这样生成的 jscss 文件将变成 app.jsapp.css

  • 先安装一个 jquery 包,注意名字小写
    npm install --save-dev jquery
    
  • 修改配置文件
    entry:{
        main:'./src/main.js',    // 将 main.js 打包成 main
        vendor:'jquery'          // 将 jquery 打包成 vendor
    }
    
多个入口
  • 自动清理需要 clean-webpack-plugin 插件
    npm install clean-webpack-plugin --save-dev
    
  • 如果我们在生成的文件中添加 hash 值会发现,每次打包由于 hash 导致名字的不同,进而会出现不同名的同文件,这显然不是我想要的。这个插件就可以用于每次打包前先清除指定目录或文件,避免重复。
  const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
    plugins: [
+     new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Output Management'
      })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

相关文章

网友评论

    本文标题:webpack 学习笔记

    本文链接:https://www.haomeiwen.com/subject/zjaarftx.html