Coder Social home page Coder Social logo

basic-project's Introduction

Basic-Project

从头搭建react环境全过程。

计划: 一个完整的流程。流程走完,再细分模块深入。

  1. 基础目录划分
  2. webpack基本配置
  3. 搭建基本功能
  4. 性能
  5. 校验

基础目录划分

首先进行基本的目录创建。

mkdir Basic-Project
cd Basic-Project
npm init -y
git init

然后在目录下创建三个文件夹publicsrcwebpack

├── public
├── src
└── webpack

public

用于放公共资源。

目前该目录下有:

  • favicon.ico 从react项目中拷来的图标
  • index.html 页面html文件,啥都还没引入,甚至连同目录下的icon也没引用。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>

src

核心代码目录

目前该目录下有:

  • index.js

webpack

webpack配置

目前该目下有三个文件:

  • webpack.base.conf.js
  • webpack.dev.conf.js
  • webpack.prod.conf.js
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   └── index.jsx
└── webpack
    ├── webpack.base.conf.js
    ├── webpack.dev.conf.js
    └── webpack.prod.conf.js

根目录

除了生成的package.json外,目前需要在根目录下添加一些其他文件,先添加README.md.gitignore.editorconfig。现在根目录下的文件有:

  • package.json 目前还是初始化的配置
  • README.md 掌握markdown语法,谁都能写
  • .gitignore 现在只需添加node_modules这一行配置
  • .editorconfig 统一开发人员编辑器配置
├── README.md
├── .gitignore
├── .editorconfig
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   └── index.jsx
└── webpack
    ├── webpack.base.conf.js
    ├── webpack.dev.conf.js
    └── webpack.prod.conf.js

webpack基本配置

npm install webpack webpack-cli -D
npm install webpack-merge -D

区分开发环境和生产环境(目前暂不考虑测试环境)。 前面已新建三个了文件webpack.base.conf.jswebpack.dev.conf.jswebpack.prod.conf.js。文件的命名格式参考了vue-cli。 在base中写开发环境和生产环境都使用的公共配置,然后开发和生产的配置文件通过webpack merge合并了base配置后,再分别针对配置。

base

目前先对基本的js进行解析,安装babel

npm install babel-loader @babel/core @babel/preset-env -D

TODO: 了解@babe/core @babel/preset-env的作用l

然后参照官网的配置写一下

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: "babel-loader",
        options: {
          presets: ["@babel/preset-env"],
        },
      },
    },
  ],
},

为了统一管理babel配置,我们将配置写到一份单独的文件。

根目录下新建一个名为.babelrc的文件,然后将我们刚才写的配置抽离到这个文件中

{
    "presets": ["@babel/preset-env"]
}
├── README.md
├── .gitignore
├── .editorconfig
├── .babelrc
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   └── index.jsx
└── webpack
    ├── webpack.base.conf.js
    ├── webpack.dev.conf.js
    └── webpack.prod.conf.js

然后webpack.base.conf.js中的配置变为

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: "babel-loader",
    },
  ],
},

目前的雏形

const webpack = require("webpack");
const path = require("path");

module.exports = {
    context: path.resolve(__dirname, "../src"),
    entry: {
        index: "./index.js",
    },
    output: {
        path: path.resolve(__dirname, '../dist'),
        filename: "[name].js",
    },
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: "babel-loader",
            },
        ],
    },
    resolve: {
        extensions: [".js"],
    },
    plugins: [],
};

dev

安装webpack dev server

npm install webpack-dev-server -D

合并base。目前webpack.dev.conf.js中的配置为

const webpack = require("webpack");
const webpackMerge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");

const devWebpackConfig = webpackMerge(baseWebpackConfig, {
  mode: 'development',
  devServer: {
    port: '3000'
  }
});

module.exports = devWebpackConfig;

在package.json中添加命令

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
+ "dev": "webpack-dev-server --config webpack/webpack.dev.conf.js",
},

prod

合并base

目前为

const webpack = require("webpack");
const webpackMerge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");

const prodWebpackConfig = webpackMerge(baseWebpackConfig, {
  mode: 'production'
});

module.exports = prodWebpackConfig;

最后配置package.json 添加dev build命令

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "dev": "webpack-dev-server --config webpack/webpack.dev.conf.js",
+ "build": "webpack --config webpack/webpack.prod.conf.js"
},

搭建基本环境

react

npm install react react-dom -S
npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev

修改.babelrc

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}

修改webpack

{
+   test: /\.(m?js|jsx)$/,
    exclude: /(node_modules|bower_components)/,
    use: "babel-loader",
},
+ extensions: [".js", ".jsx"],
entry: {
+   index: "./index.jsx",
},

