Foreword: I believe you have seen a lot of Web music APP, what imitate netease cloud, QQ music and so on. I take you to make a web music APP
The react family barrel is used in this project, which is relatively comprehensive in technology. A lot of things are not explained from the basics
The technical requirements
- React (Version 16.2.0, Basic skills)
- React-router (4.2.2, Basics)
- React-redux (5.0.6, Basics)
- Es6 (Master the Basics)
- Webpack (3.8.1, Master the basics)
- html5
- css3
Create a project
Use create-react-app to create the skeleton of the project, and then install the routing (routing changes due to the 4.x version). Install react-router-dom 4.2.2.
The structure of the created project is as follows
How do I use my own WebPack configuration?
In the React scaffolding, the basic configuration of webpack is already configured for us, so how to add our own custom configuration file? Here we use the rewire module. First, install the Rewire module
npm install rewire proxyquire --save-dev
Copy the code
Rewire only needs to be packaged for use at project development time and installed into development dependencies
Writing configuration files
Create the scripts folder in the root directory of your project, and create a customized-build.js file as follows:
/* This module runs the react-scripts script (Create React App) to customize the webpack configuration. Create the "overrides-config.dev.js" and "overrides-config.prod.js" files in the root directory of the project. A config-overrides file should export a single function that takes a config and modifies it as necessary. module.exports = function(webpackConfig) { webpackConfig.module.rules[0].use[0].options.useEslintrc = true; }; */ var rewire = require('rewire'); var proxyquire = require('proxyquire'); switch(process.argv[2]) { // The "start" script is run during development mode case 'start': rewireModule('react-scripts/scripts/start.js', loadCustomizer('./overrides-config.dev')); break; // The "build" script is run to produce a production bundle case 'build': rewireModule('react-scripts/scripts/build.js', loadCustomizer('./overrides-config.prod')); break; // The "test" script runs all the tests with Jest case 'test': // Load customizations from the config-overrides.testing file. // That file should export a single function that takes a config and returns a config let customizer = loadCustomizer('./overrides-config.testing'); proxyquire('react-scripts/scripts/test.js', { // When test.js asks for '.. /utils/createJestConfig' it will get this instead: '.. /utils/createJestConfig': (... args) => { // Use the existing createJestConfig function to create a config, then pass // it through the customizer var createJestConfig = require('react-scripts/utils/createJestConfig'); return customizer(createJestConfig(... args)); }}); break; default: console.log('customized-build only supports "start", "build", and "test" options.'); process.exit(-1); } // Attempt to load the given module and return null if it fails. function loadCustomizer(module) { try { return require(module); } catch(e) { if(e.code ! == "MODULE_NOT_FOUND") { throw e; } } // If the module doesn't exist, return a // noop that simply returns the config it's given. return config => config; } function rewireModule(modulePath, customizer) { // Load the module with `rewire`, which allows modifying the // script's internal variables. let defaults = rewire(modulePath); // Reach into the module, grab its global 'config' variable, // and pass it through the customizer function. // The customizer should *mutate* the config object, because // react-scripts imports the config as a `const` and we can't // modify that reference. let config = defaults.__get__('config'); customizer(config); }Copy the code
The above code is used to get the corresponding module configuration during dev and build at runtime. NPM run start NPM run build webpack node_modules/react-scripts/config
webpack.config.dev.jsConfiguration files at development time
Webpack.config.prod. js produces the configuration file for packaging
function rewireModule(modulePath, customizer) {
// Load the module with `rewire`, which allows modifying the
// script's internal variables.
let defaults = rewire(modulePath);
// Reach into the module, grab its global 'config' variable,
// and pass it through the customizer function.
// The customizer should *mutate* the config object, because
// react-scripts imports the config as a `const` and we can't
// modify that reference.
let config = defaults.__get__('config');
customizer(config);
}
Copy the code
The config in the above code is the module.exports object in webpack.config.dev.js(development time) or webpack.config.prod.js(production packaging time). With this object we can add configuration to it
Configure the Stylus preprocessor language
Because Stylus is built for the Node environment, the syntax is almost indistinguishable from CSS. All the projects use stylus as the CSS preprocessor language. Github address for Stylus: github.com/stylus/styl…
First install the Stylus module
npm install stylus stylus-loader --save-dev
Copy the code
After the module is installed, create overrides-config.base.js file under the scripts folder, and create overrides-config.dev.js and overrides-config.prod.js files for development and production packaging
overrides-config.dev.js
module.exports = function(config) { // Use your ESLint /*let eslintLoader = config.module.rules[0]; eslintLoader.use[0].options.useEslintrc = true; */ // Add the stylus loader second-to-last // (last one must remain as the "file-loader") let loaderList = config.module.rules[1].oneOf; loaderList.splice(loaderList.length - 1, 0, { test: /\.styl$/, use: ["style-loader", "css-loader", "stylus-loader"] }); };Copy the code
overrides-config.prod.js
const paths = require('react-scripts/config/paths'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); // Webpack uses `publicPath` to determine where the app is being served from. // It requires a trailing slash, or the file assets will get an incorrect path. const publicPath = paths.servedPath; // Some apps do not use client-side routing with pushState. // For these, "homepage" can be set to "." to enable relative asset paths. const shouldUseRelativeAssetPaths = publicPath === './'; const cssFilename = 'static/css/[name].[contenthash:8].css'; const extractTextPluginOptions = shouldUseRelativeAssetPaths ? // Making sure that the publicPath goes back to to build folder. { publicPath: Array(cssFilename.split('/').length).join('.. / ')}, {}; module.exports = function(config) { // Use your ESLint /*let eslintLoader = config.module.rules[0]; eslintLoader.use[0].options.useEslintrc = true; */ // Add the stylus loader second-to-last // (last one must remain as the "file-loader") let loaderList = config.module.rules[1].oneOf; loaderList.splice(loaderList.length - 1, 0, { test: /\.styl$/, loader: ExtractTextPlugin.extract( Object.assign( { 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('stylus-loader') } ] } ), extractTextPluginOptions) }); };Copy the code
Modifying the Startup Script
Open the package.json file
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
Copy the code
Modify the start and build scripts as follows
"scripts": {
"start": "node scripts/customized-build start",
"build": "node scripts/customized-build build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
Copy the code
Test the WebPack configuration
Change the app.css in your project to app.styl, removing curly braces and semicolons
.App text-align: center .App-logo animation: App-logo-spin infinite 20s linear height: 80px .App-header background-color: #222 height: 150px padding: 20px color: white .App-title font-size: App-intro font size: large @keyframes app-logo-spin {from {transform: rotate(0deg); } to { transform: rotate(360deg); }}Copy the code
Run the NPM start command to run the custom configuration file
View the address **Check whether the content on http://localhost:3000** is the same as that on the first creation. If no changes are made, no problem is found
Join autoprefixer
Autoprefixer is a plug-in for CSS vendor prefixes. The React scaffolding already relies on the Autoprefixer plug-in, so NPM has installed Autoprefixer for us
For Stylus and Autoprefixer to use together here use a PostStylus plugin at github address: github.com/seaneking/p… . Install poststylus
npm install poststylus --save-dev
Copy the code
In the overrides-config.base.js configuration file, add the Poststylus plug-in configuration
const webpack = require('webpack');
const poststylus = require('poststylus');
const autoprefixer = require('autoprefixer');
Copy the code
module.exports.stylusLoaderOptionsPlugin = new webpack.LoaderOptionsPlugin({
options: {
stylus: {
use: [
poststylus([
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
})
])
]
}
}
});
Copy the code
Then import overrides-config.base. Js in overrides-config.dev. Js and overrides-config.prod.js and add the following code to the model.exports function
// Use Poststylus Plugin to handle stylus
config.plugins.push(baseConfig.stylusLoaderOptionsPlugin);
Copy the code
When not using the Poststylus plug-in, we view the style of the Logo image
After using
Prefixes have been automatically added for us
Configure the root path alias for the project
Add the following code to the overrides-config.base.js file: / / add the following code to the overrides-config.base.js file: / / add the following code to the overrides-config.base
const path = require('path');
Copy the code
function resolve (dir) { return path.join(__dirname, '.. ', dir) } module.exports.rootPath = resolve('src');Copy the code
Finally, it was added to the model.exports function of overrides-config.dev.js and overrides-config.prod.js
// Define the root path alias
let alias = config.resolve.alias;
alias["@"] = baseConfig.rootPath;
Copy the code
Overrides -config.base.js Complete configuration is as follows
const path = require('path'); const webpack = require('webpack'); const poststylus = require('poststylus'); const autoprefixer = require('autoprefixer'); function resolve (dir) { return path.join(__dirname, '.. ', dir) } module.exports.rootPath = resolve('src'); module.exports.stylusLoaderOptionsPlugin = new webpack.LoaderOptionsPlugin({ options: { stylus: { use: [ poststylus([ require('postcss-flexbugs-fixes'), autoprefixer({ browsers: [ '>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9', // React doesn't support IE8 anyway ], flexbox: 'no-2009', }) ]) ] } } });Copy the code
The last
Full project address: github.com/dxx/mango-m…
The code for this chapter is in the chapter1 branch