美文网首页程序员
webpack教程_由浅入深的webpack配置

webpack教程_由浅入深的webpack配置

作者: 哔咖丘 | 来源:发表于2017-07-30 12:19 被阅读0次

前言

少侠,愿你页底归来,已习得webpack精要。

那些你熟悉的概念

那些你熟悉的概念

入口起点

  • 字符串语法
module.exports = {
    entry: './usage/index.js'
}
  • 数组语法
    向 entry 属性传入「文件路径(file path)数组」将创建多个主入口
module.exports = {
    entry: ['./plugins/hello.js','./usage/index.js']
}

问题:数组语法跟主入口文件引入依赖文件有什么区别?

  • 对象语法
module.exports = {
    entry: {
        "usage.index": './usage/index.js',
        "usage.main": './usage/main.js'
    }
}

输出

const path = require('path');
module.exports = {
    entry: {
        "usage.index": './usage/index.js',
        "usage.main": './usage/main.js'
    },
 
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'usage/dist/js'),
        publicPath: '/js/'
    }
}

说明:
publicPath:声明资源对外链接,如上配置可以通过<script src="/js/usage.index.js">去访问你的js资源。

加载器(Loaders)

loader是对应用程序中的资源进行转换。他们是函数,可以将文件资源作为参数来源,经过一番处理后返回性的文件资源。类似于fis3或者gulp中的插件

  • 通过webpack.config.js配置
const path = require('path');
module.exports = {
    entry: {
        "usage.index": './usage/index.js',
        "usage.main": './usage/main.js'
    },
  
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'usage/dist/js'),
        publicPath: '/js/'
    },
    rules: [{
        test: /\.css$/,
        use: [
            'style-loader',
            'css-loader?modules',
        ]
    }]
}
  • 通过require或CLI
require('style-loader!css-loader?modules!./styles.css');
 
webpack --module-bind jade --module-bind 'css=style!css'

说明:webpack通过「!」区分加载器。

  • 加载器是如何解析的?
    loader遵循标准的模块解析,多数情况下,从模块路径解析(通常将模块路径认为是npm install 的node_module路径)。

插件

插件是webpack的支柱功能,它的目标在于解决loader无法实现的其他事。webpack插件是一个具有apply 属性的javascript对象。

  • 使用配置
const path = require('path');
module.exports = {
    entry: {
        "usage.index": './usage/index.js',
        "usage.main": './usage/main.js'
    },
  
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'usage/dist/js'),
        publicPath: '/js/'
    },
    rules: [{
        test: /\.css$/,
        use: [
            'style-loader',
            'css-loader?modules',
        ]
    }],
     
    plugins: [
        new ManifestPlugin({
            fileName: 'manifest.json',
            basePath: './build/',
            seed: {
                name: 'My Manifest'
            }
        })
    ]
}

说明:这里使用的是一个缓存插件,具体的作用我们后续讲解。

那些我模糊的名词

那些我模糊的名词

模块

  • 模块的解析规则
    模块的解析原理是将路径转化为最终的绝对路径,然后根据这个路径找到相应模块。
    绝对路径:
    import "/home/me/file";
    import "C:\\Users\\me\\file";
    
    相对路径:
    import "../src/file1";
    import "./file2";
    
    说明:在这种情况下,出现 import 或 require 的资源文件的目录被认为是上下文目录。
    模块路径:
     import "module";
     import "module/lib/file";
    
    设置为模块路径时,模块将在 resolve.modules 中指定的所有目录内搜索。也通过 resolve.alias 配置为模块路径创建别名,eg:
     const path = require('path');
     module.exports = {
       entry: {
         "usage.index": './usage/index.js',
         "usage.main": './usage/main.js'
        },
        output: {
          filename: '[name].js',
          path: path.resolve(__dirname, 'usage/dist/js'),
          publicPath: '/js/'
        },
        rules: [{
          test: /\.css$/,
          use: [
              'style-loader',
              'css-loader?modules',
          ]
        }],
        plugins: [
          new ManifestPlugin({
              fileName: 'manifest.json',
              basePath: './build/',
              seed: {
                  name: 'My Manifest'
              }
          })
        ],
        resolve: {
          alias: {
            "jquery": path.resolve(__dirname, 'src/js/libs/jquery-1.11.1.min.js')
          }
        }
    }
    

依赖图表

从入口点开始,webpack 递归地构建一个依赖图表,这个依赖图表包括你应用所需的每个模块,然后将所有模块打包为少量的包(bundle) - 通常只有一个包 - 可由浏览器加载。

构建目标

