美文网首页
Webpack笔记二

Webpack笔记二

作者: 章鱼不丸子 | 来源:发表于2017-04-14 16:29 被阅读0次

    webpack配置DEMO

    webpack.config.js文件官方标配示例如下:

    module.exports = {
        dvtool: //配置生成Source Maps,选择合适的选项
        plugins: //插件项
        entry: //页面入口文件配置
        output: //入口文件输出配置
            path: //定义输出文件路径
            filename: //指定打包文件名称
        module: //加载器配置,对模块的处理逻辑
        loaders: //定义了一些列的加载器
            test: //正则,匹配到文件的后缀名
            loader/loaders: //处理匹配到的文件----注意现在要求loader关键字不准省略"-loader"后缀
            include: //包含的文件夹
            exclude: //排除的文件夹
        resolve: //其它解决方案的配置
            extensions: //自动补全识别后缀
    }
    

    参考各路大神的流程写下来.....应该没有漏掉哪一步吧?
    DEMO 项目结构如图:

    index.html(加载打包后的build.js)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>webpack test</title>
    </head>
    <body>
        <div id="test"></div>
    </body>
    <!-- webpack一会打包完成的js -->
    <script src="build.js"></script> 
    </html>
    

    app.js(返回包含问候信息的html元素)

    // app.js
    module.exports = function() {
      var hello = document.createElement('div');
      hello.textContent = "Hello Everybody!";
      return hello;
    };
    

    main.js(把app.js返回的节点插入页面)

    //main.js 
    var hello = require('./app.js');
    document.getElementById('test').appendChild(hello());
    

    webpack可以在终端使用

    webpack {entry file/入口文件} {destination for bundled file/存放build.js的地方}

    非全局安装使用

    node_modules/.bin/webpack app/main.js public/bundle.js

    打开index.html

    这里推荐通过配置文件来使用webpack

    entry和output

    在webpack.config.js中entry是唯一入口文件
    首先entry的值可以有三种类型:1、字符串;2、数组;3、对象

    //与DEMO无关,此为示例说明文件
    //字符串,指定从这个文件路径下面的文件作为打包的入口文件
    entry: './src/js/main.js' , //唯一入口文件
    output: {
        path: 'dist/js', //打包后的文件存放地方
        filename: "build.js" //文件名
      }
    
    //存在多个入口时,可以使用array的方式。会将里面的文件一起打包到build.js
    {
      entry: ['./src/js/main.js', './src/js/test_entry.js'],
      output: {
        path: 'dist/js',
        filename: "build.js"
      }
    }
    
    //也可以是一个对象
    {
        entry: {
            main: './src/js/main.js',
            test_entry: './src/js/test_entry.js'
        },
        output: {
            path: 'dist/js',
            filename: '[name]-[chunkhash].js' //[name]的值是entry的键值,[hash]是打包时候的hash值,chunkhash是md5加密的值,这里作为版本号使用
        }
    }
    

    每次修改文件,运行webpack后都会生成不一样的hash和chunkhash值,方便上线时候静态资源的版本管理。

    因为文件名每次运行都是变化的,文件引入的文件名字也是需要变化的,这时候使用html-webpack-plugin插件 npm install html-webpack-plugin --save-dev

    完成后在wenpack.config.js文件里添加plugins(plugins)的值是数组,里面的值都是new htmlWebpackPlugin(),参数见下文;
    最后文件如下:

    //与DEMO无关,此为示例说明文件
    var htmlWebpackPlugin = require("html-webpack-plugin");
    
    module.exports = {
        entry: {
            main: './src/js/main.js',
            test_entry: './src/js/test_entry.js'
        },
        output: {
            path: 'dist/js',
            filename: '[name]-[chunkhash].js' //[name]的值是entry的键值,[hash]是打包时候的hash值,chunkhash是md5加密的值,这里作为版本号使用
        },
        plugins: [
            new htmlWebpackPlugin({
                title: 'webpack demo',
                filename: 'index-[hash].html',
                template: 'index.html'
            })
        ]
    }
    
    • title: 用来生成页面的 title 元素
    • filename: 输出的 HTML 文件名,默认是 index.html, 也可以直接配置带有子目录。
    • template: 模板文件路径,支持加载器,比如 html!./index.html
    • inject: true | 'head' | 'body' | false ,注入所有的资源到特定的 template 或者 templateContent 中,如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body 元素的底部,'head' 将放置到 head 元素中。
    • favicon: 添加特定的 favicon 路径到输出的 HTML 文件中。
    • minify: {} | false , 传递 html-minifier 选项给 minify 输出
    • hash: true | false, 如果为 true, 将添加一个唯一的 webpack 编译 hash 到所有包含的脚本和 CSS 文件,对于解除 cache 很有用。
    • cache: true | false,如果为 true, 这是默认值,仅仅在文件修改之后才会发布文件。
    • showErrors: true | false, 如果为 true, 这是默认值,错误信息会写入到 HTML 页面中
    • chunks: 允许只添加某些块 (比如,仅仅 unit test 块)
    • chunksSortMode: 允许控制块在添加到页面之前的排序方式,支持的值:'none' | 'default' | {function}-default:'auto'
    • excludeChunks: 允许跳过某些块,(比如,跳过单元测试的块)

    在当前demo根目录下新建一个webpack.config.js的文件,首先最简单的写一下入口文件和存放打包后文件的地方的路径

    //DEMO
    module.exports = {
        entry: __dirname + "/app/main.js", //唯一入口文件
        output: {
            path: __dirname + "/public", //打包后的文件存放地方
            filename: "build.js" //打包后输出的文件的文件名
        }
    }
    

    _dirname 是node.js的一个全局变量,指向当前执行脚本所在的目录

    在终端里运行webpack node_modules/.bin/webpack(非全局安装)

    那么在非全局安装webpack中,或者是类似于上面命令很长很容易出错的时候,我们可以用npm引导任务执行,在package.json中对npm脚本部分进行设置,可以使用简单的npm start命令来代替:

    {
      "name": "demo",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "start": "webpack" //相当于把npm的start命令指向webpack命令
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "webpack": "^2.3.3"
      }
    }
    

    这时候的编译后是虚拟的,本地其实是没有编译的,所以很多使用本地路径的都需要我们去处理。

    无论全局还是局部安装的webpack,这里都不需要写前面详细路径,因为package.json脚本部分已经默认在命令中添加了node_module/.bin路径。

    devtool

    生成Source Maps可以使开发更容易。打包后的文件有时候是不容易找到错的地方对应的源码的。通过简单的配置,webpack在打包时候会为我们生成source maps,这可以为我们提供一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,更容易调试。

    devtool选项 配置结果
    source-map 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包文件的构建速度;
    cheap-module-source-map 在一个单独的文件中生成一个不带列映射的map,不带列映射提高项目构建速度,但是也是的浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便;
    eval-source-map 使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的source map,但是对打包后输出的js文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项;
    cheap-module-eval-source-map 这是在打包文件时最快的生成source map的方法,生成的source map会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点

    在webpack中配置source maps需要配置devtool,它共有四种不同的配置选项,优缺点描述如下:

    devtool选项 配置结果
    source-map 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包文件的构建速度;
    cheap-module-source-map 在一个单独的文件中生成一个不带列映射的map,不带列映射提高项目构建速度,但是也是的浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便;
    eval-source-map 使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的source map,但是对打包后输出的js文件的执行具有性能和安全的隐患。不过在开发阶段这是一个非常好的选项,但是在生产阶段一定不要用这个选项;
    cheap-module-eval-source-map 这是在打包文件时最快的生成source map的方法,生成的source map会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点

    接下来生成Source Maps这可以使调试更加的容易,因为这只是一个测试的小项目,所以推荐使用eval-source-map,不过只是在开发阶段使用。

    //DEMO
    module.exports = {
        devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
        entry: __dirname + "/app/main.js", //唯一入口文件
        output: {
            path: __dirname + "/public", //打包后的文件存放地方
            filename: "build.js" //打包后输出的文件的文件名
        }
    }
    

    使用webpack构建本地服务器

    webpack可以提供一个可选的本地开发服务器,该服务器是基于node.js构建,不过它是一个单独的组件(webpack-dev-server是一个独立的NPM包),在webpack中进行配置之前需要单独安装它作为项目依赖。这一步搞好了,嗯哼~你的浏览器就可以监测你代码的修改然后自动刷新了。

    npm install --save-dev webpack-dev-server

    接下来我们调整一下配置文件:

    module.exports = {
        devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
        entry: __dirname + "/app/main.js", //唯一入口文件
        output: {
            path: __dirname + "/public", //打包后的文件存放地方
            publicPath:"/assets/", //运行后你看不到,因为实时编译是保存到了内存中
            filename: "build.js" //打包后输出的文件的文件名
        }
    }
    

    调整一下index.html的js引用路径 <script src="assets/build.js"></script>

    运行webpack-dev-server --content-base ./public得到如下(这里如果不进行设定的话,默认是当前目录下的):

    打开浏览器输入:localhost:8080 你就能看到你的hello信息了....

    对上面设定的content-base做一些说明:

    注意:如果在webpack.config.js里面如果配置了output的publicPath这个字段的值的话,在index.html文件里面也应该做出调整,因此才需要调整index.html。上述配置了这个字段是为了对实时编译保存到内存中做一个说明,你也可以省略这个字段,那么index.html的js引用路径就依然是<script src="build.js"></script>

    有同学要说,坑爹啊,我想要的是实时编译,实时刷新,浏览器自刷新。你这个是手动的什么鬼??

    webpack-dev-server目前支持两种自动刷新的方式:

    1. iframe mode
    2. inline mode

    这2种模式的配置方式和访问路径稍微有点区别,最主要的区别是:Iframe mode是在网页中嵌入了一个iframe,将我们自己的应用注入到这个iframe中,因此你每次修改的文件都是对这个iframe进行了reload。而inline mode是webpack-dev-server会在wenpack.config.js的入口配置文件中再添加一个入口。

    module.exports = {
        devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
        entry: {
            app: [
                'webpack-dev-derver/client?http://localhost:8080/',
                __dirname + "/app/main.js", //唯一入口文件
            ]
        },
        output: {
            path: __dirname + "/public", //打包后的文件存放地方
            filename: "build.js" //打包后输出的文件的文件名
        }
    }
    

    你也可以直接在index.html中引入这部分代码:<script src="http://localhost:8080/webpack-dev-server.js"></script>

    Iframe mode

    浏览器访问路径变为:localhost:8080/webpack-dev-server/index.html

    页面的header部分会出现整个reload消息的状态,当改变源文件时候,就可以自动完成编译打包,页面自动刷新。

    Inline code

    使用时候,cmd line需要写成webpack-dev-server --inline --content-base ./public

    浏览器访问路径是:localhost:8080/index.html

    它会在控制台中显示reload状态,也具有自动编译打包的功能。

    hot module replacement

    开启hot module replacement 功能,在cmd line里面添加 --hot就可以

    webpack-dev-derver --hot --inline --content-base ./public

    其它的配置项比如:

    • quiet 控制台中不输出打包信息
    • compress 开启gzip压缩
    • propress 显示打包的进度

    调整package.json里面的配置项

    "scripts": {
        "dev": "webpack-dev-server --devtool eval-source-map --progress --colors --hot --inline --content-base ./public",
        "build": "webpack --progress --colors"
      }
    

    接下来就可以使用npm run dev 在浏览器中打开localhost:8080/index.html 进行愉快开发了

    备注一下devserver配置选项

    devserver配置选项 描述
    contentBase 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在的目录(比如DEMO中的“public”目录)
    port 设置默认监听端口,默认为“8080”
    inline 设置为true,当源文件改变时,会自动刷新页面
    colors 设置为true,终端输出的文件为彩色的
    historyApiFallback 开发单页面应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html

    module-loaders

    loaders中对我来说最难的是babel,我看着大神的教程N久没折腾出来,就为了体验把ES6,也是拼了。
    按照大神的教程,继续....希望这次折腾成功 come on baby
    首先明确大名鼎鼎的loaders在webpack中为啥是个很犀利的功能。主要就是通过使用不同的loader,webpack可以通过调用外部的脚本或工具,对各种格式的文件进行处理。比如分析JSON文件把它转换为JS文件,或者是ES6/ES7转换为现代浏览器可以识别的JS文件。还可以将react的jsx文件转换成JS文件。厉害了我的loader....

    loaders需要单独安装

    npm install --save-dev json-loader

    安装成功后需要在webpack.config.js下的module关键字下进行配置,配置项如下:

    • test: 一个匹配loaders处理的文件的拓展名的正则表达式(必写)
    • loader: loader的名称(必写)
    • include/exclude: 手动添加必须处理的文件(文件夹)/屏蔽不需要处理的文件(文件夹)(非必写)
    • query: 为loaders提供额外的设置选项(非必写)

    webpack.config.js

    module.exports = {
        devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
        entry: {
            app: [
                __dirname + "/app/main.js", //唯一入口文件
            ]
        },
        output: {
            path: __dirname + "/public", //打包后的文件存放地方
            filename: "build.js" //打包后输出的文件的文件名
        },
        module: { //配置文件里添加json loader
            loaders: [
                {
                    test: /\.json$/,
                    loader: "json-loader"
                }
            ]
        },
    }
    

    DEMO继续,把app.js的message单独放在一个message.json文件里,再进行配置,让app.js可以读取到json中的message。

    message.json

    {
        "hello": "Hello everybody and from json file!"
    }
    

    app.js

    // app.js
    var message = require('./message.json');
    
    module.exports = function() {
      var hello = document.createElement('div');
      hello.textContent = message.hello;
      return hello;
    };
    

    嗯哼,走你~~

    这个是简单的了。接下来是我有爱有恨的babel
    Babel其实是一个编译JavaScript的平台,强大之处就是:ES6/ES7转换为现代浏览器可以识别的JS文件。还可以将react的jsx文件转换成JS文件,简直占据了目前我的loader的半壁江山啊。

    Babel其实就是几个模块化的包,核心功能位于babel-core的npm包中,不过webpack把它们整合在一起使用了,但是对于每一个你需要的功能或者拓展,你都需要安装单独的包(比如解析Es6的babel-preset-es2015和解析JSX的babel-preset-react包)

    我们来个全家桶一次搞定:

    npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react(npm一次性安装多个依赖模块,模块之间用空格隔开)

    配置webpack.config.js:

    module.exports = {
        devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
        entry: {
            app: [
                __dirname + "/app/main.js", //唯一入口文件
            ]
        },
        output: {
            path: __dirname + "/public", //打包后的文件存放地方
            filename: "build.js" //打包后输出的文件的文件名
        },
        module: { //配置文件里添加json loader
            loaders: [
                {
                    test: /\.json$/,
                    loader: "json-loader"
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader',
                    query: {
                        presets: ['es2015', 'react']
                    }
                }
            ]
        }
    }
    

    因为demo会用的react所以记得安装react和react-dom

    npm install --save react react-dom

    在app.js里使用es6新语法开始愉快的返回一个react组件试一下吧

    import React, {Component} from 'react'
    import message from './message.json'
    
    class Hello extends Component {
        render() {
            return (
                <div>
                    {message.hello}
                </div>
            );
        }
    }
    
    export default Hello
    

    在main.js使用ES6的模块定义和渲染Hello模块

    import React from 'react';
    import {render} from 'react-dom';
    import Hello from './app.js';
    
    render(<Hello />, document.getElementById("test"));
    

    考虑到babel有非常多的配置选项,在webpack.config.js里面进行配置的话会显得太复杂,因此比较好的方式是把babel的配置选项单独放在一个.babelrc的配置文件中。webpack会自动调用这个配置文件的选项。因此我们将刚才的配置分离出来到.babelrc:

    {
      "presets": ["react", "es2015"]
    }
    

    穿插点题外的。webpack对于模块有非常强大的处理功能,那么什么算是模块呢??

    事实上一切皆模块,包括我们的css、fonts、图片、js等,当通过合适的loaders时,它们都可以被当成模块来处理。

    CSS

    webpack提供了两个工具处理样式表,css-loader和style-loader,这两个处理的任务不同。css-loader使你能够以类似@import 或者 url(...) 这种方式实现 require()的功能,style-loader是将所有计算后的样式加入页面中,两者组合在一起就能使样式表嵌入webpack打包后的js文件中。

    DEMO继续:

    npm install --save-dev style-loader css-loader

    webpack.config.js中添加配置:

     {
        test: /\.css$/,
        loader: 'style-loader!css-loader'//添加对样式表的处理
     }
    

    感叹号的作用在于使同一文件能够使用不同类型的loader

    在app文件夹创建一个main.css文件,写点样式

    html {
      box-sizing: border-box;
      -ms-text-size-adjust: 100%;
      -webkit-text-size-adjust: 100%;
    }
    
    *, *:before, *:after {
      box-sizing: inherit;
    }
    
    body {
      margin: 0;
      font-family: '微软雅黑', Helvetica, Arial, sans-serif;
      background: #f2f2f2;
    }
    
    h1, h2, h3, h4, h5, h6, p, ul {
      margin: 0;
      padding: 0;
    }
    

    webpack只有单一入口,其它的模块需要通过import、require、url等导入相关位置,现在将main.css导入main.js中

    import React from 'react';
    import {render} from 'react-dom';
    import Hello from './app.js';
    
    import './main.css';
    
    render(<Hello />, document.getElementById("test"));
    

    通常情况下,css会和js打包到同一个文件中,并不会打包一个单独的css文件,通过合适的配置webpack的话也可以把css打包为单独的文件的。

    CSS module

    随着前端模块化开发的推动,css module出现了。它将js的模块化思想带入css中来,通过css模块,所有的类名、动画名默认都只作用于当前模块。webpack一开始就对css模块化提供了支持,在css loader中进行配置后,你所需要做的就是把modules传递到需要的地方,然后就可以直接把css的类名传递到组件的代码中,且只对当前组件有效,不比担心在不同的模块中具有相同的类名可能会造成的问题,实现方式先调整webpack.config.js中的css配置

    {
        test: /\.css$/,
        loader: 'style-loader!css-loader?modules' //跟前面相比就在后面加上了?modules
    }
    

    创建一个app.js文件

    #test {
        background-color: pink;
        padding: 10px;
        border: 5px solid green;
    }
    

    导入#test 到app.js中

    import React, {Component} from 'react';
    import message from './message.json';
    import styles from './app.css';
    
    class Hello extends Component {
        render() {
            return (
                <div className={styles.test}>
                    {message.hello}
                </div>
            );
        }
    }
    
    export default Hello
    

    相同的类名也不会造成不同组件之间的污染..
    css modules是一个很大的主题,可以参考cssModules官方文档查看更多

    css预处理器

    Sass和Less之类的预处理器是对原生css的拓展,它们允许你使用类似于variables,nesting,mixins,inheritance等不存在于css中的特性来写css,css预处理器可以使这些特殊的语句转化为浏览器可以识别的css语句。

    常用的loaders:

    • Less Loader
    • Sass Loader
    • Stylus Loader

    还有一个css的处理平台-PostCss,具体可以参考PostCss官方文档

    安装postcss和autoprefixer(自动添加前缀的插件)可以参考autoprefixer官方文档

    npm install --save-dev postcss-loader autoprefixer

    新建一个postcss.config.js文件,并在里面申明依赖的插件

    module.exports = {
        plugins: [
            require ('autoprefixer')
        ]
    }
    

    webpack.config.js 如下现在你写的css会自动根据can i use 里的数据添加不同的前缀了。

    module.exports = {
        devtool: 'eval-source-map',//配置生成Source Maps,选择合适的选项
        entry: {
            app: [
                __dirname + "/app/main.js", //唯一入口文件
            ]
        },
        output: {
            path: __dirname + "/public", //打包后的文件存放地方
            filename: "build.js" //打包后输出的文件的文件名
        },
        module: { //配置文件里添加json loader
            loaders: [
                {
                    test: /\.json$/,
                    loader: "json-loader"
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: 'babel-loader'
                },
                {
                    test: /\.css$/,
                    loader: 'style-loader!css-loader?modules!postcss-loader'
                }       
            ]
        }
    }
    

    插件(plugins)

    loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less...),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。

    webpack分为内置插件和第三方插件。在笔记二中对这两者有基础介绍。下一节笔记就正式开始参考官方进行vue的渐进学习。

    更多文章请移步 http://www.yuki.kim

    相关文章

      网友评论

          本文标题:Webpack笔记二

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