webpack2搭建开发环境

开发环境

本文主要介绍使用webpack2进行前端开发以及编译发布文件,主要涉及:

  • HMR - React
  • HMR - less
  • iconfont

如果你对 Vue 项目感兴趣,可移步至我的开源项目
buluoci-web

安装node依赖

第一步我们先搭建基础的webpack开发环境,并支持React Hot Module Replacement(HMR),为此,我们需要安装以下依赖到项目:

npm install --save-dev babel-core babel-loader babel-preset-es2015 webpack webpack-dev-server

react:

npm install --save-dev babel-preset-react react-hot-loader
npm install --save react react-dom

css:

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

less:

npm install --save-dev less less-loader

图片:

npm install --save-dev image-webpack-loader file-loader url-loader

svgs转iconfont:

npm install --save-dev webfonts-loader

babel的配置文件

.bablrc

{
    "presets": [
        ["es2015", { "modules": false }],
        "react"
    ],
    "env": {
        "development": {
            "plugins": ["react-hot-loader/babel"]
        }
    }
}

我们只是在开发时才需要react HMR,所以react-hot-loader/babel 被配置到env为development下。

项目代码

src/index.html




    
    
    
    


    

src/m.html

与index.html类似




    
    
    
    


    

src/js/container/index.js

import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';// necessary wrapper component for HMR

import App from 'js/views/Index';

function renderApp(Component) {
    render(, document.getElementById('app'));
}
renderApp(App);

// Hot Module Replacement API
if(module.hot) module.hot.accept('js/views/Index', () => renderApp(App));

src/js/container/m.js

与index.js类似

import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';// necessary wrapper component for HMR

import App from 'js/views/M';

function renderApp(Component) {
    render(, document.getElementById('app'));
}
renderApp(App);

// Hot Module Replacement API
if(module.hot) module.hot.accept('js/views/M', () => renderApp(App));

如果有svg图标需要转字体

src/icons/index.js

module.exports = {
    files: ['./*.svg'],

    // https://github.com/nfroidure/svgicons2svgfont#api
    fontName: 'iconfont',
    fixedWidth: true,
    normalize: true,
    descent: 160,

    types: ["ttf"],
    formatOptions: {
        ttf: {
            // 保证输出一致
            ts: 1451512800000
        }
    }
};