因为服务端可浏览器端代码都可以用JavaScript编写,因此,webpack提供了 nodeweb 两种类型的构建,我们可以通过设置构建目标实现不同类型的构建。

  • 如何配置?
const path = require('path');
module.exports = {
    target: 'node',  // 默认是web,可以省略
    entry: {
        "usage.index": './usage/index.js',
        "usage.main": './usage/main.js'
    },
  
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'usage/dist/js'),
        publicPath: '/js/'
    }
    // ...
}

通过 module.exports = [clientConfig, serviceConfig],的方式实现多target配置。

  • 模块热替换(HMR)
    模块热替换功能会在应用程序运行过程替换、添加或删除模块。这使得你可以在独立模块变更后,无需刷新浏览器页面,就可以更新这些模块,极大地提高开发效率。
  • 如何配置?
const path = require('path');
const webpack = require('webpack');
 
module.exports = {
    target: 'node',  // 默认是web,可以省略
    entry: {
        "usage.index": './usage/index.js',
        "usage.main": './usage/main.js'
    },
  
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'usage/dist/js'),
        publicPath: '/js/'
    },
     
    plugins: [
        // 开启全局的模块热替换(HMR)
        new webpack.HotModuleReplacementPlugin(),
        // 当模块热替换(HMR)时在浏览器控制台输出对用户更友好的模块名字信息
        new webpack.NamedModulesPlugin(),
    ],
 
    rules: [{
        test: /\.css$/,
        use: [
            'style-loader',
            'css-loader?modules',
        ]
    }],
    // ...
}

你的入口index.js:

import _ from 'lodash';
import styles from './css/main.css';
function component () {
    let element = document.createElement('div');
    element.innerHTML = _.join(['hello', 'webpack'],' ');
    return element;
}
document.body.appendChild(component());

说明:在该配置下,修改 mian.css 样式表后,不需要刷新浏览器页面即可看到更新。
问题:在入口index.js文件中引入样式表,那么最终样式表会跟js文件一起打包,如此会影响到页面的加载性能。那么要如何分离呢?
Answer: 使用 extract-text-webpack-plugin 解决你的问题。

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

module.exports = {
  // ...
  plugins: [
    new ExtractTextPlugin('dist/style.css')  // 不支持热替换
  ],
  module: {
    rules: [{
      test: /\.css$/,
      use: ExtractTextPlugin.extract({
        use: 'css-loader'
      })
    }]
}

说明:该插件作用之后,会将入口文件中引用的 main.css 构建成 dist/style.css 。另,该插件不支持热替换,亦即在本地开发过程,使用热替换达到独立模块热替换,在build过程开启开插件做分离构建。

那些我们遇到的问题

那些我们遇到的问题

如何做精准的构建

const path = require('path');
module.exports = {
    entry: {
        "usage.index": './usage/index.js',
        "usage.main": './usage/main.js'
    },
  
    output: {
        filename: '[name].[chunkhash].js',  // 每一个文件拥有自己唯一的hash值,不要在开发环境下使用,这会增加编译时间,不能与HMR插件共同使用
        path: path.resolve(__dirname, 'usage/dist/js'),
        publicPath: '/js/'
    }
}

说明:在该配置下,只会对有作更改的入口文件进行构建。区分:filename: '[name].[hash].js',这种配置下,所有的入口文件共享一个hash值,即其中某个入口文件更改之后,会对所有的入口文件做更改。
问题:重复构建导致许多的垃圾文件?文件名每次变更,html引入麻烦?这些....,交给webpack插件,都不是问题!

plugins: [
    new ManifestPlugin({
        fileName: 'manifest.json',
        basePath: './build/',
        seed: {
            name: 'My Manifest'
        }
    })
]

使用了插件,会生成一个映射文件,从这里,可以取到对应的文件名:

缓存文件映射表

webpack js资源断点调试技巧

  • 调试类型:

    • source-map:可断点调试,可在生产环境使用
    • cheap-module-source-map:可断点调试,可在生产环境使用
    • eval-source-map:能看源码,不可断点调试,不可在生产环境使用

    这里只是列出部分常用的类型,具体可参考webpack文档。

  • 如何配置?

module.exports = {
    devtool: 'source-map',// 可断点调试
}
  • 开始调试
    webpack断点调试
  • 如何分离开发和生产环境的配置?
    • 设置你的webpack.config.js
    function buildConfig(env) {
      return require('./config/' + env + '.js')({ env: env })
    }
    module.exports = buildConfig(env);
    
    • 设置你的package.json
    "build:dev": "webpack --env=dev --progress --profile --colors",
    "build:dist": "webpack --env=prod --progress --profile --colors",
    

相关文章

网友评论

    本文标题:webpack教程_由浅入深的webpack配置

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