從零搭建一個屬於本身的react框架

前言

事例一:咱們在使用react的時候,會用create-react-app命令下載一個react的模板,而後開始在裏面實現各類功能。css

事例二:前幾個月的時候,我偶然發現飛冰官網,瀏覽後以爲不錯,並在其上面下載了幾個模板。html

那咱們可能好奇兩件事情:前端

  • 這個模板是如何從一個空目錄下搭建起來的呢
  • 這個模板搭建起來以後,是如何定義命令行下載的呢

本文將按照我本身的一個想法、以react模板樣式爲基準,就這兩個話題展開敘述。vue

1、開始搭建

1.1 目錄

├─ build                     // webpack配置目錄
│  ├─ webpack.base.js        // webpack共有配置
│  ├─ webpack.dev.js         // webpack開發環境配置
│  └─ webpack.prod.js        // webpack生產環境配置
├─ public                    // 模板存放目錄
│  ├─ favicon.ico            // 網站圖標
│  └─ index.html             // 模板html文件
├─ src                       // 項目
│  ├─ common                 // 共有方法
│  ├─ compoents              // 自封裝組件
│  ├─ layouts                // 佈局組件 
│  ├─ pages                  // 頁面
│  ├─ index.js               // 項目入口
│  ├─ App.css                // css樣式
│  ├─ logo.svg               // 首頁logo
│  └─ App.jsx                
├─ .babelrc                  // babel配置文件
├─ .browerslistrc            // 配置瀏覽器的兼容性範圍
├─ .gitignore                // 忽略上傳文件
├─ package.json              
├─ README.md                 // 工程搭建文檔說明
複製代碼

1.2 初始化

首先,咱們要建立一個空目錄,而後初始化項目 npm init -y 執行完命令,咱們會在目錄中看見一個package.json文件。 node

1.3 配置package.json

咱們知道,不管是項目的啓動仍是打包,它的命令是從package.json文件中本身定義的。在建立的模板中,有start命令-啓動react,有build-將react項目打包,目前咱們只配置這兩個命令以及開發環境下的打包、生產環境下啓動服務命令。react

找到pakage.json文件中的scripts,像這樣配置webpack

"scripts": {
    "start": "webpack-dev-server --env.development --config ./build/webpack.base.js",      // 開發環境啓動服務,
    "dev":"webpack --env.development --config ./build/webpack.base.js",                    // 開發環境打包代碼
    "build": "webpack --env.production --config ./build/webpack.base.js",                  // 生產環境打包代碼
    "build:server": "webpack-dev-server --env.production --config ./build/webpack.base.js" // 生產環境啓動服務
  },
複製代碼

這樣,咱們完成了基礎的配置,可是,咱們會思考:不一樣的平臺(MacWindows)是否是會出現設置環境變量不同的問題?基於這個問題,咱們找到了cross-env插件,那咱們應該如何將上面配置好的scripts改進呢?git

"scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server --config ./build/webpack.base.js",
    "dev":"cross-env NODE_ENV=development webpack --config ./build/webpack.base.js",
    "build": "cross-env NODE_ENV=production webpack --config ./build/webpack.base.js",
    "build:server": "cross-env NODE_ENV=production webpack-dev-server --config ./build/webpack.base.js"
  },
複製代碼

配置好之後,下一步,咱們就開始配置webpackgithub

1.4 配置webpack

1.4.1 webpack.base.js

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const dev = require('./webpack.dev');
const prod = require('./webpack.prod');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const isDev = process.env.NODE_ENV === 'development';