然后把项目里的index.js改为index.jsx,并添加内容。

import React from 'react';
import ReactDOM from 'react-dom';

function App(){
  return <div>Hello Webpack</div>
}
ReactDOM.render(<App />, document.querySelector('#root'));

html

为了能够在浏览器中看到我们代码更改的效果,我们需要安装html-webpack-plugin

npm install html-webpack-plugin -D

配置webpack.base.conf.js的plugins选项

new HtmlWebpackPlugin({
  template: path.resolve(__dirname, "../public", "index.html"),
  filename: "index.html",
}),

运行命令npm run dev,打开localhost:3000,可以在页面上看到Hello Webpack

source-map

但是目前通过控制台无法很好的调试我们的代码,在source中打开index.jsx,发现代码调试太难。需要配置devtool。分别对webpack.dev.conf.jswebpack.prod.conf.js进行配置

devtool: 'cheap-module-eval-source-map',
devtool: 'source-map'

重启项目。

样式

npm i css-loader style-loader -D

修改webpack.base.config.js

{
    test: /\.css$/,
    use: ["style-loader", "css-loader"],
},

预处理器,本次选用less。如果需要sass或stylus,请自行替换。

npm install less less-loader -D

修改webpack.base.conf.js

{
  test: /\.less$/,
    use: ["style-loader", "css-loader", "less-loader"],
},

