Skip to content

Commit

Permalink
feat: make hmr, multi-compiler etc work nicely
Browse files Browse the repository at this point in the history
Instead of spawning multiple compiler, use one compiler and attach
middlewares to it.

Also make use of the proper publicPath for HMR and DevServer.
  • Loading branch information
swashata committed Oct 8, 2018
1 parent 93605d6 commit 05668c7
Show file tree
Hide file tree
Showing 16 changed files with 371 additions and 113 deletions.
12 changes: 9 additions & 3 deletions examples/plugin/inc/Enqueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ public function __construct( $outputPath, $version, $type = 'plugin', $pluginPat
}
$this->rootPath = $filepath;
$this->rootUrl = $url;

\add_action( 'wp_head', [ $this, 'printPublicPath' ], 1 );
\add_action( 'admin_head', [ $this, 'printPublicPath' ], 1 );
}

public function printPublicPath() {
$publicPath = $this->getUrl( '' );
$jsCode = 'window.wpackIo' . ucfirst( $this->outputPath ) . '=\'' . esc_js( $publicPath ) . '\';';
echo '<script type="text/javascript">/* wpack.io publicPath */' . $jsCode . '</script>';
}

/**
Expand Down Expand Up @@ -117,9 +126,6 @@ public function enqueue( $dir, $entryPoint, $config ) {
foreach ( $enqueue['js'] as $index => $js ) {
$handle = $identifier . '_' . $index;
wp_enqueue_script( $handle, $this->getUrl( $js ), $config['js_dep'], $this->version, $config['in_footer']);
wp_localize_script( $handle, $identifier, [
'publicPath' => $this->getUrl( $dir . '/' ),
] );
$js_handles[] = $handle;
}
}
Expand Down
12 changes: 11 additions & 1 deletion examples/plugin/src/app/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import './publicPathIndex';
import '../publicPathIndex';
import './index.css';
import imgURL from './image.png';
import logger from './modules/logger';
Expand All @@ -15,10 +15,20 @@ console.log('I am too');

logger();

// Dynamic import
import('./modules/dynamic.js').then(({ default: _ }) => {
_();
});

if (module.hot) {
module.hot.accept('./modules/logger.js', () => {
/* eslint-disable global-require */
const newLogger = require('./modules/logger').default;
newLogger();
});
module.hot.accept('./modules/dynamic.js', () => {
/* eslint-disable global-require */
const newLogger = require('./modules/dynamic').default;
newLogger();
});
}
3 changes: 3 additions & 0 deletions examples/plugin/src/app/modules/dynamic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function iAmGroot() {
console.log('I am dynamic groot! With Hot reloading!');
}
5 changes: 1 addition & 4 deletions examples/plugin/src/app/modules/logger.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
export default function logger() {
console.log('Huh');
console.log('Huh');
console.log('Huh');
console.log('Hot Reloaded');
console.log('Load me 🤟');
}
3 changes: 3 additions & 0 deletions examples/plugin/src/foo/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function bar() {
console.log('I am bar, with hot reloaded!!');
}
12 changes: 12 additions & 0 deletions examples/plugin/src/foo/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import '../publicPathIndex';
import bar from './bar';

bar();

