Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): add monorepo and Yarn PnP support #1418

Merged
merged 7 commits into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wicked-baboons-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'preact-cli': minor
---

Added monorepo and Yarn PnP support by correctly loading dependencies, removing faulty install checks, and adding undeclared dependencies
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,36 @@ jobs:
LIGHTHOUSE_CHROMIUM_PATH: 'which google-chrome-stable'
run: npm run test

pnpTest:
name: PnPTest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1

- uses: actions/setup-node@v1
with:
node-version: 12.x

- name: Run PnP test
run: |
git clone https://github.com/preactjs-templates/default.git default
cd default/template
touch yarn.lock
echo $(cat package.json | jq '.name = "pnp-test"') > package.json
yarn set version 2
yarn config set pnpFallbackMode none
yarn config set compressionLevel 0
yarn link -A -p ../..
yarn build

ci-success:
name: ci
if: ${{ success() }}
needs:
- test
- pnpTest
runs-on: ubuntu-latest
steps:
- name: CI succeeded
Expand Down
10 changes: 0 additions & 10 deletions packages/cli/lib/commands/build.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const rimraf = require('rimraf');
const { resolve } = require('path');
const { promisify } = require('util');
const { isDir, error } = require('../util');
const runWebpack = require('../lib/webpack/run-webpack');
const { validateArgs } = require('./validate-args');

