Skip to content

Webpack 3.x 学习-第二天 #6

@shushu2013

Description

@shushu2013

Webpack 学习第三步

1、处理 css 文件

需要用到 css-loaderstyle-loader 加载器

参考资料:

css-loader GitHub 地址
style-loader GitHub 地址

安装 css-loaderstyle-loader

cnpm i -D style-loader css-loader

配置 webpack.config.js 中的 module 项中的 rules

module.exports = {

    // ... 省略其他配置项
    
    // 模块:例如转换 es6, less, 图片转换等...
    module: {
        rules:[
            {
                // 用正则去匹配要用该 loader 转换的 CSS 文件
                test: /\.css$/,
                use: ['style-loader', 'css-loader?minimize']
            }
        ]
    }
}

如上配置告诉 Webpack 在遇到以 .css 结尾的文件时先使用 css-loader 读取 CSS 文件,再交给 style-loaderCSS 内容注入到 JavaScript 里。 在配置 Loader 时需要注意的是:

  • use 属性的值需要是一个由 Loader 名称组成的数组,Loader 的执行顺序是由后到前的;
  • 每一个 Loader 都可以通过 URL querystring 的方式传入参数,例如 css-loader?minimize 中的 minimize 告诉 css-loader 要开启 CSS 压缩

style-loader 的工作原理大概是把 CSS 内容用 JavaScript 里的字符串存储起来, 在网页执行 JavaScript 时通过 DOM 操作动态地往 HTML head 标签里插入 HTML style 标签。

2、提取 CSS 文件

在上面重新执行构建后,你会发现 index.js 文件被更新了,里面注入了在 index.css 中的 CSS,而不是额外生成一个 CSS 文件,这里需要用到 Webpack 的插件,即 extract-text-webpack-plugin

参考资料:

extract-text-webpack-plugin GitHub 地址

安装 extract-text-webpack-plugin 插件

cnpm i -D extract-text-webpack-plugin

webpack 相关配置

const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {

    // ... 省略其他配置项
    
    module: {
        rules: [
            {
                // 用正则去匹配要用该 loader 转换的 CSS 文件
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    // 转换 .css 文件需要使用的 Loader
                    use: ['css-loader?minimize']
                })
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin({
          // 从 js 文件中提取出来的 css 文件的名称,前面可加存放路径
          filename: `css/[name]_[contenthash:8].css`,
        })
    ]
}

学习 Webpack 第四步

1、实现自动化,提高开发效率

1.1 自动化需求:

1、提供 HTTP 服务 而不是使用本地文件预览;
2、监听文件的变化并自动刷新网页,做到实时预览;
3、支持 Source Map ,以方便调试;

参考资料

webpack-dev-server GitHub 地址
DevServer 官方文档

1.2 webpack-dev-server 的安装及使用

安装

cnpm i -D webpack-dev-server

首先在 package.json 中配置 npm script 脚本命令来启动 webpack-dev-server

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

然后在 Webpack 配置文件的 devServer 配置项中对 webpack-dev-server 进行配置

const webpack = require('webpack');

module.exports = {

    // ... 省略其他配置项
    
    plugins: [
        new webpack.HotModuleReplacementPlugin()    // 开启模块热替换需要使用的插件
    ],
    // 配置 webpack 开发本地服务器功能
    devServer: {
        // 服务器的IP地址,默认为 localhost
        host:'localhost',
        // 服务端压缩是否开启
        compress:true,
        // 配置服务端口号,默认为 8080
        port:8000,
        // 使用默认浏览器自动打开网页
        open: true,
        // 开启模块热替换 (不刷新网页进行更新)
        hot: true
    }
}

webpack-dev-server 会把 Webpack 构建出的文件保存在内存中,在要访问输出的文件时,必须通过 HTTP 服务访问

这里开启模块热替换有两种方法:

方法一:通过 'webpack-dev-server' 命令行选项 '--hot' 来指定开启模块热替换

// 在 package.json 文件中配置 npm script 脚本命令
"scripts": {
    "dev": "webpack-dev-server --hot"
}


方法二:在配置文件的 'devServer' 选项中开启模块热替换时,需要在 'plugins' 配置项中加入  
'Webpack' 自带 'HotModuleReplacementPlugin' 插件,所以需要先引入 `webpack`,代码如下:  

const webpack = require('webpack');

module.exports = {

    // ... 省略其他配置项
    
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    // 配置 webpack 开发本地服务器功能
    devServer: {
        // 开启模块热替换 (不刷新网页进行更新)
        hot: true
        
        // ... 省略其他配置项
    }
}

如果使用方法二,没有引入 HotModuleReplacementPlugin 插件,网页控制台会显示出错信息: Uncaught Error: [HMR] Hot Module Replacement is disabled.

出错相关参考资料

GitHub 上相关的 issue
webpack-dev-server 官方文档相关说明

1.3、遇到的问题

1.2.1、构建失败,报错信息为:Cannot use [chunkhash] for chunk in 'js/[name]-[chunkhash:8].js' (use [hash] instead)

这里注意,如果开启了模块热替换,Webpack 构建打包不能使用 chunkhash 来给输出的文件命名,而应该使用 hash,否则构建会失败

module.exports = {
    // 入口文件的配置项
    entry: {
        index: './src/js/index.js'
    },
    // 出口文件的配置项
    output: {
        path: path.resolve(__dirname, 'dist'),
        // 当开启模块热替换时,使用 hash
        filename: 'js/[name]-[hash:8].js'
    }
    
     // ... 省略其他配置项
}

1.2.2、修改 css 文件后,页面并没有变化