/* eslint-disable global-require */
if (module.hot) {
module.hot.accept('./bar.js', () => {
const newBar = require('./bar').default;
newBar();
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ if (process.env.NODE_ENV === 'production') {
// We set dynamic publicPath only for production
// In development, it is always handled by the internals
// As in the webpack config.
__webpack_public_path__ = window.wpackIoAppMain.publicPath;
__webpack_public_path__ = window.wpackIoDist;
}
4 changes: 3 additions & 1 deletion examples/plugin/wpackio-plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
// Create an admin page
add_action( 'wp_enqueue_scripts', 'wpackio_plugin_enqueue' );
require_once dirname( __FILE__ ) . '/inc/Enqueue.php';
$enqueue = new \WPackio\Enqueue( 'dist', '1.0.0', 'plugin', __FILE__ );

function wpackio_plugin_enqueue() {
$enqueue = new \WPackio\Enqueue( 'dist', '1.0.0', 'plugin', __FILE__ );
global $enqueue;
$enqueue->enqueue( 'app', 'main', [] );
$enqueue->enqueue( 'foo', 'main', [] );
}
9 changes: 8 additions & 1 deletion examples/plugin/wpackio.project.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,18 @@ module.exports = {
main: ['./src/app/index.js'],
mobile: ['./src/app/mobile.js'],
},
filename: '[name].js',
// Extra webpack config to be passed directly
webpackConfig: undefined,
},
// If has more length, then multi-compiler
{
name: 'foo',
entry: {
main: ['./src/foo/foo.js'],
},
// Extra webpack config to be passed directly
webpackConfig: undefined,
},
],
// Output path relative to the context directory
// We need relative path here, else, we can not map to publicPath
Expand Down
4 changes: 2 additions & 2 deletions examples/plugin/wpackio.server.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ module.exports = {
},
// Whether to show the "BrowserSync Connected"
notify: false,
// Open the local URL, set to false to disable
open: 'external',
// Open the dev server URL, set false to disable
open: true,
// BrowserSync ghostMode, set to false to completely disable
ghostMode: {
clicks: true,
Expand Down
1 change: 1 addition & 0 deletions packages/scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"mini-css-extract-plugin": "^0.4.3",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss-loader": "^3.0.0",
"react-dev-utils": "^6.0.4",
"sass-loader": "^7.1.0",
"signale": "^1.3.0",
"slugify": "^1.3.1",
Expand Down
33 changes: 33 additions & 0 deletions packages/scripts/src/config/CreateWebpackConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,33 @@ export class CreateWebpackConfig {
return this.getSingleCompilerConfig(this.projectConfig.files[0]);
}

public getWebpackConfig(): webpack.Configuration | webpack.Configuration[] {
// Now it can be a single compiler, or multicompiler
// In any case, figure it out, create the compiler options
// and return the stuff.

// If the configuration is for multiple compiler mode
// Then return an array of config.
if (this.projectConfig.files.length > 1) {
// Return an array of configuration
const config: webpack.Configuration[] = [];
this.projectConfig.files.forEach((file: FileConfig) => {
config.push(this.getSingleWebpackConfig(file));
});

return config;
}

// Otherwise, just return a single compiler mode config
return this.getSingleWebpackConfig(this.projectConfig.files[0]);
}

public getPublicPath(): string {
const { slug, outputPath, type } = this.projectConfig;

return `/wp-content/${type}s/${slug}/${outputPath}/`;
}

/**
* Get Webpack Configuration for single compiler mode.
*
Expand Down Expand Up @@ -138,4 +165,10 @@ export class CreateWebpackConfig {

return { config, hmrPublicPath };
}

private getSingleWebpackConfig(file: FileConfig): webpack.Configuration {
const { config } = this.getSingleCompilerConfig(file);

return config;
}
}
35 changes: 20 additions & 15 deletions packages/scripts/src/config/WebpackConfigHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ interface CommonWebpackConfig {
* A helper class to get different configuration of webpack.
*/
export class WebpackConfigHelper {
// This is where all the filename will be prefixed, so we create a directory
public readonly outputInnerDir: string;
// Actual outputPath as provided by user
public readonly outputPath: string;
private file: FileConfig;
private isDev: boolean;
Expand All @@ -57,7 +59,7 @@ export class WebpackConfigHelper {
*/
private env: 'development' | 'production';

private hmrPublicPath: string;
private publicPath: string;

/**
* Create an instance of GetEntryAndOutput class.
Expand All @@ -84,10 +86,8 @@ export class WebpackConfigHelper {
// and file
const { name } = this.file;
this.outputInnerDir = slugify(name, { lower: true });
this.outputPath = path.join(this.cwd, outputPath, this.outputInnerDir);
this.hmrPublicPath = `/wp-content/${contentDir}/${slug}/${outputPath}/${
this.outputInnerDir
}/`;
this.outputPath = path.join(this.cwd, outputPath);
this.publicPath = `/wp-content/${contentDir}/${slug}/${outputPath}/`;
}

/**
Expand All @@ -97,7 +97,7 @@ export class WebpackConfigHelper {
public getHmrPath(): string {
const { name } = this.file;

return `${this.hmrPublicPath}__wpackio_${name}`;
return `${this.publicPath}__wpackio`;
}

/**
Expand Down Expand Up @@ -142,14 +142,17 @@ export class WebpackConfigHelper {
// 2. overlay and overlayStypes - To enable overlay on errors, we don't need warnings here
// 3. path - The output path, We need to make sure both server and client has the same value.
// 4. name - Because it could be multicompiler
const webpackHotClient: string = `webpack-hot-middleware/client?path=__wpackio_${name}&name=${name}&dynamicPublicPath=true&overlay=true&reload=true&overlayStyles=${encodeURIComponent(
const webpackHotClient: string = `webpack-hot-middleware/client?path=__wpackio&name=${name}&dynamicPublicPath=true&overlay=true&reload=true&overlayStyles=${encodeURIComponent(
JSON.stringify(overlayStyles)
)}`;
// Now add to each of the entries
// We don't know if user want to specifically disable for some, but let's
// not think ahead of ourselves
Object.keys(normalizedEntry).forEach((key: string) => {
normalizedEntry[key].push(webpackHotClient);
normalizedEntry[key] = [
webpackHotClient,
...normalizedEntry[key],
];
});
}

Expand All @@ -164,7 +167,7 @@ export class WebpackConfigHelper {
// Destucture stuff we need from config
const { host, port } = this.config;
// and file
const { filename } = this.file;
// const { filename } = this.file;
// Assuming it is production
const output: webpack.Output = {
// Here we create a directory inside the user provided outputPath
Expand All @@ -175,7 +178,7 @@ export class WebpackConfigHelper {
// We do not use path.resolve, because we expect outputPath to be
// relative. @todo: create a test here
path: this.outputPath,
filename,
filename: `${this.outputInnerDir}/[name].js`,
// leave blank because we would handle with free variable
// __webpack_public_path__ in runtime.
publicPath: '',
Expand All @@ -191,7 +194,7 @@ export class WebpackConfigHelper {
// Maybe we can get an option from user for SSL?
// But this is needed for hot middleware
output.publicPath = `//${host || 'localhost'}:${port}${
this.hmrPublicPath
this.publicPath
}`;
}

Expand All @@ -213,13 +216,15 @@ export class WebpackConfigHelper {
new cleanWebpackPlugin([this.outputPath], { root: this.cwd }),
// Initiate mini css extract
new miniCssExtractPlugin({
filename: '[name].css',
filename: `${this.outputInnerDir}/[name].css`,
}),
// Create Manifest for PHP Consumption
new WebpackAssetsManifest({
writeToDisk: true,
output: `${this.outputPath}/manifest.json`,
publicPath: `${this.outputInnerDir}/`, // We dont put ${this.config.outputPath}/ here because, PHP will pick it up anyway.
output: `${this.outputPath}/${
this.outputInnerDir
}/manifest.json`,
publicPath: ``, // We dont put ${this.config.outputPath}/ here because, PHP will pick it up anyway.
entrypoints: true,
entrypointsKey: 'wpackioEp',
}),
Expand Down Expand Up @@ -349,7 +354,7 @@ ${bannerConfig.credit ? creditNote : ''}
loader: 'file-loader',
options: {
name: 'asset-[hash].[ext]',
outputPath: 'assets/',
outputPath: `${this.outputInnerDir}/assets/`,
},
},
],
Expand Down
2 changes: 1 addition & 1 deletion packages/scripts/src/scripts/Build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class Build {
false
);
const compiler = webpack(
config.getConfig() as webpack.Configuration
config.getWebpackConfig() as webpack.Configuration
);
compiler.run((err, stats) => {
if (err || stats.hasErrors()) {
Expand Down
Loading

0 comments on commit 05668c7

Please sign in to comment.