这样配置后,src/icons/*svg 可以通过 import 'icons'; 以字体方式引入

src/js/views/Index.js

真正的index.html页面逻辑写在这里

import React from 'react';

import 'less/admin/index.less';// 如果有样式可以这样引入
import 'icons';// 如果需要,可以这样引入图标字体

export default function() {
    return (
        
这里的内容会填充到 index.html 的 div#app 里
); }

src/js/views/M.js

与 Index.js 类似

import React from 'react';

export default function() {
    return (
        
这里的内容会填充到 m.html 的 div#app 里
); }

开发环境的webpack配置

webpack.dev.config.js

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

var devPort = 8080;
var devHost = process.env.DEV_HOST || 'http://localhost';
var context = path.resolve('src');

module.exports = {
    context,
    entry: {
        index: [
            'react-hot-loader/patch',
            './js/container/index'
        ],
        m: [
            'react-hot-loader/patch',
            './js/container/m'
        ]
    },
    output: {
        filename: '[name].js',// for multi chunks

        // css启用sourcemap时需指定
        // 否则图片等相关资源在通过blob加载的css中无法正确引用
        publicPath: `${devHost}:${devPort}/`
    },
    plugins: [
        new webpack.NoEmitOnErrorsPlugin(),
        new webpack.NamedModulesPlugin(),
        new webpack.LoaderOptionsPlugin({
            options: {
                context,
                postcss: function() {
                    return [
                        require('autoprefixer')({ browsers: ["Android >= 4", "iOS >= 7", "IE >= 9"] })
                    ];
                },
            }
        }),

        new HtmlWebpackPlugin({
            template: 'index.html',
            favicon,
            chunks: ['index']
        }),
        new HtmlWebpackPlugin({
            template: 'm.html',
            favicon,
            chunks: ['m'],
            filename: 'm.html'
        })
    ],
    devServer: {
        noInfo: true,
        host: '0.0.0.0',
        port: devPort
    },
    devtool: 'eval',

    module: {
        rules: [
            {
                // iconfont
                test: /icons/,
                // embed解决 对publicPath解析bug
                use: [
                    'style-loader',
                    'css-loader',
                    'webfonts-loader'
                ]
            }, {
                // js and jsx
                test: /\.jsx?$/,
                exclude: /node_modules/,
                use: [
                    'babel-loader',// configed in .babelrc
                ]
            }, {
                // less
                test: /\.less$/,
                use: [
                    'style-loader',
                    'css-loader?sourceMap',
                    'postcss-loader',
                    'less-loader?sourceMap'
                ]
            }, {
                // images
                test: /\.(png|jpe?g)$/,
                use: ['file-loader']
            }
        ]
    },

    resolve: {
        extensions: ['*', '.js', '.jsx'],
        alias: {
            'js': path.resolve('src/js'),
            'less': path.resolve('src/less'),
            'img': path.resolve('src/img'),
            'icons': path.resolve('src/icons'),
        }
    }
};

万事俱备准备开发

package.json

{
  ...
  "scripts" : {
    "dev": "webpack-dev-server --hot --config webpack.dev.config.js"
  }
  ...
}

执行 npm run dev,然后打开浏览器前往 http://localhost:8080

生产环境

安装node依赖

npm install --save-dev extract-text-webpack-plugin chunk-manifest-webpack-plugin

生产环境的webpack配置

webpack.prod.config.js

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
var path = require("path");
var favicon = 'img/favicon.ico';
var context = path.resolve('src');

module.exports = {
    context,
    entry: {
        index: [
            './js/container/index'
        ],
        m: [
            './js/container/m'
        ],
        // 将公共库打包成libs.js
        libs: [
            'react',
            'react-dom',
        ]
    },
    output: {
        path: path.resolve('dist/assets'),
        filename: '[name].js?[chunkhash]'
    },
    plugins: [
        new webpack.LoaderOptionsPlugin({
            options: {
                context,
                postcss: function() {
                    return [
                        require('autoprefixer')({ browsers: ["Android >= 4", "iOS >= 7", "IE >= 9"] })
                    ];
                },
                imageWebpackLoader: {
                    mozjpeg: {
                        quality: 65
                    },
                    pngquant: {
                        quality: "65-90"
                    }
                }
            }
        }),
        new ChunkManifestPlugin(),// 防止chunk被hash更新
        new webpack.optimize.CommonsChunkPlugin({
            name: 'libs',
            filename: '[name].js?[chunkhash]',
            minChunks: Infinity
        }),

        // 将css输出到独立的文件,而不是内嵌在js中
        new ExtractTextPlugin('[name].css?[contenthash]'),

        new HtmlWebpackPlugin({
            template: 'index.html',
            favicon,
            chunks: ['home', 'libs']
        }),
        new HtmlWebpackPlugin({
            template: 'm.html',
            favicon,
            chunks: ['m', 'libs'],
            filename: 'm.html'
        })
    ],

    module: {
        loaders: [
            {
                // iconfont
                test: /icons/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        'css-loader',
                        'webfonts-loader?embed'
                    ]
                })
            }, {
                // js and jsx
                test: /\.jsx?$/,
                exclude: /node_modules/,
                use: [
                    'babel-loader',// configed in .babelrc
                ]
            }, {
                test: /\.less$/,
                // 输出独立的css文件
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        'css-loader?-minimize',
                        'postcss-loader',
                        'less-loader'
                    ]
                })
            }, {
                // images
                test: /\.(png|jpe?g)$/,
                use: [
                    'url-loader?limit=10000&name=[path][name].[ext]?[hash]',
                    'image-webpack-loader'
                ]
            }
        ]
    },

    resolve: {
        extensions: ['*', '.js', '.jsx'],
        alias: {
            'js': path.resolve('src/js'),
            'less': path.resolve('src/less'),
            'img': path.resolve('src/img'),
            'icons': path.resolve('src/icons'),
        }
    }
};

package.json

{
  ...
  "scripts" : {
    ...
    "clean": "rm -rf dist/assets",
    "build": "npm run clean && BABEL_ENV=production webpack -p --progress --config webpack.prod.config.js",
  }
  ...
}

执行 npm run build,文件会编译到 dist/assets下

你可能感兴趣的:(webpack2搭建开发环境)