原因是,使用了 ExtractTextPlugin 插件来提取 css 到一个独立的样式文件,而 ExtractTextPlugin 不支持模块热替换,因此不要单独提取 css

module.exports = {

    // ... 省略其他配置项
 
    module: {
        rules:[
            {
                // 用正则去匹配要用该 loader 转换的 CSS 文件
                test: /\.css$/,
                use: ExtractTextPlugin.extract({    // 从 js 文件中提取 css 
                    // 转换 .css 文件需要使用的 Loader
                    use: ['css-loader?minimize']
                })
            }
        ]
    }
}

改为

module.exports = {

    // ... 省略其他配置项
 
    module: {
        rules:[
            {
                // 用正则去匹配要用该 loader 转换的 CSS 文件
                test: /\.css$/,
                use:  ['style-loader', 'css-loader?minimize']
            }
        ]
    }
}

这时修改 css 文件会触发模块热替换, 因为 style-loader 会注入用于接受 CSS 的代码。

1.4 Source Map 配置

参考资料

webpack 官方文档 使用 Source Map
Devtool 官方文档

有两种方式

方法一:在 Webpack 配置文件中配置 devtool 选项即可

devtool 配置可选项很多,具体可参考上面的 Devtool 官方文档

常用的有如下四个:

  • source-map : 在一个单独文件中产生一个完整且功能完全的文件。这个文件具有最好的 source map,但是它会减慢打包速度;
  • cheap-module-source-map : 在一个单独的文件中产生一个不带列映射的 map ,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列;
  • eval-source-map : 使用 eval 打包源文件模块,在同一个文件中生产干净的完整版的 source map,但是对打包后输出的 JS 文件的执行具有性能和安全的隐患;
  • cheap-module-eval-source-map : 这是在打包文件时最快的生产 source map 的方法,生产的 source map 会和打包后的 JavaScript 文件同行显示,没有影射列;

如果大型项目可以使用 source-map,如果是中小型项目使用 eval-source-map 就完全可以

配置选项如下

module.exports = {

    // ... 省略其他配置项
    
    devtool: 'source-map'
}

方法二:在 webpack-dev-server 命令行选项加入 --devtool source-map 参数来指定以 source-map 的方式生成 Source Map--devtool 可选参数同方法一)

"scripts": {
    "dev": "webpack-dev-server --devtool source-map"
}

2、分离开发环境和生产环境配置

在上面使用 webpack-dev-server 开启模块热替换,提高开发效率的同时,需要对 Webpack 配置文件做相应的修改,其中一些修改和代码优化设置不兼容,这就迫使我们做出改变,针对 开发环境生产环境 ,分别使用不同的配置文件

开发环境Webpack 配置文件为 webpack.config.dev.js
生产环境Webpack 配置文件为 webpack.config.prod.js

package.json 中的构建脚本改为

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

webpack.config.dev.js 配置文件内容如下

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

module.exports = {
    // 入口文件的配置项
    entry: {
        index: './src/js/index.js'
    },
    // 出口文件的配置项
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'js/[name]-[hash:8].js'
    },
    // 模块:例如转换 es6, less, 图片转换等...
    module: {
        rules:[
            {
                // 用正则去匹配要用该 loader 转换的 CSS 文件
                test: /\.css$/,
                use:  ['style-loader', 'css-loader?minimize']
            }
        ]
    },
    // 插件,用于生产模板等各项功能
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({
            title: 'learn webpack',         // 标题
            template: './src/index.html',   // html 模板
            filename: 'index.html',         // 生成的 HTML 名称
            inject: 'true',                 // 引入生成的 js 文件,false 则不引入
            minify: {
                removeComments : true,      //去掉注释
                collapseWhitespace : true   //去掉空行
            }
        })
    ],
    // 配置 Source Maps
    devtool: 'source-map',
    // 配置 webpack 开发本地服务器功能
    devServer: {
        // 服务器的IP地址,默认为 localhost
        host:'localhost',
        // 服务端压缩是否开启
        compress:true,
        // 配置服务端口号,默认为 8080
        port:8000,
        // 使用默认浏览器自动打开网页
        open: true,
        // 开启模块热替换 (不刷新网页进行更新)
        hot: true
    }
}

webpack.config.prod.js 配置文件内容如下

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    // 入口文件的配置项
    entry: {
        index: './src/js/index.js',
        // list: './src/js/list.js'
    },
    // 出口文件的配置项
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'js/[name]-[chunkhash:8].js'
    },
    // 模块:例如转换 es6, less, 图片转换等...
    module: {
        rules:[
            {
                // 用正则去匹配要用该 loader 转换的 CSS 文件
                test: /\.css$/,
                use: ExtractTextPlugin.extract({    // 从 js 文件中提取 css 
                    // 转换 .css 文件需要使用的 Loader
                    use: ['css-loader?minimize']
                })
            }
        ]
    },
    // 插件,用于生产模板等各项功能
    plugins: [
        new CleanWebpackPlugin(['dist']),   //构建前,删除 dist 目录
        new HtmlWebpackPlugin({
            title: 'learn webpack',         // 标题
            template: './src/index.html',   // html 模板
            filename: 'index.html',         // 生成的 HTML 名称
            inject: 'true',                 // 引入生成的 js 文件,false 则不引入
            minify: {
                removeComments : true,      //去掉注释
                collapseWhitespace : true   //去掉空行
            }
        }),
        new ExtractTextPlugin({
            // 从 .js 文件中提取出来的 .css 文件的名称
            filename: 'css/[name]_[contenthash:8].css'
        })
    ]
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions