webpack进修笔记

敕令运用

npm install webpack -g
    作为全局装置, 在恣意目次运用

npm install webpack --save-dev
    作为项目依靠装置

npm init
    建立package.json

npm install webpack-dev-server --save-dev
    运用webpack-dev-server启动服务器

webpack --progress -colors
    让编译的输出内容带有进度和色彩

webpack --watch
    假如不想每次修正模块后都从新编译, 那末可以启动监听情势。
    开启监听情势后, 没有变化的模块会在编译后缓存到内存中,
    而不会每次都被从新编译, 所以监听情势的团体速率是很快的

webpack --display-error-details
    用来打印毛病概况

npm install xxx-loader --save-dev
    装置多个加载器: npm install babel-core babel-preset-es2015 babel-preset-react

npm webpack --config webpack.config.js
    实行打包敕令

npm start
    启动开辟情势下的server

npm run start:prod
    启动临盆情势的server

npm run build
    打包临盆情势的代码

npm run lint: eslint
    代码搜检

npm run lint:watch: eslint
    看管

npm run remove:build
    删除dist目次

npm run clean:build
    消灭dist目次

// 挪用webpack
webpack
    开辟环境下编译

webpack -p
    产物编译及紧缩

webpack --watch
    开辟环境下延续的监听文件更改来举行编译

webpack -d
    引入source maps

设置文件

webpack.config.dev.js: 开辟情势相干设置
webpack.config.prod.js: 临盆情势相干设置
server.js: 设置当地的server(包含dev server和prod server) 将server部份星散到一个零丁到的文件设置
package.json
//webpack.config.dev.js

var webpack = require('webpack');
var path = require('path');
var config = {
    // 进口文件设置
    entry: {
        path.resolve(__dirname, 'app/index.js');
    },
    // 文件输出设置
    output: {
        path: path.resolve(_dirname, 'build'),
        filename: 'bundle.js',
        publicPath: '/'
    },

    // 插件项
    plugins: [],

    // 加载器设置
    module: {
        loaders: [
            {
                test: /pattern/,
                loader: 'xxx-loader',
                exclude: /dir/,
                query: {
                    presets: ['react']
                }
            },
             {
                 test: /\.(png|jpg)$/,
                 loader: 'url-loader?limit=8192'
                 // 内联的base64的图片地点, 图片要小于8k, 直接的url的地点则不剖析
             }
        ]
    },
    // 其他解决方案设置
    resolve: {
        extensions: ['', '.js', '.json'],
        alias: {}
    },
    watch: true
};

module.exports = config;
webpack.server.js

var webpack = require('webpack');
var webpackServer = require('webpack-dev-server');
var config = require('./webpack.config.dev.js');

var compiler = webpack(config);
var server = new webpackDevServer(compiler, {
    contentBase: './app',
    historyApiFallback: true,
    hot: true,        //热启动
    inline: true, // 监控js变化
    stats: {
        color: true
    }
});

config.entry.unshift('webpack-dev-server/client?http://localhost:8080/',
    'webpack/hot/dev-server');

server.listen(8080, 'localhost', function(err) {
    if(err) {
        console.log(err);
    }
    console.log('Listening at localhost:8080...');
});

<!-- package.json -->
'script': {
    'start': 'node server.js'
}

设置详解

entry: 进口, 定义要打包的文件

output: 出口, 定义打包输出的文件;包含途径, 文件名,还可能有运行时的接见途径(publicPath)参数

module: webpack将一切的资本都看作是模块, 而模块就须要加载器;
|---- loaders: 重要定义一些loaders, 定义哪些后缀名的文件应该用哪些loader

|-------- test: 婚配文件后缀, 检测哪些文件须要此loader, 是一个正则表达式

|-------- exclude: 疏忽哪些文件

|-------- query: 参数 (或直接写于loader如: loader: 'url-loader?limit=8192')

|------------ presets:

resolve: 其他解决方案设置

|---- extensions: 疏忽文件扩展名, require文件时可直接运用require('file'),而非带后缀如require('file.js')

|-------- alias: 模块别号定义,轻易后续直接饮用别号无需多写长地点, 后续直接require(key)

plugins: 定义一些分外的插件

watch: 值为boolean, 监听文件变化

