从零搭建react 脚手架

前言

目前前端最主流,应用最广的webpack总结下

目前常用的构建工具

  1. facebook官方的create-react-app(官方推荐)
    create-react-app

但是现在大部分公司都需要自己能搞定脚手架,所以大家还是能自己搭建为好

(二)webpack基本概念

  • 入口(entry)
  • 输出(output)
  • loader
  • 插件(plugins)

  • entry
    webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
    配置参数

  • output
    output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。
    配置参数

  • loader
    webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。

    配置中 loader 有两个目标:
    test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
    use 属性,表示进行转换时,应该使用哪个 loader。

    配置参数


  • plugins
    插件目的在于解决 loader 无法实现的其他事。比如 压缩js(uglifyjs-webpack-plugin),压缩css(optimize-css-assets-webpack-plugin),将js中的css分离独立出来(extract-text-webpack-plugin)等

配置参数

(三)搭建webpack基础环境

  • 初始化项目目录
$ mkdir webpack-demo
$ cd webpack-demo
$ npm init -y // -y的意思是默认安装

新建四个文件,分别是webpack.base.js(基础环境),webpack.dev.js(开发环境),webpack.prod.js(生产环境),.gitignore(git忽略文件)

这时候我们的文件目录为

从零搭建react 脚手架_第1张图片


  • 配置webpack基本环境设置
    注意:-S是安装在生产环境,-D安装在开发环境。
 // 模块管理和打包工具
$ npm install webpack@3 -D
// 监听代码自动刷新(注意@3版本对应webpack@4)
$ npm install webpack-dev-server@2 -D 
// 安装merge
$ npm i webpack-merge -D
// 安装html处理
$ npm i html-webpack-plugin -D
// 清除插件
$ npm i clean-webpack-plugin -D
// copy 插件
$ npm i copy-webpack-plugin -D
// 安装dev open-browser
$ npm i open-browser-webpack-plugin -D
// 安装 lodash 
$ npm install  lodash -S

新建public和src文件夹,项目目录为下图
从零搭建react 脚手架_第2张图片

配置webpack.base.js

/**
 * @component webpack.base.js
 * @description 基础环境
 * @time 2018/3/8
 * @author **
 */
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 生成html
const CleanWebpackPlugin = require('clean-webpack-plugin'); // 清除dist
const CopyWebpackPlugin = require('copy-webpack-plugin'); // copy

function resolve(dir) {
    return path.join(__dirname, dir);
}

module.exports = {
    entry: {
        app: './src/index.js',
        vendor: [
            'lodash'
        ]
    },
    resolve: {
        extensions: [' ', '.js', '.json', '.jsx', '.css', '.less','.json'],
        modules: [resolve( "src"), "node_modules"], //绝对路径;
    },
    module: {
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new CopyWebpackPlugin([{
            from: "./public",
            to: "",
            force: true
        }]),
        new HtmlWebpackPlugin({
            filename: 'index.html',//输出的html路径
            template: './public/index.html', //html模板路径
            chunks: ['app', 'vendor', 'manifest'],
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeRedundantAttributes: true,
                useShortDoctype: true,
                removeEmptyAttributes: true,
                removeStyleLinkTypeAttributes: true,
                keepClosingSlash: true,
                minifyCSS: true,
                minifyJS: true,
                minifyURLs: true,
            }
        }),
        new webpack.HashedModuleIdsPlugin(), // 修复vendor hash
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: Infinity
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'manifest', // 指定公共 bundle 的名称。
            minChunks: Infinity
        })
    ]
};

配置webpack.dev.js

/**
 * @component webpack.dev.js
 * @description 开发环境
 * @time 2018/3/8
 * @author **
 */
const webpack = require('webpack');
const path = require('path');
const merge = require('webpack-merge');
const OpenBrowserPlugin = require('open-browser-webpack-plugin');
const base = require('./webpack.base.js');

function resolve (dir) {
    return path.join(__dirname, dir)
}
// 端口
const port = 8080;

module.exports = merge(base, {
    output: {
        filename: 'static/js/[name].js', //
        path: resolve('dist'), // 输出的文件地址
        publicPath: ''
    },
    devtool: 'inline-source-map',
    module: {
    },
    devServer: {
        contentBase: './dist',
        compress: true,
        port: port,
        historyApiFallback: true,//不跳转
        inline: true//实时刷新
    },
    plugins: [
    new webpack.NamedModulesPlugin(),
	new webpack.HotModuleReplacementPlugin(),
        new OpenBrowserPlugin({ url: 'http://localhost:'+port }),
    ],
});

配置webpack.prod.js