const base = {
    entry: path.resolve(__dirname, '../src/index.js'),      // 入口
    module: {                                               
        rules: [{                                           // 對.js、.jsx的處理
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: 'babel-loader'
        }, {                                                // 對.css的處理
            test: /\.css$/,
            use: [
                !isDev && MiniCssExtractPlugin.loader,      // 生產環境下樣式抽離
                isDev && 'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 1                    // 引入的文件調用後面的loader處理
                    }
                },
                {                                           // 智能添加樣式前綴
                    loader: "postcss-loader",
                    options:{
                        plugins:[require('autoprefixer')]
                    }
                },
            ].filter(Boolean)
        }, {
            test: /\.scss$/,                               // css預處理器scss的處理
            use: [
                !isDev && MiniCssExtractPlugin.loader,     // 生產環境下抽離樣式
                isDev && 'style-loader',
                "css-loader",
                "sass-loader"
            ].filter(Boolean)
        }, {
            test: /\.less$/,                               // css預處理器less的處理
            use: "less-loader",
        }, {
            test: /\.stylus$/,                             // css預處理器stylus的處理                           
            use: "stylus-loader",
        }, {
            test: /\.(jpe?g|png|svg|gif)$/,                // 對圖片的處理
            loader: "file-loader",
            options: {
                name: "image/[contentHash].[ext]"
            },
        }, {
            test: /\.(woff|ttf|eot|otf|ico)$/,             // 對字體圖標的處理
            loader: "file-loader",
            options: {
                name: "image/[name].[ext]"
            },
        }]
    },
    output: {                                              // 出口
        filename: 'scripts/[name].bundle.js',
        path: path.resolve(__dirname, '../dist')
    },
    resolve: {                                             // 引入js、jsx文件時,無需添加後綴
        extensions: ['.js', '.jsx'],
    },
    plugins: [
        !isDev && new MiniCssExtractPlugin({               // css樣式抽離
            filename: 'css/[name].[contentHash].css'
        }),
        new HtmlWebpackPlugin({                            // 配置入口html
            filename: 'index.html',
            template: path.resolve(__dirname, '../public/index.html'),
            hash: true,
            inject: true,
            favicon: path.resolve(__dirname, '../public/favicon.ico'), 
            minify: !isDev && {
                removeAttributeQuotes: true,               // 去掉屬性雙引號
                collapseWhitespace: true,                  // 將html文件摺疊成一行
            }
        }),
        new webpack.HotModuleReplacementPlugin(),
    ].filter(Boolean),
    devServer: {                                           // 配置服務
        hot:true,                                          // 熱更新
        port: 3000,                                        // 端口號
        compress: true,                                    // 提高頁面返回速度
        open: true,                                        // 啓動服務後自動啓動瀏覽器
        contentBase: path.resolve(__dirname, '../dist'),   // webpack啓動服務會在dist目錄下
    }
}

module.exports = () => {                                    // 根據環境合併webpack
    if (isDev) {
        return merge(base, dev);
    } else {
        return merge(base, prod);
    }
}
複製代碼

1.4.2 webpack.dev.js

module.exports = {
    mode: 'development',
}
複製代碼

1.4.3 webpack.prod.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
    mode: 'production',
    plugins: [
        new CleanWebpackPlugin(),                         // 打包前清空dist目錄
        new UglifyJsPlugin({                              // 打包後自動去除debugger、console等        
            uglifyOptions: {
                compress: {
                    drop_debugger: true,               
                    drop_console: true,
                    pure_funcs: ['console.log', 'debugger']
                }
            },
            parallel: true
        }),
    ],
}
複製代碼

1.5 查看效果

如今,咱們已經實現了一個屬於本身的模板,可是咱們發現打包的速度可能會有一些慢。那究竟如何讓本身的代碼打包更快呢?

咱們能夠優化咱們的webpack配置~web

關於webpack的配置優化,後續,會單獨寫一個文章~

2、自定義命令下載本身的模板

咱們都用過vue-clicreate-react-app等命令下載一個初始的vuereact模板,這裏我要寫一個屬於本身的cli下載屬於本身的模板(手動狗頭)~

個人clinpm上的名字叫react-demo-cli,下載模板的命令是create-react-cli download

因此,在使用的時候,先輸入命令 npm install react-demo-cli -g 而後 create-react-cli download 就能夠啦~

效果是這樣嬸滴

最後

這一篇文章的核心簡單來講有兩條

  • 配置webpack
  • 搭建一個本身的cli 只要這兩件事情搞定了,問題就不難了

這裏,主要說了從零搭建本身的react框架的思路、方法,效果和create-react-app等比起來,仍是差不少。因此,我會不斷優化本身和本身的代碼~

還有:

  • 對於cli,只有使用方法,後續會有專門的文章講解如何搭建一個本身的cli。這裏還要感謝圈圈的圈的cli代碼講解~
  • 對於webpack,我使用了webpack-dev-server來啓動服務,這樣啓動的服務在控制檯打印了不少東西,因此後續會改成本身編寫腳本的方式~

下面,是clireact-templategithub地址

上面的文章若有不對之處,還請你們指點出來~咱們共同進步~

而後,分享一下個人公衆號「web前端日記」的二維碼,歡迎前來你們關注~

相關文章
相關標籤/搜索