设置临盆环境

开辟环境:
    webpack.config.dev.js
    须要日记输出, sourcemap, 毛病报告等

临盆环境:
    webpack.config.prod.js
    须要做代码紧缩, 对文件名举行hash处置惩罚等

辨别环境

运用DefinePlugin设置环境变量, 依据设置的环境变量决议是不是打包紧缩及启动dev server或prod server

plugins: [
    new webpack.DefinePlugin({
        'process.evn.NODE_ENV': JSON.stringify('production')
    });
]

推断当前是不是是临盆环境

var isProduction = function() {
    return process.env.NODE_ENV === 'production';
}


output: {
    path: path.resolve(isProduction ? '__build' : './assets/'),
    filename: isProduction ? '[name].js' : './assets/js/[chunkhash:8].[name].min.js',
    chunkFilename: isProduction ? '[chunkhash:8].chunk.js' : './assets/js/[chunkhash:8].chunk.min.js',
    publicPath: isProduction ? '/__build/' : 'http://cdn.site.com/'
}

代码紧缩

new webpack.optimizeUglifyJsPlugin({
    compress: {
        warnings: false
    }
});

增加Hash缓存

关于没有修正的文件, 从缓存中猎取文件, 关于已修正的文件, 不要从缓存中猎取

output: {
    //chunkhash 默许16位, 可自定义设置
    filename: '[chunkhash:8].bundle.js'
}

自动天生页面

文件名带上hash值后, 这个值在每次编译的时刻都邑发生变化,都须要在 html 文件里手动修正援用的文件名,这类反复事变很噜苏且轻易失足, 这里我们可以运用 html-webpack-plugin 来帮我们自动处置惩罚这件事变, 用来简化建立服务于webpackbundle的HTML文件

解决方案: 在项目目次下建一个index.tpl.html作为钩子

    <!-- index.tpl.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>My APP</title>
    </head>
    <body>
        <div id="app"></div>
    </body>
    </html>

在webpack.config.dev.js和webpack.config.prod.js增加设置代码, 即可天生响应的index.html

    plugins: [
        new HtmlWebpackPlugin({
            template: 'app/index.tpl.html',
            inject: 'body',
            filename: index.html
        })
    ]

加载器

js处置惩罚

babel-loader: 转换JSX
babel-core: babel核心包
babel-preset-react
babel-preset-es2015
<!-- webpack.config.dev.js -->
<!-- babel-loader设置 -->
loaders:[
    {
        loaders: 'xxx-loader',
        query: {
            resets:['react', 'es2015']
        }
    }
]

css处置惩罚

style-loader
css-loader
less-loader

img处置惩罚

url-loader
    可以依据自定义文件大小或许转化为 base64 花样的 dataUrl, 或许零丁作为文件, 也可以自定义对应的hash 文件名
file-loader
    默许情况下会依据图片天生对应的 MD5hash 的文件花样
image-webpack-loader
    供应紧缩图片的功用

加载babel-loader须要设置query参数

<!-- webpack.config.dev.js -->
<!-- url-loader设置 -->
loaders:[
    {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loaders: [
            // 当内容size小于8KB时, 会自动转成base64的体式格局内嵌进去, 如许可以削减一个HTTP的要求
            // 当图片大于8KB时, 则会在img/下天生紧缩后的图片, 定名是[hash:8].[name].[ext]的情势
            // hash:8的意义是取图片内容hashsum值的前8位,
            // 如许做可以保证援用的是图片资本的最新修正版本, 保证浏览器端可以立即更新
            'url?limit=8192&name=img/[hash:8].[name].[ext]',

            // 图片紧缩
            'image-webpack'
        ]
    }
]
<!-- webpack.config.dev.js -->
<!-- file-loader设置 -->
loaders:[
    {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loaders: [
            // 天生md5 hash花样的文件名
            'file?hash=sha512&digest=hex&name=[hash].[ext]',
            // 图片紧缩
            'image-webpack'
        ]
    }
]

插件

<!-- webpack.config.dev.js -->
plugins: [definPlugin, bannerPlugin, uglifyJsPlugin...]

设置环境变量

var definPlugin = new webpack.DefinePlugin({
    "process.env": {
        NODE_ENV: JSON.stringify("production")
    }
    // feature flags: 在开辟环境(比方日记)活内部测试环境(比方没有宣布的新功用)中运用
    // __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
    // __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
});

给输出的文件头部增加解释信息

var bannerPlugin = new webpack.BannerPlugin('This is test!');

JS殽杂

var uglifyJsPlugin = new webpack.optimize.UglifyJsPlugin({
    mangle: {
        // 设置以下列表, 在殽杂代码时, 以下设置的变量, 不会被殽杂
        except: ['$super', '$', 'exports', 'require']
    }
});

紧缩JS

var minChunkSizePlugin = new webpack.optimize.MinChunkSizePlugin({
    compress: {
        warnings: false
    }
});

紧缩React

var definPlugin = new webpack.DefinePlugin({
    'process.env': {
        NODE_ENV: JSON.stringify('production')
    }
});

加载jQuery

new webpack.ProvidePlugin({
    $: 'jquery'
});

大众模块提取

new webpack.optimize.CommonsChunkPlugin({
    name: 'vendors',                     // 将大众模块提取, 天生名为`vendors`的chunk
    chunks: ['index','list','about'],     //提取哪些模块共有的部份
    minChunks: 3                         // 提取最少3个模块共有的部份
});

零丁运用link标签加载css并设置途径

new ExtractTextPlugin('css/[name].css'), // 相关于output设置中的publickPath

自动天生html文件, 模板天生的相干设置, 每一个关于一个页面的设置, 有几个写几个

new HtmlWebpackPlugin({                 //依据模板插进去css/js等天生终究HTML
    favicon: './src/img/favicon.ico',     //favicon途径, 经由过程webpack引入同时可以天生hash值
    filename: './view/index.html',         //天生的html寄存途径, 相关于path
    template: './src/view/index.html',     //html模板途径
    inject: 'body',                     //js插进去的位置, true/'head'/'body'/false
    hash: true,                         //为静态资本天生hash值
    chunks: ['vendors', 'index'],        //须要引入的chunk, 不设置就会引入一切页面的资本
    minify: {                             //紧缩HTML文件
        removeComments: true,             //移除HTML中的解释
        collapseWhitespace: false         //删除空白符与换行符
    }
});
new HtmlWebpackPlugin({                 //依据模板插进去css/js等天生终究HTML
    favicon: './src/img/favicon.ico',     //favicon途径, 经由过程webpack引入同时可以天生hash值
    filename: './view/list.html',         //天生的html寄存途径, 相关于path
    template: './src/view/list.html',     //html模板途径
    inject: true,                         //js插进去的位置, true/'head'/'body'/false
    hash: true,                         //为静态资本天生hash值
    chunks: ['vendors', 'list'],        //须要引入的chunk, 不设置就会引入一切页面的资本
    minify: {                             //紧缩HTML文件
        removeComments: true,             //移除HTML中的解释
        collapseWhitespace: false         //删除空白符与换行符
    }
});

别的插件

new webpack.HotModuleReplacementPlugin()     // 热加载
HotModuleReplacementPlugin()                 // 代码热替代
NoErrorsPlugin()                             // 报错但不退出webpack历程
OpenBrowserPlugin()                         // 自动翻开浏览器

webpack运用

剖析多个模块的公用代码提取并零丁打包

var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
module.exports = {
    entry: {
        page1: './main1.js',
        page2: './main2.js'
    },
    output: {
        path: 'build',
        filename: '[name].js'
    },
    plugins: [
        commonsPlugin
    ]
}

文件援用疏忽扩展名设置

假如你愿望在require文件时省略文件的扩展名, 只须要在webpack.config.js中增加 resolve.extensions 来设置。

// webpack.config.js
module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            { test: /\.coffee$/, loader: 'coffee-loader' },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                query: {
                    presets: ['es2015', 'react']
                }
            }
        ]
    },
    resolve: {
        // 如今你require文件的时刻可以直接运用require('file'), 不必运用require('file.coffee')
        extensions: ['', '.js', '.json', '.coffee']
    }
};

css款式和图片的加载

起首你须要用require()去加载你的静态资本(named as they would with node’s require()):

require('./bootstrap.css');
require('./myapp.less');

var img = document.createElement('img');
img.src = require('./glyph.png');

当你require了CSS(less或许其他)文件, webpack会在页面中插进去一个内联的<style>, 去引入款式。当require图片的时刻, bundle文件会包含图片的url, 并经由过程require()返回图片的url。

然则这须要你在webpack.config.js做响应的设置(这里照样运用loaders)

// webpack.config.js
module.exports = {
    entry: './main.js',
    output: {
        path: './build', // 图片和js会放在这
        publicPath: 'http://mycdn.com/', // 这里用来天生图片的地点
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.less$/,
                loader: 'style-loader!css-loader!less-loader'
            }, // 用!去链式挪用loader
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {
                test: /\.(png|jpg)$/,
                loader: 'url-loader?limit=8192'
                // 内联的base64的图片地点, 图片要小于8k, 直接的url的地点则不剖析
            }
        ]
    }
};

功用标识(Feature flags)

项目中有些代码我们只为在开辟环境(比方日记)或许是内部测试环境(比方那些没有宣布的新功用)中运用, 那就须要引入下面这些魔法全局变量(magic globals):

if (__DEV__) {
    console.warn('Extra logging');
}
// ...
if (__PRERELEASE__) {
    showSecretFeature();
}

同时还要在webpack.config.js中设置这些变量, 使得webpack可以辨认他们。

// webpack.config.js

// definePlugin 会把定义的string 变量插进去到Js代码中。
var definePlugin = new webpack.DefinePlugin({
    __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
    __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
});

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    plugins: [definePlugin]
};

设置完成后, 就可以运用 BUILD_DEV=1 BUILD_PRERELEASE=1 webpack来打包代码了。
值得注意的是, webpack -p 会删除一切无作用代码, 也就是说那些包裹在这些全局变量下的代码块都邑被删除, 如许就可以保证这些代码不会因宣布上线而泄漏。

多个进口文件

假如你有两个页面:profile和feed。假如你愿望用户接见profile页面时不加载feed页面的代码, 那就须要天生多个bundles文件:为每一个页面建立本身的“main module”(进口文件)。

// webpack.config.js
module.exports = {
    entry: {
        Profile: './profile.js',
        Feed: './feed.js'
    },
    output: {
        path: 'build',
        filename: '[name].js' // name是基于上边entry中定义的key
    }
};

在profile页面中插进去<script src="build/Profile.js"></script>。feed也一样。

优化通用代码

Feed和Profile页面存在大批通用代码(比方React、大众的款式和组件等等)。webpack可以抽离页面间大众的代码, 天生一个大众的bundle文件, 供这两个页面缓存运用:

// webpack.config.js

var webpack = require('webpack');

var commonsPlugin =
    new webpack.optimize.CommonsChunkPlugin('common.js'); // 引入插件

module.exports = {
    entry: {
        Profile: './profile.js',
        Feed: './feed.js'
    },
    output: {
        path: 'build',
        filename: '[name].js' // 为上面entry的key值
    },
    plugins: [commonsPlugin]
};

在上一步引入本身的bundle之前引入<script src="build/common.js"></script>

异步加载

虽然CommonJS是同步加载的, 然则webpack也供应了异步加载的体式格局。这关于单页运用中运用的客户端路由异常有效。当真正路由到了某个页面的时刻, 它的代码才会被加载下来。

指定你要异步加载的 拆分点。看下面的例子

if (window.location.pathname === '/feed') {
    showLoadingState();
    require.ensure([], function() { // 这个语法痕新鲜, 然则照样可以起作用的
        hideLoadingState();
        require('./feed').show(); // 当这个函数被挪用的时刻, 此模块是肯定已被同步加载下来了
    });
} else if (window.location.pathname === '/profile') {
    showLoadingState();
    require.ensure([], function() {
        hideLoadingState();
        require('./profile').show();
    });
}

剩下的事就可以交给webpack, 它会为你天生并加载这些分外的 chunk 文件。

webpack 默许会从项目的根目次下引入这些chunk文件。你也可以经由过程 output.publicPath来设置chunk文件的引入途径

// webpack.config.js
output: {
    path: "/home/proj/public/assets", // webpack的build途径
    publicPath: "/assets/" // 你require的途径
}
    原文作者:引路人
    原文地址: https://segmentfault.com/a/1190000003039047
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