/**
 * @component webpack.prod.js
 * @description 生产环境
 * @time 2018/3/8
 * @author **
 */
const webpack = require('webpack');
const path = require('path');
const merge = require('webpack-merge');
const base = require('./webpack.base.js');

function resolve (dir) {
    return path.join(__dirname, dir)
}

module.exports = merge(base, {
    output: {
        filename: 'static/js/[name].[hash:7].js', //
        path: resolve('dist'), // 输出的文件地址
        publicPath: './'
    },
    devtool: 'source-map',
    module: {
    },
    plugins: [
	    new webpack.optimize.UglifyJsPlugin({ // 压缩JS
            compress: {
                warnings: false,
                comparisons: false,
            },
            mangle: {
                safari10: true,
            },
            output: {
                comments: false,
                ascii_only: true,
            },
            sourceMap: true,
        }),
    ]
});

src新增index.js

import _ from 'lodash';

function component() {
    var element = document.createElement('div');

    // Lodash, now imported by this script
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    element.classList.add('hello');

    return element;
}

document.body.appendChild(component());

public新增index.html




    Getting Started




修改package.json

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

分别执行 npm run dev(开发) / npm run build(发布)

演示目的,我们使用开发演示修改代码。


(四)增加css处理

// 安装相关loader
$ npm install style-loader css-loader less-loader postcss-loader postcss-flexbugs-fixes -D
$ npm i autoprefixer -D
$ npm i less -D
// 将css分离出js
$ npm i extract-text-webpack-plugin -D

配置webpack.prod.js

const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const path = require('path');
const merge = require('webpack-merge');
const ExtractTextPlugin = require("extract-text-webpack-plugin"); // 分离css
const base = require('./webpack.base.js');

function resolve (dir) {
    return path.join(__dirname, dir)
}
module.exports = merge(base, {
    output: {
        filename: 'static/js/[name].[hash:7].js', //
        path: resolve('dist'), // 输出的文件地址
        publicPath: './'
    },
    devtool: 'source-map',
    module: {
        rules: [
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract({
                    fallback: {
                        loader: require.resolve('style-loader'),
                        options: {
                            hmr: false,
                        },
                    },
                    use: [
                        {
                            loader: require.resolve('css-loader'),
                            options: {
                                importLoaders: 1,
                                minimize: true,
                                sourceMap: true,
                            },
                        },
                        {
                            loader: require.resolve('postcss-loader'),
                            options: {
                                ident: 'postcss',
                                plugins: () => [
                                    require('postcss-flexbugs-fixes'),
                                    autoprefixer({
                                        browsers: [
                                            '>1%',
                                            'last 4 versions',
                                            'Firefox ESR',
                                            'not ie < 9', // React doesn't support IE8 anyway
                                        ],
                                        flexbox: 'no-2009',
                                    }),
                                ],
                            },
                        },
                    ],
                }),
            },
            {
                test: /\.less$/,
                loader: ExtractTextPlugin.extract({
                    fallback: {
                        loader: require.resolve('style-loader'),
                        options: {
                            hmr: false,
                        },
                    },
                    use: [
                        {
                            loader: require.resolve('css-loader'),
                            options: {
                                importLoaders: 1,
                                minimize: true,
                                sourceMap: true,
                            },
                        },
                        {
                            loader: require.resolve('postcss-loader'),
                            options: {
                                ident: 'postcss',
                                plugins: () => [
                                    require('postcss-flexbugs-fixes'),
                                    autoprefixer({
                                        browsers: [
                                            '>1%',
                                            'last 4 versions',
                                            'Firefox ESR',
                                            'not ie < 9', // React doesn't support IE8 anyway
                                        ],
                                        flexbox: 'no-2009',
                                    }),
                                ],
                            },
                        },
                        {
                           loader: require.resolve('less-loader'),
                           options: {
                               importLoaders: 2,
                               minimize: true,
                               sourceMap: true,
                           },
                       },
                    ],
                }),
                // Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
            },
        ]
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin({ // 压缩JS
            compress: {
                warnings: false,
                comparisons: false,
            },
            mangle: {
                safari10: true,
            },
            output: {
                comments: false,
                ascii_only: true,
            },
            sourceMap: true,
        }),
        new ExtractTextPlugin({
            filename: "static/css/[name].[hash:7].css",
            allChunks: true
        }),
    ]
});

配置webpack.dev.js

const webpack = require('webpack');
const autoprefixer = require('autoprefixer');
const path = require('path');
const merge = require('webpack-merge');
const OpenBrowserPlugin = require('open-browser-webpack-plugin');
const base = require('./webpack.base.js');