Expand Down Expand Up @@ -94,15 +93,6 @@ async function command(src, argv) {
argv.production = toBool(argv.production);

let cwd = resolve(argv.cwd);
let modules = resolve(cwd, 'node_modules');

if (!isDir(modules)) {
return error(
'No `node_modules` found! Please run `npm install` before continuing.',
1
);
}

Comment on lines -97 to -105
Copy link
Contributor Author

@merceyz merceyz Jan 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When run in a monorepo where the hoisting is good this folder wont exist so checking if the project is installed like this is not correct

if (argv.clean === void 0) {
let dest = resolve(cwd, argv.dest);
await promisify(rimraf)(dest);
Expand Down
9 changes: 4 additions & 5 deletions packages/cli/lib/lib/webpack/prerender.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ module.exports = function (env, params) {
return '';
}
const { cwd } = env;

const preact = require(require.resolve(`${cwd}/node_modules/preact`));
const renderToString = require(require.resolve(
`${cwd}/node_modules/preact-render-to-string`
));
const preact = require(require.resolve('preact', { paths: [cwd] }));
const renderToString = require(require.resolve('preact-render-to-string', {
paths: [cwd],
}));
return renderToString(preact.h(app, { ...params, url }));
} catch (err) {
let stack = stackTrace.parse(err).filter(s => s.getFileName() === entry)[0];
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/lib/lib/webpack/proxy-loader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
var utils = require('loader-utils');
var requireRelative = require('require-relative');

function proxyLoader(source, map) {
var options = utils.getOptions(this);
Expand All @@ -17,7 +16,9 @@ function proxyLoader(source, map) {

var loader;
try {
loader = requireRelative(proxyOptions.loader, proxyOptions.cwd);
loader = require(require.resolve(proxyOptions.loader, {
paths: [proxyOptions.cwd],
}));
} catch (e) {
loader = require(proxyOptions.loader);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/lib/lib/webpack/render-html-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ module.exports = async function (config) {
: resolve(dest, url.substring(1), 'index.html');
return Object.assign(values, {
filename,
template: `!!ejs-loader?esModule=false!${template}`,
template: `!!${require.resolve('ejs-loader')}?esModule=false!${template}`,
minify: isProd && {
collapseWhitespace: true,
removeScriptTypeAttributes: true,
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/lib/lib/webpack/transform-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ class WebpackConfigHelpers {
} catch (e) {}

let templatePath = isPath
? `!!ejs-loader?esModule=false!${resolve(this._cwd, template)}`
? `!!${require.resolve('ejs-loader')}?esModule=false!${resolve(
this._cwd,
template
)}`
: template;
let { plugin: htmlWebpackPlugin } = this.getPluginsByName(
config,
Expand Down
9 changes: 5 additions & 4 deletions packages/cli/lib/lib/webpack/utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
const resolveFrom = require('resolve-from');

function isInstalledVersionPreactXOrAbove(cwd) {
try {
return (
parseInt(require(resolveFrom(cwd, 'preact/package.json')).version, 10) >=
10
parseInt(
require(require.resolve('preact/package.json', { paths: [cwd] }))
.version,
10
) >= 10
);
} catch (e) {}
return false;
Expand Down
93 changes: 58 additions & 35 deletions packages/cli/lib/lib/webpack/webpack-base-config.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
const webpack = require('webpack');
const path = require('path');
const { resolve } = require('path');
const { resolve, dirname } = require('path');
const { readFileSync, existsSync } = require('fs');
const { isInstalledVersionPreactXOrAbove } = require('./utils');
const autoprefixer = require('autoprefixer');
const browserslist = require('browserslist');
const requireRelative = require('require-relative');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const ReplacePlugin = require('webpack-plugin-replace');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const createBabelConfig = require('../babel-config');
const loadPostcssConfig = require('postcss-load-config');
const PnpWebpackPlugin = require(`pnp-webpack-plugin`);

function readJson(file) {
try {
Expand Down Expand Up @@ -96,9 +96,16 @@ module.exports = function (env) {

let compat = 'preact-compat';
try {
requireRelative.resolve('preact/compat', cwd);
compat = 'preact/compat';
} catch (e) {}
compat = dirname(
require.resolve('preact/compat/package.json', { paths: [cwd] })
);
} catch (e) {
try {
compat = dirname(
require.resolve('preact-compat/package.json', { paths: [cwd] })
);
} catch (e) {}
}

let tsconfig = resolveTsconfig(cwd, isProd);

Expand All @@ -110,6 +117,14 @@ module.exports = function (env) {
postcssPlugins = [autoprefixer({ overrideBrowserslist: browsers })];
}

function tryResolveOptionalLoader(name) {
try {
return require.resolve(name);
} catch (e) {
return name;
}
}

return {
context: src,

Expand All @@ -130,21 +145,23 @@ module.exports = function (env) {
'.css',
'.wasm',
],
alias: Object.assign(
{
style: source('style'),
'preact-cli-entrypoint': source('index'),
url: 'native-url',
// preact-compat aliases for supporting React dependencies:
react: compat,
'react-dom': compat,
'react-addons-css-transition-group': 'preact-css-transition-group',
'preact-cli/async-component': IS_SOURCE_PREACT_X_OR_ABOVE
? require.resolve('@preact/async-loader/async')
: require.resolve('@preact/async-loader/async-legacy'),
},
compat !== 'preact-compat' ? { 'preact-compat': compat } : {}
),
alias: {
style: source('style'),
'preact-cli-entrypoint': source('index'),
url: dirname(require.resolve('native-url/package.json')),
// preact-compat aliases for supporting React dependencies:
react: compat,
'react-dom': compat,
'preact-compat': compat,
'react-addons-css-transition-group': 'preact-css-transition-group',
'preact-cli/async-component': IS_SOURCE_PREACT_X_OR_ABOVE
? require.resolve('@preact/async-loader/async')
: require.resolve('@preact/async-loader/async-legacy'),
},
plugins: [
// TODO: Remove when upgrading to webpack 5
PnpWebpackPlugin,
],
},

resolveLoader: {
Expand All @@ -162,7 +179,7 @@ module.exports = function (env) {
test: /\.m?[jt]sx?$/,
resolve: { mainFields: ['module', 'jsnext:main', 'browser', 'main'] },
type: 'javascript/auto',
loader: 'babel-loader',
loader: require.resolve('babel-loader'),
options: Object.assign(
{ babelrc: false },
createBabelConfig(env, { browsers }),
Expand All @@ -175,10 +192,10 @@ module.exports = function (env) {
test: /\.less$/,
use: [
{
loader: 'proxy-loader',
loader: require.resolve('./proxy-loader'),
options: {
cwd,
loader: 'less-loader',
loader: tryResolveOptionalLoader('less-loader'),
options: {
sourceMap: true,
lessOptions: {
Expand All @@ -195,10 +212,10 @@ module.exports = function (env) {
test: /\.s[ac]ss$/,
use: [
{
loader: 'proxy-loader',
loader: require.resolve('./proxy-loader'),
options: {
cwd,
loader: 'sass-loader',
loader: tryResolveOptionalLoader('sass-loader'),
options: getSassConfiguration(...nodeModules),
},
},
Expand All @@ -210,10 +227,10 @@ module.exports = function (env) {
test: /\.styl$/,
use: [
{
loader: 'proxy-loader',
loader: require.resolve('./proxy-loader'),
options: {
cwd,
loader: 'stylus-loader',
loader: tryResolveOptionalLoader('stylus-loader'),
options: {
sourceMap: true,
paths: nodeModules,
Expand All @@ -227,9 +244,11 @@ module.exports = function (env) {
test: /\.(p?css|less|s[ac]ss|styl)$/,
include: [source('components'), source('routes')],
use: [
isWatch ? 'style-loader' : MiniCssExtractPlugin.loader,
isWatch
? require.resolve('style-loader')
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
loader: require.resolve('css-loader'),
options: {
modules: {
localIdentName: '[local]__[hash:base64:5]',
Expand All @@ -239,7 +258,7 @@ module.exports = function (env) {
},
},
{
loader: 'postcss-loader',
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
sourceMap: true,
Expand All @@ -253,15 +272,17 @@ module.exports = function (env) {
test: /\.(p?css|less|s[ac]ss|styl)$/,
exclude: [source('components'), source('routes')],
use: [
isWatch ? 'style-loader' : MiniCssExtractPlugin.loader,
isWatch
? require.resolve('style-loader')
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
loader: require.resolve('css-loader'),
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
sourceMap: true,
Expand All @@ -277,11 +298,13 @@ module.exports = function (env) {
},
{
test: /\.(xml|html|txt|md)$/,
loader: 'raw-loader',
loader: require.resolve('raw-loader'),
},
{
test: /\.(svg|woff2?|ttf|eot|jpe?g|png|webp|gif|mp4|mov|ogg|webm)(\?.*)?$/i,
loader: isProd ? 'file-loader' : 'url-loader',
loader: isProd
? require.resolve('file-loader')
: require.resolve('url-loader'),
},
],
},
Expand Down
23 changes: 19 additions & 4 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"devDependencies": {
"html-looks-like": "^1.0.2",
"jest": "^26.0.1",
"less-loader": "^7.0.1",
"ncp": "^2.0.0",
"node-sass": "^4.12.0",
"p-retry": "^4.1.0",
Expand All @@ -57,11 +58,26 @@
"puppeteer": "^5.3.1",
"sass-loader": "^10.0.4",
"shelljs": "^0.8.3",
"sirv": "^1.0.0-next.2"
"sirv": "^1.0.0-next.2",
"stylus-loader": "^3.0.2"
},
"peerDependencies": {
"less-loader": "^7.0.1",
"preact": "*",
"preact-render-to-string": "*"
"preact-render-to-string": "*",
"sass-loader": "^10.0.0 || ^9.0.2",
"stylus-loader": "^3.0.2"
},
"peerDependenciesMeta": {
"less-loader": {
"optional": true
},
"sass-loader": {
"optional": true
},
"stylus-loader": {
"optional": true
}
},
"dependencies": {
"@babel/core": "^7.9.0",
Expand Down Expand Up @@ -107,15 +123,14 @@
"native-url": "0.3.4",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"ora": "^4.0.3",
"pnp-webpack-plugin": "^1.6.4",
"postcss-load-config": "^2.1.0",
"postcss-loader": "^3.0.0",
"progress-bar-webpack-plugin": "^2.1.0",
"promise-polyfill": "^8.1.0",
"prompts": "^2.2.1",
"raw-loader": "^4.0.0",
"react-refresh": "0.8.3",
"require-relative": "^0.8.7",
"resolve-from": "^5.0.0",
"rimraf": "^3.0.2",
"sade": "^1.4.1",
"size-plugin": "^2.0.1",
Expand Down
Loading