然后给项目添加文件,新建App.jsx和`styles/App.less``

├── README.md
├── .gitignore
├── .editorconfig
├── .babelrc
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── App.jsx
│   ├── index.jsx
│   └── styles
│       └── App.less
└── webpack
    ├── webpack.base.conf.js
    ├── webpack.dev.conf.js
    └── webpack.prod.conf.js

主要更改集中于App.less

@color: orange;

#app {
  color: @color;
}

然后在App.jsx中引入样式文件

import React from 'react';
+ import './styles/App.less';

function App(){
  return <div id="app">Hello Webpack</div>
}

export default App;

TODO: postcss css模块化

图片、字体文件

npm install file-loader url-loader -D

url-loader封装了file-loader但不依赖file-loader。但是在文件大小(单位byte)低于指定的限制时,可以返回一个DataURL。配置webpack.base.conf.js

{
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: "url-loader",
    options: {
        limit: 10000,
    },
},
{
    test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
    loader: "url-loader",
    options: {
        limit: 10000,
    },
},
{
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: "url-loader",
    options: {
        limit: 10000,
    },
},

添加images目录,再修改App.jsx

import React from "react";
import "./styles/App.less";
+ import img from "./images/a.jpg";

function App() {
    return (
        <div id="app">
            <h1>Hello Webpack</h1>
+           <img src={img} alt="" />
        </div>
    );
}

export default App;

TODO: 自定义file name hash

清空dist

每次打包前清空dist目录

npm install clean-webpack-plugin -D

修改webpack.base.conf.js

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

plugins: [
    ...,
+    new CleanWebpackPlugin()
],

TODO: copywebpackplugin

TODO: ProvidePlugin 配置全局变量

热更新

现在虽然我们配置了devserver可以动态更新,但每次都是刷新浏览器,我们想要局部更新。

首先配置 devServerhottrue

并且在 plugins 中增加 new webpack.HotModuleReplacementPlugin()

修改webpack.dev.conf.js

const devWebpackConfig = webpackMerge(baseWebpackConfig, {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  devServer: {
    port: '3000',
    hot: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
});

此时还是整个页面刷新。

在入口文件index.jsx中添加

if(module && module.hot) {
    module.hot.accept()
}

环境判断

有时我们需要在一个公共文件中判断当前的环境是生成环境还是开发环境。安装cross-env

npm install cross-env -S

修改package.json的scripts

+ "dev": "cross-env NODE_ENV=devlopment webpack-dev-server --config webpack/webpack.dev.conf.js",
+ "build": "cross-env NODE_ENV=production webpack --config webpack/webpack.prod.conf.js"

cross-env能够帮我们设置环境变量的时候解决不同系统之间的兼容性问题。

性能

分析

速度

安装speed-measure-webpack-plugin,该插件能分析loader和plugin的耗时。

npm install speed-measure-webpack-plugin -D

修改webpack.prod.conf.js

const webpackMerge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();

const _webpackConfig = webpackMerge(baseWebpackConfig, {
  mode: 'production',
  devtool: 'source-map'
});
const prodWebpackConfig = smp.wrap(_webpackConfig);

module.exports = process.env.NODE_ENV === 'analysis' ? prodWebpackConfig : _webpackConfig;

修改package.json的scripts

"analysis": "cross-env NODE_ENV=analysis webpack --config webpack/webpack.prod.conf.js"

执行npm run analysis,可以看到分析结果

 SMP  ⏱  
General output time took 1.69 secs

 SMP  ⏱  Plugins
HtmlWebpackPlugin took 0.091 secs
CleanWebpackPlugin took 0.013 secs
MiniCssExtractPlugin took 0.002 secs

 SMP  ⏱  Loaders
babel-loader took 0.643 secs
  module count = 3
modules with no loaders took 0.508 secs
  module count = 9
url-loader took 0.495 secs
  module count = 1
mini-css-extract-plugin, and 
css-loader, and 
less-loader took 0.259 secs
  module count = 1
css-loader, and 
less-loader took 0.237 secs
  module count = 1
html-webpack-plugin took 0.015 secs
  module count = 1

大小

安装webpack-bundle-analyzer,该插件能够分析打包后各类包的引用大小,我们需要针对体积过大的文件进行优化处理。

npm install webpack-bundle-analyzer -D

修改webpack.prod.conf.js

const webpackMerge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
+ const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");

const smp = new SpeedMeasurePlugin();

const _webpackConfig = webpackMerge(baseWebpackConfig, {
    mode: "production",
    devtool: "source-map",
});
const prodWebpackConfig = smp.wrap(_webpackConfig);

+ if (process.env.NODE_ENV === "analysis") {
+    _webpackConfig.plugins.push(new BundleAnalyzerPlugin());
+ }

module.exports =
    process.env.NODE_ENV === "analysis" ? prodWebpackConfig : _webpackConfig;

执行npm run analysis即可。

压缩代码

压缩js

terser

抽离css并压缩

npm install mini-css-extract-plugin -D

webpack4使用mini-css-extract-plugin

修改webpack.base.conf.js

修改webpack.base.conf.js

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const env = process.env.NODE_ENV;

{
    test: /\.css$/,
    use: [
        env === "production"
            ? MiniCssExtractPlugin.loader
            : "style-loader",
        "css-loader",
    ],
},
{
    test: /\.less$/,
    use: [
        env === "production"
            ? MiniCssExtractPlugin.loader
            : "style-loader",
        "css-loader",
        "less-loader",
    ],
},

plugins: [
    ...,
    new MiniCssExtractPlugin({}),
],

todo: 与extract-text-webpack-plugin比较

optimize-css-assets-webpack-plugin

按需加载

import

添加一个文件buttonClickFunc.js

const sayHello = () => {
    console.log("hello world");
};
const sayGoodbye = () => {
    console.log("goodbye");
};

export { sayHello, sayGoodbye };

修改app.jsx

import React from "react";
import "./styles/App.less";
import img from "./images/a.jpg";

function App() {
  const onClick = () => {
    import('./buttonClickFunc').then(module => {
      const {sayHello, sayGoodbye} = module;
      sayHello();
      sayGoodbye();
    })
  }
    return (
        <div id="app">
            <h1>Hello Webpack</h1>
            <button onClick={onClick}>click me to load file</button>
            <img src={img} alt="" />
        </div>
    );
}

export default App;

当我们点击button的时候,看控制台,发现会多请求一个0.js。

TODO: chunkfilename webpackchunkname魔法注释

范围

resolve

tree-shaking

scope hoist

code spliting

按需引入

webpack bundle analyzer

speed-measure-webpack-plugin

splitchunk

dllplugin

loader开启缓存

合理使用sourcemap

loader exclude include

mini-css-extract-plugin optimize-css-assets-webpack-plugin

moment ignoreplugin

lodash 按需加载 配置babel 注意同名情况报错解决

校验

typescript

lint

eslint

eslint eslint-loader

stylelint

commitlint

husky

prettier

editorconfig

其他

多页

跨域

总结

hash

hash

chunkhash

contenthash

loader

css-loader style-loader less-loader postcss-loader file-loader url-loader

image-webpack-loader

thread-loader

lugin

  • clean-webpack-plugin
  • webpack.DefinePlugin
  • html-webpack-plugin
  • terser-webpack-plugin
  • mini-css-extract-plugin
  • case-sensitive-paths-webpack-plugin
  • progress-plugin friendly-errors-webpack-plugin node-notifier

webpack-bundle-analyzer

speed-measure-webpack-plugin

optimize-css-assets-webpack-plugin

purgecss-webpack-plugin

dllplugin

原理

webpack打包原理

hmr

手写loader plugin

basic-project's People

Contributors

grayfrost avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.