function resolve (dir) {
    return path.join(__dirname, dir)
}
// 端口
const port = 8080;
module.exports = merge(base, {
    output: {
        filename: 'static/js/[name].js', //
        path: resolve('dist'), // 输出的文件地址
        publicPath: ''
    },
    devtool: 'inline-source-map',
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    require.resolve('style-loader'),
                    {
                        loader: require.resolve('css-loader'),
                        options: {
                            importLoaders: 1,
                        },
                    },
                    {
                        loader: require.resolve('postcss-loader'),
                        options: {
                            ident: 'postcss',
                            plugins: () => [
                                require('postcss-flexbugs-fixes'),
                                autoprefixer({
                                    browsers: [
                                        '>1%',
                                        'last 4 versions',
                                        'Firefox ESR',
                                        'not ie < 9', // React doesn't support IE8 anyway
                                    ],
                                    flexbox: 'no-2009',
                                }),
                            ],
                        },
                    },
                ],
            },
            {
                test: /\.less$/,
                use: [
                    require.resolve('style-loader'),
                    {
                        loader: require.resolve('css-loader'),
                        options: {
                            importLoaders: 1,
                        },
                    },
                    {
                        loader: require.resolve('postcss-loader'),
                        options: {
                            ident: 'postcss',
                            plugins: () => [
                                require('postcss-flexbugs-fixes'),
                                autoprefixer({
                                    browsers: [
                                        '>1%',
                                        'last 4 versions',
                                        'Firefox ESR',
                                        'not ie < 9', // React doesn't support IE8 anyway
                                    ],
                                    flexbox: 'no-2009',
                                }),
                            ],
                        },
                    },
                    {
                        loader: require.resolve('less-loader'),
                        options: {
                            importLoaders: 2,
                        },
                    },
                ],
            },
        ]
    },
    devServer: {
        contentBase: './dist',
        compress: true,
        port: port,
        historyApiFallback: true,//不跳转
        inline: true//实时刷新
    },
    plugins: [
        new OpenBrowserPlugin({ url: 'http://localhost:'+port }),
    ],
});

src修改
新增index.css, test.less

/**index.css**/
body {
    background-color: aqua;
}
/**test.less**/
.hello {
    color: red;
    transition: all .5s;
}
/**index.js新增**/
import './index.css'
import './test.less'

npm run build查看打包dist文件夹

成功

(五)增加image, font, babel处理, 压缩js,react

// image和font处理
$ npm i file-loader url-loader -D
//减少打包的时候重复代码
$ npm i babel-runtime  -S
$ npm i babel-plugin-transform-runtime -D

//安装babel相关
$ npm i babel-loader -D //安装babel-loader
$ npm i babel-core -D //安装babel核心
$ npm i babel-preset-es2015 -D //支持ES2015
$ npm i babel-preset-react -D  //支持jsx
$ npm i babel-preset-stage-0 -D //支持ES7

//安装react
$ npm i react -S
$ npm i react-dom -S

项目结构
从零搭建react 脚手架_第3张图片

webpack.base.js新增module,修改entry

entry: {
	  app: './src/index.js',
	  vendor: [
	    'react',
	    'react-dom'
	  ]
},
module: {
        rules: [
            {
                test: /\.(js|jsx)?$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                include: [resolve('src'), resolve('test')]
            },
            {
                test: /\.(png|svg|jpg|gif|jpeg)$/, use:
                [{
                    loader: 'url-loader',
                    options: {
                        fallback: 'file-loader',
                        limit: 8192,
                        outputPath: 'static/images/',
                        name: '[name]_[hash:7].[ext]',
                    }
                }]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/, use:
                [{
                    loader: 'file-loader',
                    options: {
                        outputPath: 'static/fonts/',
                        name: '[name]_[hash:7].[ext]',
                    }
                }]
            }
        ]
    },

在public/index.html



新建.babel

{
  "presets": [ "es2015", "stage-0", "react"],
  "env": {
    "build": {
      "optional": ["optimisation", "minification"]
    }
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import _ from 'lodash';
import './index.less';

if (process.env.NODE_ENV !== 'production') {
  console.log('Looks like we are in development mode!!!!');
}

ReactDOM.render(, document.getElementById('root'));

App.jsx

import React, { Component } from 'react';
import Icon from './logo.svg';
import loginBg from './login-bg.jpg';
import './App.less';

class App extends Component {
  render() {
    return (
      
logo

Welcome to React

); } } export default App;

相关代码已推送到github

webpack@3 github地址

webpack@4 github地址 移动端

你可能感兴趣的:(React,Webpack)